%lex %s comment %% <> { return "EOF"; } "\n" { this.popState(); return "NEWLINE"; } . { /* ignore anything else inside a comment */ } ";" { this.pushState('comment'); } [\n] { return "NEWLINE"; } \s { /* ignore whitespace */ } "MOV" { return "MOV"; } "ADD" { return "ADD"; } "SUB" { return "SUB"; } "CMP" { return "CMP"; } "SLT" { return "SLT"; } "JMP" { return "JMP"; } "JMZ" { return "JMZ"; } "JMN" { return "JMN"; } "DJN" { return "DJN"; } "SPL" { return "SPL"; } "DAT" { return "DAT"; } "EQU" { return "EQU"; } "END" { return "END"; } "," { return ","; } "#" { return "#"; } "@" { return "@"; } "<" { return "<"; } "$" { return "$"; } "(" { return "("; } ")" { return ")"; } "+" { return "+"; } "-" { return "-"; } "*" { return "*"; } "/" { return "/"; } [0-9]+ { return "NUMBER"; } [A-Z][A-Z0-9_]+ { return "LABEL"; } /lex %left '+' '-' %left '*' '/' %left UMINUS %% program : lines END coda { return { start: 0, program: $lines }; } | lines END label coda { return { start: yy.getLabel($label), program: $lines }; } ; coda : newlines EOF | EOF ; newlines : newlines NEWLINE | NEWLINE ; lines : lines line { if ($line !== null) { $lines.push($line); } $$ = $lines; } | line { if ($line === null) { $$ = []; } else { $$ = [ $line ]; } } ; line : row NEWLINE { $$ = $row; } | NEWLINE { $$ = null; } ; row : op { yy.step(); $$ = $op; } | label op { yy.setLine($label); yy.step(); $$ = $op; } | label EQU e { yy.setEqu($label, $e); $$ = null; } ; op : opcode address "," address { $$ = { opcode: $opcode, a: $address1, b: $address2 }; } | opcode address { $$ = { opcode: $opcode, a: $address, b: { mode: 'direct', value: 0 }, }; } ; opcode : MOV { $$ = $1; } | ADD { $$ = $1; } | SUB { $$ = $1; } | CMP { $$ = $1; } | SLT { $$ = $1; } | JMP { $$ = $1; } | JMZ { $$ = $1; } | JMN { $$ = $1; } | DJN { $$ = $1; } | SPL { $$ = $1; } | DAT { $$ = $1; } ; address : address_mode e { $$ = { mode: $1, value: $2 }; } | e { $$ = { mode: 'direct', value: $1 }; } ; address_mode : "#" { $$ = 'immediate'; } | "@" { $$ = 'indirect'; } | "<" { $$ = 'predecrement'; } | "$" { $$ = 'direct'; } ; e : e '+' e { $$ = Math.floor($e1 + $e2); } | e '-' e { $$ = Math.floor($e1 - $e2); } | e '*' e { $$ = Math.floor($e1 * $e2); } | e '/' e { $$ = Math.floor($e1 / $e2); } | '(' e ')' { $$ = Math.floor($e); } | '-' e %prec UMINUS { $$ = - $e; } | NUMBER { $$ = Math.floor(Number(yytext)); } | label { $$ = yy.getLabel($label); } ; label : LABEL { $$ = yytext; } ;