You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
3.1 KiB
150 lines
3.1 KiB
// a simple recognizer, produces no useful value |
|
|
|
ometa L { |
|
number = digit+, |
|
addExpr = addExpr '+' mulExpr |
|
| addExpr '-' mulExpr |
|
| mulExpr, |
|
mulExpr = mulExpr '*' primExpr |
|
| mulExpr '/' primExpr |
|
| primExpr, |
|
primExpr = '(' expr ')' |
|
| number, |
|
expr = addExpr |
|
} |
|
|
|
L.matchAll('6*(4+3)', 'expr') |
|
|
|
|
|
|
|
|
|
|
|
|
|
// a recognizer that also interprets |
|
|
|
ometa Calc { |
|
digit = ^digit:d -> d.digitValue(), |
|
number = number:n digit:d -> (n * 10 + d) |
|
| digit, |
|
addExpr = addExpr:x '+' mulExpr:y -> (x + y) |
|
| addExpr:x '-' mulExpr:y -> (x - y) |
|
| mulExpr, |
|
mulExpr = mulExpr:x '*' primExpr:y -> (x * y) |
|
| mulExpr:x '/' primExpr:y -> (x / y) |
|
| primExpr, |
|
primExpr = '(' expr:x ')' -> x |
|
| number, |
|
expr = addExpr |
|
} |
|
|
|
Calc.matchAll('6**(4+3)', 'expr') |
|
|
|
|
|
|
|
|
|
|
|
|
|
// parser and simple interpreter combo |
|
|
|
ometa CalcParser { |
|
digit = ^digit:d -> d.digitValue(), |
|
number = number:n digit:d -> (n * 10 + d) |
|
| digit, |
|
addExpr = addExpr:x '+' mulExpr:y -> ['add', x, y] |
|
| addExpr:x '-' mulExpr:y -> ['sub', x, y] |
|
| mulExpr, |
|
mulExpr = mulExpr:x '*' primExpr:y -> ['mul', x, y] |
|
| mulExpr:x '/' primExpr:y -> ['div', x, y] |
|
| primExpr, |
|
primExpr = '(' expr:x ')' -> x |
|
| number:n -> ['num', n], |
|
expr = addExpr |
|
} |
|
|
|
tree = CalcParser.matchAll('6*(4+3)', 'expr') |
|
|
|
ometa CalcInterpreter { |
|
interp = ['num' anything:x] -> x |
|
| ['add' interp:x interp:y] -> (x + y) |
|
| ['sub' interp:x interp:y] -> (x - y) |
|
| ['mul' interp:x interp:y] -> (x * y) |
|
| ['div' interp:x interp:y] -> (x / y) |
|
} |
|
|
|
CalcInterpreter.match(tree, 'interp') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// we can write a "compiler" instead |
|
|
|
ometa CalcCompiler { |
|
comp = ['num' anything:x] -> x.toString() |
|
| ['add' comp:x comp:y] -> ('(' + x + '+' + y + ')') |
|
| ['sub' comp:x comp:y] -> ('(' + x + '-' + y + ')') |
|
| ['mul' comp:x comp:y] -> ('(' + x + '*' + y + ')') |
|
| ['div' comp:x comp:y] -> ('(' + x + '/' + y + ')') |
|
} |
|
|
|
code = CalcCompiler.match(tree, 'comp') |
|
eval(code) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// spice things up with ML-like syntax |
|
|
|
ometa CalcCompiler { |
|
comp ['num' anything:x] -> x.toString(), |
|
comp ['add' comp:x comp:y] -> ('(' + x + '+' + y + ')'), |
|
comp ['sub' comp:x comp:y] -> ('(' + x + '-' + y + ')'), |
|
comp ['mul' comp:x comp:y] -> ('(' + x + '*' + y + ')'), |
|
comp ['div' comp:x comp:y] -> ('(' + x + '/' + y + ')') |
|
} |
|
|
|
code = CalcCompiler.match(tree, 'comp') |
|
eval(code) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// a neat trick: dispatch on node tags using higher-order rule "apply" |
|
|
|
ometa CalcCompiler { |
|
comp [anything:t apply(t):ans] -> ans, |
|
num anything:x -> x.toString(), |
|
add comp:x comp:y -> ('(' + x + '+' + y + ')'), |
|
sub comp:x comp:y -> ('(' + x + '-' + y + ')'), |
|
mul comp:x comp:y -> ('(' + x + '*' + y + ')'), |
|
div comp:x comp:y -> ('(' + x + '/' + y + ')') |
|
} |
|
|
|
code = CalcCompiler.match(tree, 'comp') |
|
eval(code) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|