grammar cardinal::Grammar is PCT::Grammar;

token TOP { <comp_stmt> [ $ || <panic: Syntax error> ] {*} }

token comp_stmt { {*} #= open <stmts> {*} #= close }

rule stmts { <.term>?[ <stmt> <.term>+]* {*} }

token term { \n | ';' }

token basic_stmt { | <alias> {*} #= alias | <return_stmt> {*} #= return_stmt | <expr> {*} #= expr | <begin> {*} #= begin | <end> {*} #= end }

token return_stmt { 'return' <.ws> <call_args> {*} }

rule alias { 'alias' <fname> <fname> {*} }

token stmt { <basic_stmt> <.ws> <stmt_mod>* {*} }

token stmt_mod { $<sym>=[if|while|unless|until] <.ws> <expr> {*} }

rule expr { <basic_expr> [$<op>=['and'|'or'] <expr>]? {*} }

token basic_expr { | <assignment> {*} #= assignment | <arg> {*} #= arg | <not_expr> {*} #= not_expr }

rule not_expr { 'not' <expr> {*} }

rule begin { 'BEGIN' '{' <comp_stmt> '}' {*} }

rule end { 'END' '{' <comp_stmt> '}' {*} }

rule assignment { <mlhs=lhs> '=' <mrhs=arg> #XXX need to figure out multiple assignment {*} }

rule mlhs { | <lhs> {*} #= lhs | '(' <mlhs> ')' {*} #= mlhs }

token lhs { | <variable> {*} #= variable | <indexed_variable> {*} #= indexed_variable | <member_variable> {*} #= member_variable }

rule indexed_variable { <primary> '[' <args>? ']' {*} }

token member_variable { <primary> '.' <identifier> {*} }

token command { | <call> {*} #= call | <super_call> {*} #= super_call }

rule call { [ <primary=variable> $<dot>=['.'|'::'] ]? <operation> <call_args> <do_block>? {*} }

rule do_block { 'do' <do_args> <.term>? <comp_stmt> 'end' {*} }

rule super_call { 'super' <call_args> {*} }

rule not_command { '!' <command> {*} }

token operation { <.identifier> ('!'|'?')? }

token call_args { | '()' {*} | <args> {*} | '(' <.ws> <args> <.ws> ')' {*} }

rule do_args { '|' [ <identifier> [',' <identifier>]*]?'|' {*} }

token variable { | <varname> {*} #= varname | 'nil' #= nil | 'self' #= self }

token varname { <!reserved_word> [ <global> {*} #= global | <instance_variable> {*} #= instance_variable | <local_variable> {*} #= local_variable ] }

token mrhs { <args> {*} }

rule args { <arg> [',' <arg>]* {*} }

rule 'arg' is optable { ... }

proto 'infix:=' is precedence('1') is pasttype('copy') is lvalue(1) { ... }

token basic_primary { | <literal> {*} #= literal | <command> {*} #= command | <not_command> {*} #= command | <variable> {*} #= variable | <array> {*} #= array | <ahash> {*} #= ahash | <functiondef> {*} #= functiondef | <if_stmt> {*} #= if_stmt | <while_stmt> {*} #= while_stmt | <unless_stmt> {*} #= unless_stmt | <module> {*} #= module | <begin_end> {*} #= begin_end | <pcomp_stmt> {*} #= pcomp_stmt | <scope_identifier> {*} #= scope_identifier }

rule primary { <basic_primary> <post_primary_expr>* {*} }

rule post_primary_expr { | <scope_identifier> {*} #= scope_identifier | '[' <args>? ']' {*} #= args }

rule scope_identifier { '::' <identifier> {*} }

rule pcomp_stmt { '(' <comp_stmt> ')' {*} }

rule if_stmt { 'if' <expr> <.then> <comp_stmt> ['elsif' <expr> <.then> <comp_stmt>]* <else>? 'end' {*} }

token then { ':' | 'then' | <term> ['then']? }

rule while_stmt { $<sym>=['while'|'until'] <expr> <.do> <comp_stmt> 'end' {*} }

rule do { ':' | 'do' | <term> ['do']? }

rule unless_stmt { 'unless' <expr> <.then> <comp_stmt> <else>? 'end' {*} }

rule else { 'else' <comp_stmt> {*} }

rule ensure { 'ensure' <comp_stmt> {*} }

rule rescue { # XXX check <args> ['rescue' <args> <.then> <comp_stmt>]+ {*} }

rule module { 'module' <module_identifier> <comp_stmt> 'end' {*} }

rule functiondef { 'def' <fname> <argdecl> <comp_stmt> 'end' {*} }

rule bodystmt { <comp_stmt> <rescue>? <else>? <ensure>? }

rule argdecl { ['(' [ <identifier> [',' <identifier>]* [',' <slurpy_param>]? [',' <block_param>]? | <slurpy_param> [',' <block_param>]? | <block_param>? ] ')']? {*} }

token slurpy_param { '*' <identifier> {*} }

token block_param { '&' <identifier> {*} }

rule begin_end { 'begin' <comp_stmt> ['rescue' <args>? <.do> <comp_stmt>]+ ['else' <comp_stmt>]? ['ensure' <comp_stmt>]? 'end' {*} }

token fname { <.identifier> }

rule array { '[' [ <args> [',']? ]? ']' {*} }

rule ahash { '{' [ [ <args> | <assocs> ] [',']? ]? '}' {*} }

rule assocs { <assoc> [',' <assoc>]* {*} }

rule assoc { <arg> '=>' <arg> {*} }

token identifier { <!reserved_word> <ident> {*} }

token module_identifier { <before <[A..Z]>> <ident> {*} }

token global { '$' <ident> {*} }

token instance_variable { '@' <ident> {*} }

token class_variable { '@@' <ident> {*} }

token local_variable { <before <[a..z_]>> <ident> {*} }

token constant_variable { <before <[A..Z]>> <ident> {*} }

token literal { | <float> {*} #= float | <integer> {*} #= integer | <string> {*} #= string }

token float { \d* '.' \d+ {*} }

token integer { \d+ {*} }

token string { [ \' <string_literal: "'"> \' | \" <string_literal: '"'> \" ] {*} }

token reserved_word { [alias|and|BEGIN|begin|break|case |class|def|defined|do|else|elsif |END|end|ensure|false|for|if |in|module|next|nil|not|or |redo|rescue|retry|return|self|super |then|true|undef|unless|until|when |while|yield|__FILE__|__LINE__]>> }

token ws { | '\\' \n ## a backslash at end of line | <after [','|'='|'+']> \n ## a newline after a comma or operator is ignored | \h* ['#' \N* \n*]? }

proto 'infix:=' is precedence('1') is pasttype('copy') is lvalue(1) { ... }

proto 'prefix:defined?' is looser('infix:=') { ... }

proto 'infix:+=' is equiv('infix:=') is pirop('add') { ... }

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

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

proto 'infix:*=' is equiv('infix:=') is pirop('mul') { ... }

proto 'infix:%=' is equiv('infix:=') is pirop('mul') { ... }

proto 'infix:|=' is equiv('infix:=') { ... }

proto 'infix:&=' is equiv('infix:=') { ... }

proto 'infix:~=' is equiv('infix:=') { ... }

proto infix:«>>=» is equiv('infix:=') is pirop('rsh') { ... }

proto infix:«<<=» is equiv('infix:=') is pirop('lsh') { ... }

proto 'infix:&&=' is equiv('infix:=') is pirop('and') { ... }

proto 'infix:**=' is equiv('infix:=') is pirop('pow') { ... }

proto 'ternary:? :' is tighter('infix:=') is pirop('if') { ... }

proto 'infix:..' is tighter('ternary:? :') is pirop('n_add') { ... }

proto 'infix:...' is equiv('infix:...') { ... }

proto 'infix:||' is tighter('infix:..') is past('unless') { ... }

proto 'infix:&&' is tighter('infix:||') is past('if') { ... }

proto 'infix:==' is tighter('infix:&&') { ... } 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:==') { ... }

proto 'infix:«<=»' is tighter('infix:===') { ... } proto infix:«=>» is tighter('infix:===') { ... } proto infix:«>» is tighter('infix:===') { ... } proto infix:«<» is tighter('infix:===') { ... }

proto 'infix:|' is tighter('infix:«<=»') { ... } proto 'infix:^' is equiv('infix:|') { ... }

proto 'infix:&' is tighter('infix:|') { ... }

proto infix:«<<» is tighter('infix:&') { ... } proto infix:«>>» is equiv(infix:«<<») { ... }

proto 'infix:+' is tighter(infix:«<<») is pirop('n_add') { ... }

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

proto 'infix:*' is tighter('infix:+') is pirop('n_mul') { ... }

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

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

#proto 'prefix:+' is tighter('infix:*') { ... } #proto 'prefix:-' is equiv('prefix:+') { ... } #proto 'prefix:!' is equiv('prefix:+') { ... } #proto 'prefix:~' is equiv('prefix:+') { ... }

proto 'term:' is tighter('infix:*') is parsed(&primary) { ... }


parrot