just a demo, need a 'real' grammar spec....
opasgn := '+=' meps | '-=' | '*-' | '/=' | '%=' | '**='
| '&=' | '|=' | '^=' | '<<=' | '>>='
| '&&=' | '||=' . " opasgn << '+='; << '||=' "
identifier := '\a[\w_]*' regex. " identifier << 'a_1' "
fname := identifier | '..' | '|' | '^' | '&'
| '<=>' | '===' | '==' | '=~'
| '>=' | '>>' | '>' | '<<' | '<=' | '<'
| '+@' | '+' | '-@' | '-' | '/' | '%' | '**' | '*'
| '~' | '[]=' | '[]'. " fname << '[]'; << 'abc' "
global :='\$' regex ,< identifier
| '\$\-.' regex
| '\$.' regex. " global << '$abc'; << '$-a'; <<'$a' "
varname := global
| ('@' regex ,< identifier)
| identifier. " varname << '@abc'; << 'abc' "
symbol := (':' regex ,< fname)
| (':' regex ,< varname). " symbol << ':@abc'; << ':===' "
operation := identifier deepCopy ,< '[!\?]' regex. " operation << 'abc!'; << 'abc?' "
string := '"[^"]*"' regex.
string2 :=
[ : input : peek |
| p1 p2 char matchChar matchAny |
p1 := input position .
matchChar := [input match: '.' regex action: [:r | char := r]].
matchAny := [ input matchUpToAll: char asString action: [ : r | r ]].
input match: '%[Qqx]' regex , matchChar , matchAny , [char]
action: [ : r |
p2 := input position .
input position: p1 .
input next: p2 - p1]]. " string2 meps << '%QzABCz' ; << '%x%foo%' "
heredoc :=
[ : input : peek |
| p1 p2 ident matchIdent matchBody |
p1 := input position .
matchIdent := [ input match: identifier meps | string
action: [ : r | ident := r ]].
matchBody := [ input matchUpToAll: ident action: [ : r | r ]].
input
match: '<<' meps , matchIdent , matchBody , [ident]
action: [ : oc |
p2 := input position.
input position: p1 .
input next: p2 - p1]]. " heredoc meps << '<<zz abc def abc zz' "
regexp := [ : input : peek | | rule1 rule2 p1 p2 char matchChar matchAny| p1 := input position . rule1 := '\/[^\/]*\/[io]' regex . matchChar := [input match: '.' regex action:[:r | char := r]]. matchAny := [ input matchUpToAll: char asString action: [ : r | r ]]. rule2 := [input match: '%r' regex , matchChar , matchAny , [matchChar] action: [:r|r]]. input match: rule1 | rule2 action: [ : r | p2 := input position . input position: p1 . input next: p2 - p1]]. " regexp meps << '/abc/i'; << '/abc/o' "