ometa CalcParser { sp = ' ' | '\t', q1 = "'", q2 = '"', newline = '\n' | '\r' | '\n' '\r' | '\r' '\n', start = line*:x -> [['start']].concat(x).concat([['end']]), line = ~newline sp* stmt:x sp* newline -> x | ~newline sp* stmt:x sp* -> x // last line no CRLF | ~newline sp* newline -> ['noop'] | newline -> ['noop'] | Comment, Comment = fromTo('/*', '*/') | fromTo('//', '\n'), fromTo :x :y = seq(x) (~seq(y) char)* seq(y) -> ['noop'], stmt = ASSIGN:x -> ['stmt', x] | BEGIN_LOOP:x -> ['stmt', x] | END_LOOP:x -> ['stmt', x] | PRINT:x -> ['stmt', x] | CHANGE:x -> ['stmt', x] | IF:x -> ['stmt', x] | ENDIF:x -> ['stmt', x] | DOWHILE:x -> ['stmt', x] | ENDWHILE:x -> ['stmt', x] | DOUNTIL:x -> ['stmt', x] | ENDUNTIL:x -> ['stmt', x] | REQUEST:x -> ['stmt', x] | ERROR:x -> ['error', x], ERROR = (~newline char)+:x -> x.join(''), IF = "IF" sp+ "COND(" sp* cond:x sp* ")" -> ['if', x] | "IF" sp+ "(" sp* cond:x sp* ")" -> ['if', x], ENDIF = "ENDIF" -> ['endif'], DOWHILE = "DOWHILE" sp+ "COND(" sp* cond:x sp* ")" -> ['dowhile',x] | "DOWHILE" sp+ "(" sp* cond:x sp* ")" -> ['dowhile',x], ENDWHILE = "ENDWHILE" -> ['endwhile'], DOUNTIL = "DOUNTIL" sp+ "COND(" sp* cond:x sp* ")" -> ['dountil',x] | "DOUNTIL" sp+ "(" sp* cond:x sp* ")" -> ['dountil',x], ENDUNTIL = "ENDUNTIL" -> ['enduntil'], cond = addExpr:x logic_op:o addExpr:y -> ['cond',x,o,y], logic_op = ("=" | "*EQ"):x -> ['logic_op', '=='] | ("*LE" | "<="):x -> ['logic_op', '<='] | ("*GE" | ">="):x -> ['logic_op', '>='] | ("*NE" | "<>"):x -> ['logic_op', '!='] | ("*LT" | "<"):x -> ['logic_op', '<'] | ("*GT" | ">"):x -> ['logic_op', '>'], CHANGE = "CHANGE" sp+ "FIELD(" sp* fields:f sp* ")" sp+ "TO(" sp* changeto:t sp* ")" -> ['change',['fields',f],['to',t]], REQUEST = "REQUEST" sp+ "FIELDS(" sp* fields:f sp* ")" -> ['request',['fields',f]], BEGIN_LOOP = "BEGIN_LOOP" sp+ BL_USING:u BL_FROM:f BL_TO:t BL_STEP:s -> ['begin_loop',u,f,t,s], BL_USING = "USING(" sp* addExpr:u sp* ")" sp+ -> u | sp* -> ['*internal'], BL_FROM = "FROM(" sp* addExpr:f sp* ")" sp+ -> f | sp* -> ['num','1'], BL_TO = "TO(" sp* addExpr:t sp* ")" sp+ -> t | sp* -> ['num','9999999'], BL_STEP = "STEP(" sp* addExpr:s sp* ")" -> s | sp* -> ['num','1'], END_LOOP = "END_LOOP" -> ['end_loop'], ASSIGN = id:x sp* ":=" sp* addExpr:y sp* -> ['assign', x, y], PRINT = "PRINT(" sp* id:x sp* ")" -> ['print_id', x] | "PRINT(" sp* q1 literal1:x q1 sp* ")" -> ['print_lit1', x] | "PRINT(" sp* q2 literal2:x q2 sp* ")" -> ['print_lit2', x], literal1 = (~")" ~q1 char)+:x -> ['literal', x.join('')], literal2 = (~")" ~q2 char)+:x -> ['literal', x.join('')], fields = id:x sp+ fields:y -> [x].concat(y) | id:x -> [x], changeto = addExpr | id, addExpr = addExpr:x sp* '+' sp* mulExpr:y -> ['add', x, y] | addExpr:x sp* '-' sp* mulExpr:y -> ['sub', x, y] | mulExpr, mulExpr = mulExpr:x sp* '*' sp* primExpr:y -> ['mul', x, y] | mulExpr:x sp* '/' sp* primExpr:y -> ['div', x, y] | primExpr, primExpr = '(' sp* addExpr:x sp* ')' -> x | sp* digit+:d sp* -> ['num', d.join('')] | id:x -> x, id = '#' letter+:x (letter|digit)*:y -> ['id', x.join('') + y.join('')] } var source = " CHANGE FIELD( #C ) TO( #A / #B ) REQUEST FIELDS(#X #Y #Z) IF (1 = 0) #X := 1 DOWHILE COND(#X <= 3) PRINT(#X) #X := #X + 1 #Y := 1 DOWHILE COND(#Y <= 3) PRINT(#Y) #Y := #Y + 1 ENDWHILE ENDWHILE ENDIF #A := 1 DOUNTIL COND(#A >= 3) PRINT(#A) #A := #A + 1 #B := 1 DOUNTIL COND(#B >= 3) PRINT(#B) #B := #B + 1 ENDUNTIL ENDUNTIL "; tree = CalcParser.matchAll(source, 'start') // [[start], [noop], [stmt, [request, [fields, [[id, X], [id, Y], [id, Z]]]]], [end]] ometa CalcCompiler { ast = [array*:x] -> x.join(''), array = ['stmt' comp:x] -> (x + '\n') | ['noop'] -> ' ' | ['start'] -> { dowhilestack = new Array(); return ' '?> \n' | ['error' :x] -> ('//ERROR -> ' + x + '\n'), comp = ['num' :x ] -> x | ['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 + ')') | ['id' :x] -> ('$' + x) | ['assign' comp:x comp:y] -> (x + '=' + y + ';') | ['change' ['fields' [comp+:x]] ['to' comp:y]] -> {var myX = ''; for(i=0;i ('echo ' + x + ',"
\n";' ) | ['print_lit1' comp:x] -> ('echo ' + "'" + x + "'" + ',"
\n";' ) | ['print_lit2' comp:x] -> ('echo ' + '"' + x + '"' + ',"
\n";' ) | ['literal' :l] -> l | ['begin_loop' comp:u comp:f comp:t comp:s] -> ('for (' + u + '=' + f + '; ' + u + '<=' + t + '; ' + u + '+=' + s + ') {') | ['*internal'] -> ('$i') | ['end_loop'] -> ('}') | ['if' comp:x] -> ('if ' + x + ' {') | ['cond' comp:x comp:o comp:y] -> ('(' + x + o + y + ')') | ['logic_op' :o] -> o | ['endif'] -> ('}') | ['dountil' comp:x] -> {dowhilestack.push(x); return 'do {' } | ['enduntil'] -> {'} while (!' + dowhilestack.pop() + ');'} | ['dowhile' comp:x] -> ('while ' + x + ' {') | ['endwhile'] -> ('}') | ['request' ['fields' [comp+:x]] ] -> {var myY = ''; for(i=0;i