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.
151 lines
3.1 KiB
151 lines
3.1 KiB
1 month ago
|
// 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)
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|