Copyright © Cay S. Horstmann 2011 Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.

Parsing 5

Reminder: Context-Free Grammar

Repetition

Operator Precedence

Operator Associativity

LL(1) Grammars

Avoiding Left Recursion

Left Factoring

Ambiguity

Reading Grammars

Lab

???

Step 1

  1. Look at the Annotated XML Specification Section 3.1. Can you have spaces before an element name in a start tag?
    < name>

    Which grammar rule did you use to answer this question?

  2. Before the /> in an empty-element tag?
    <name />

    Which grammar rule did you use to answer this question?

  3. Around the = in an attribute?
    <name attr = "value">

    Which grammar rule did you use to answer this question?

Step 2

  1. Design a grammar for the function headers of Crazy Section 2.4 (without the body). Write the grammar in EBNF form.
  2. Write a Scala program that parses a Crazy function header, using a Parser[Any]. What is your program? What output do you get for
    function area(a: integer; b: real; c: integer): real; 

    For

    function area(a: integer; b, c: real): real; 
  3. Improve your program to yield a Function object, defined below:
    case class Variable(name : String, `type` : String) 
      // type is a reserved word in Scala. 
      // We use `...` to parse it as an identifier
    case class Function(name : String, params : List[Variable], returnType : String)

    Do only the easy part, where all params have the form repsep(param, ";") where param is ident ~ ":" ~ ident. That is, don't yet handle parameter groups of the form a, b : type. (You'll do that later in the term project.)

    What is your program? What output do you get for

    function area(a: integer; b: real; c: integer): real; 

    Hint: Transform parameters into Variable objects

    def param: Parser[Variable] = ident ~ (":" ~> ident) ^^ 
      { case i ~ t => Variable(i, t) }

    Hint: You always want to use ~> and <~ to throw away tokens. But you often need parentheses. Note that ~, ~>, and <- are left associative and <- has lower precedence than ~, ~>.For example,

    ident ~ (":" ~> ident)

    or

    (ident <~ ":") ~ ident

Step 3 (Optional)

  1. Write a Scala parser for the grammar
    expr ::= "if" "(" number ")" expr ("else" expr)? | number

    What is your program? What do you get when you parse

    if (1) if (2) 3 else 4
  2. Ok, it's too tedious to figure out whether the else associates with the first or second if. Enhance your program to yield a IfExpr. Use the following outline:
    class Expr
    case class IfExpr(cond : Number, pos : Expr, neg : Expr) extends Expr
    case class Number(value : String) extends Expr
    
    class SimpleLanguageParser extends JavaTokenParsers {    
      def expr: Parser[Expr] = ... 
      def number: Parser[Number] = wholeNumber ^^ { Number(_) }
    }

    Transform cond ~ expr ~ None into IfExpr(cond, expr, null).

    Now what do you get for

    if (1) if (2) 3 else 4
  3. Does the Scala parser resolve the if/if/else ambiguity in the same way as C++, or the other way?