grammar ABC::Grammar;

## an example 'bc' grammar

token TOP { <program> }

## recognize terms
token term { 
    | $<float>:=[ \d+\.\d* | \.\d+ ]
    | $<integer>:=[\d+] 
    | $<ident>:=[<[a..z]><[_a..z0..9]>*] 
        [ $<array>:=[ \[ <expression> \] ]
        | $<call>:=[ \( <expression> \) ]
        ]?
}

## Standalone strings do not handle backslashed caracters.
## However, when a string is passed to 'print', special chars are handled.
token string { <-["]>* }

## 'print' is a GNU extension to bc
## backslashed characters are ignored for now
rule print {
    print [ <string> | <expression> ] [ , [ <string> | <expression> ] ]*
}

rule compound_statement { \{ <statement_list> \} }
rule if_statement { if \( <expression> \) <statement> [ else <statement> ]? }
rule while_statement { while \( <expression> \) <statement> }
rule for_statement {
    for \( <expression> ; <expression> ; <expression> \) <statement>
}
rule statement {
    | <if_statement>
    | <while_statement>
    | <for_statement>
    | <compound_statement>
    | \" <string> \"
    | break
    | continue
    | halt
    | return [ \( <expression> \) ]?
    | <expression>
}
rule statement_list { <statement>? [ ; <statement>? ]* }
rule program { ^ <statement_list> [ $ | <die: parse error> ] }

rule pseudo_statement { limits | quit | warranty }



## create operator precedence parser
rule 'expression'   is optable { ... }


## terms
proto 'term:'       is precedence('=')
    is parsed(&term)
    { ... }

proto 'circumfix:( )'  is equiv('term:') 
    is pirop('set')
    { ... }

## autoincrement
proto 'postfix:++'  is looser('term:')     is lvalue(1) { ... }
proto 'postfix:--'  is equiv('postfix:++') is lvalue(1) { ... }
proto 'prefix:++'   is equiv('postfix:++') is lvalue(1) { ... }
proto 'prefix:--'   is equiv('postfix:++') is lvalue(1) { ... }

## negation
proto 'prefix:-'    is looser('postfix:++')
    is pirop('neg')
    { ... }

## exponentiation
proto 'infix:^'     is looser('prefix:-')  { ... }

## multiplicative
proto 'infix:*'     is looser('infix:^')
    is pirop('mul')
    { ... }

proto 'infix:/'     is equiv('infix:*')
    is pirop('div')
    { ... }

proto 'infix:%'     is equiv('infix:*')
    is pirop('mod')
    { ... }

## additive
proto 'infix:+'     is looser('infix:*')
    is pirop('add')
    { ... }

proto 'infix:-'     is equiv('infix:+')
    is pirop('sub')
    { ... }

## assignment
proto 'infix:='     is looser('infix:+')
    is assoc('right')
    is past('assign')
    is lvalue(1)
    { ... }

## relational
proto 'infix:=='    is looser('infix:=')  is assoc('non')  { ... }
proto 'infix:!='    is equiv('infix:==') { ... }
proto 'infix:<'     is equiv('infix:==') { ... }
proto 'infix:<='    is equiv('infix:==') { ... }
proto 'infix:>'     is equiv('infix:==') { ... }
proto 'infix:>='    is equiv('infix:==') { ... }

## boolean
proto 'prefix:!'    is looser('infix:==') is pirop('not') is returns('.Integer') { ... }
proto 'infix:&&'    is looser('prefix:!') is assoc('left') { ... }
proto 'infix:||'    is looser('infix:&&') is assoc('left') { ... }

## vim: expandtab sw=4
