5 This is the grammar for cardinal written as a sequence of Perl 6 rules.
7 Originally taken (partly) from:
8 http://www.math.hokudai.ac.jp/~gotoken/ruby/man/yacc.html
10 and parse.y from the ruby source
14 grammar cardinal::Grammar is PCT::Grammar;
18 [ $ || <panic: Syntax error> ]
29 <.term>?[ <stmt> [<.term>+ | <.before <end_block>> | $ | <panic: unterminated statement>] ]* {*}
32 token term { \n | ';' }
33 token end_block { <.ws> [ 'end' | '}' ] }
36 | <alias> {*} #= alias
37 | <classdef> {*} #= classdef
38 | <functiondef> {*} #= functiondef
39 | <if_stmt> {*} #= if_stmt
40 | <while_stmt> {*} #= while_stmt
41 | <for_stmt> {*} #= for_stmt
42 | <unless_stmt> {*} #= unless_stmt
43 | <module> {*} #= module
44 | <begin_end> {*} #= begin_end
45 | <indexed_assignment> {*} #= indexed_assignment
46 | <member_assignment> {*} #= member_assignment
47 | <assignment> {*} #= assignment
48 | <return_stmt> {*} #= return_stmt
50 | <begin> {*} #= begin
55 'return' <.ws> <call_args> {*}
59 'alias' <fname> <fname>
64 <basic_stmt> <.ws> <stmt_mod>*
69 $<sym>=[if|while|unless|until] <.ws> <expr>
74 [$<not>=['!'|'not']]? <arg> [$<op>=['and'|'or'] <expr>]?
79 'BEGIN' '{' <comp_stmt> '}'
84 'END' '{' <comp_stmt> '}'
88 token indexed_assignment {
89 <basic_primary> '[' <key=arg> ']' <.ws> '=' <.ws> <rhs=arg>
93 token member_assignment {
94 <basic_primary> '.' <key=identifier> <.ws> '=' <.ws> <rhs=arg>
99 <mlhs=lhs> '=' <mrhs=arg> #XXX need to figure out multiple assignment
105 | '(' <mlhs> ')' {*} #= mlhs
109 | <basic_primary> {*} #= basic_primary
117 token member_variable {
118 <primary> '.' <identifier>
124 <operation> <call_args>? <do_block>?
129 | 'do' <do_args>? <.term>? <.before <stmt>><comp_stmt> 'end' {*}
130 | '{' <do_args>? <.term>? <.before <stmt>><comp_stmt> '}' {*}
139 <.identifier> ('!'|'?')?
142 #XXX UGLY! Refactor into <args> maybe?
144 | '()' [<.ws> <do_block>]? {*}
145 | [ <.after \s|\)> | <.before \s> ] <args> [<.ws> <do_block>]? {*}
146 | '(' <.ws> <args> <.ws> ')' [<.ws> <do_block>]? {*}
150 '|' <block_signature> '|'
153 rule sig_identifier {
154 #XXX Should this be basic_primary or expr or what?
155 <identifier>[ '=' <default=basic_primary>]? {*}
158 rule block_signature {
160 | <sig_identifier> [',' <sig_identifier>]* [',' <slurpy_param>]? [',' <block_param>]?
161 | <slurpy_param> [',' <block_param>]?
167 | <varname> {*} #= varname
174 [ <global> {*} #= global
175 | <class_variable> {*} #= class_variable
176 | <instance_variable> {*} #= instance_variable
177 | <local_variable> {*} #= local_variable
178 | <constant_variable> {*} #= constant_variable
183 <!reserved_word> <local_variable> <.before \s|'('> <.before <call_args>> {*}
195 rule 'arg' is optable { ... }
197 proto 'infix:=' is precedence('1') is pasttype('copy') is lvalue(1) { ... }
201 token basic_primary {
202 | <literal> {*} #= literal
203 | <funcall> {*} #= funcall
204 | <variable> {*} #= variable
205 | <ahash> {*} #= ahash
206 | <regex> {*} #= regex
207 | <do_block> {*} #= do_block
208 | <quote_string> {*} #= quote_string
209 | <warray> {*} #= warray
210 | <array> {*} #= array
211 | <pcomp_stmt> {*} #= pcomp_stmt
212 | <scope_identifier> {*} #= scope_identifier
213 | <control_command> {*} #= control_command
217 <basic_primary> <post_primary_expr>*
221 token post_primary_expr {
222 | <indexed> {*} #= indexed
223 | <call_args> {*} #= call_args
224 | <methodcall> {*} #= methodcall
225 | <scope_identifier> {*} #= scope_identifier
226 | '[' <args>? ']' {*} #= args
229 token scope_identifier {
243 ['elsif' <expr> <.then>
247 |<panic: syntax error in if statement>]
251 token then { ':' | 'then' | <term> ['then']? }
254 $<sym>=['while'|'until'] <expr> <.do>
261 'for' <variable> 'in' <expr> <.do>
267 token do { ':' | 'do' | <term> ['do']? }
270 'unless' <expr> <.then> <comp_stmt>
277 'else' <.ws> <comp_stmt>
282 'ensure' <.ws> <comp_stmt>
288 ['rescue' <args> <.then> <comp_stmt>]+
292 token control_command {
294 | 'break' {*} #= break
299 'module' <module_identifier>
306 'class' <module_identifier> {*} #= open
312 'def' <fname> <argdecl>
344 ['rescue' <args>? <.do> <comp_stmt>]+
345 ['else' <comp_stmt>]?
346 ['ensure' <comp_stmt>]?
352 <.identifier> <[=!?]>?
356 ['%q'|'%Q'] <.before <[<[_|({]>> <quote_expression: :qq>
361 '%w' <.before <[<[({]>> <quote_expression: :w :q>
366 '[' [ <args> [',']? ]? ']'
371 '{' [ <assocs> [',']? ]? '}'
376 <assoc> [',' <assoc>]*
386 <!reserved_word> <ident> {*}
389 token module_identifier {
390 <.before <[A..Z]>> <ident>
399 token instance_variable {
404 token class_variable {
409 token local_variable {
410 <before <[a..z_]>> <ident>
414 token constant_variable {
415 <before <[A..Z]>> <ident>
420 | <float> {*} #= float
421 | <integer> {*} #= integer
422 | <string> {*} #= string
436 [ \' <string_literal: "'"> \' | \" <string_literal: '"'> \" ]
441 <.before '/'> [<quote_expression: :regex> $<modifiers>=[<alpha>]*
442 |<panic: problem parsing regex>]
446 token reserved_word {
447 [alias|and|BEGIN|begin|break|case
448 |class|def|defined|do|else|elsif
449 |END|end|ensure|false|for|if
450 |in|module|next|nil|not|or
451 |redo|rescue|retry|return|self|super
452 |then|true|undef|unless|until|when
453 |while|yield|__FILE__|__LINE__]>>
457 | '\\' \n ## a backslash at end of line
458 | <after [','|'='|'+']> \n ## a newline after a comma or operator is ignored
463 proto 'infix:=' is precedence('1') is pasttype('copy') is lvalue(1) { ... }
465 proto 'prefix:defined?' is looser('infix:=') { ... }
467 proto 'infix:+=' is equiv('infix:=')
470 proto 'infix:-=' is equiv('infix:=')
471 is pirop('sub') { ... }
473 proto 'infix:/=' is equiv('infix:=')
474 is pirop('div') { ... }
476 proto 'infix:*=' is equiv('infix:=')
477 is pirop('mul') { ... }
479 proto 'infix:%=' is equiv('infix:=')
480 is pirop('mul') { ... }
482 proto 'infix:|=' is equiv('infix:=') { ... }
484 proto 'infix:&=' is equiv('infix:=') { ... }
486 proto 'infix:~=' is equiv('infix:=') { ... }
488 proto infix:«>>=» is equiv('infix:=')
489 is pirop('rsh') { ... }
491 proto infix:«<<=» is equiv('infix:=')
492 is pirop('lsh') { ... }
494 proto 'infix:&&=' is equiv('infix:=')
495 is pirop('and') { ... }
497 proto 'infix:**=' is equiv('infix:=')
498 is pirop('pow') { ... }
500 proto 'ternary:? :' is tighter('infix:=')
501 is pirop('if') { ... }
503 proto 'infix:..' is tighter('ternary:? :')
504 is parsed(&primary) { ... }
505 #is pirop('n_add') { ... }
507 proto 'infix:...' is equiv('infix:...') { ... }
509 proto 'infix:||' is tighter('infix:..')
510 is past('unless') { ... }
512 proto 'infix:&&' is tighter('infix:||')
513 is past('if') { ... }
516 proto 'infix:==' is tighter('infix:&&') { ... }
517 proto 'infix:!=' is equiv('infix:==') { ... }
518 proto 'infix:=~' is equiv('infix:==') { ... }
519 proto 'infix:!~' is equiv('infix:==') { ... }
520 proto 'infix:===' is equiv('infix:==') { ... }
521 proto infix:«<=>» is equiv('infix:==') { ... }
524 proto infix:«>» is tighter('infix:===') { ... }
525 proto infix:«<» is tighter('infix:===') { ... }
526 proto infix:«<=» is tighter('infix:===') { ... }
527 proto infix:«>=» is tighter('infix:===') { ... }
529 proto 'infix:|' is tighter('infix:<=') { ... }
530 proto 'infix:^' is equiv('infix:|') { ... }
532 proto 'infix:&' is tighter('infix:|') { ... }
534 proto infix:«<<» is tighter('infix:&') { ... }
535 proto infix:«>>» is equiv(infix:«<<») { ... }
537 proto 'infix:+' is tighter(infix:«<<») { ... }
539 proto 'infix:-' is equiv('infix:+') { ... }
540 #is pirop('n_sub') { ... }
542 proto 'infix:*' is tighter('infix:+') { ... }
543 #is pirop('n_mul') { ... }
545 proto 'infix:/' is equiv('infix:*') { ... }
546 #is pirop('n_div') { ... }
548 proto 'infix:%' is equiv('infix:*')
549 is pirop('n_mod') { ... }
551 #proto 'prefix:+' is tighter('infix:*') { ... }
552 #proto 'prefix:-' is equiv('prefix:+') { ... }
553 #proto 'prefix:!' is equiv('prefix:+') { ... }
554 #proto 'prefix:~' is equiv('prefix:+') { ... }
556 proto 'term:' is tighter('infix:*')
557 is parsed(&primary) { ... }