Created
April 6, 2013 04:46
-
-
Save forestbelton/5324847 to your computer and use it in GitHub Desktop.
VVTB interpreter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
intro = [ | |
'=======================================', | |
'VVTB (Very Very Tiny Basic) interpreter', | |
'(c) 2012 Forest Belton (case)', | |
'=======================================' | |
] | |
prgm = {} | |
vars = {} | |
add_msg = (msg, error) -> | |
classes = if error is true then 'error' else '' | |
$('#msgs').append "<div class=\"#{classes}\">#{msg}</div>" | |
getlines = () -> | |
lines = [] | |
for line of prgm | |
lines.push parseInt(line) | |
return lines.sort (a,b) -> a - b | |
print_prgm = () -> | |
keys = getlines() | |
for key in keys | |
add_msg prgm[key].raw, false | |
run_prgm = () -> | |
lines = getlines() | |
pc = lines[0] | |
while prgm[pc] isnt undefined | |
console.log "PC: #{pc}" | |
pc = eval_prgm pc, prgm[pc].stmt, lines | |
eval_prgm = (pc, stmt, lines) -> | |
switch stmt.type | |
when 'goto' then return stmt.line | |
when 'let' then vars[stmt.dest] = eval_expr stmt.val | |
when 'print' then add_msg (stmt.items.map(eval_expr).join ''), false | |
when 'if' then if stmt.cond.op eval_expr(stmt.cond.left), eval_expr(stmt.cond.right) then return stmt.line | |
for line in lines | |
if line > pc | |
return line | |
return undefined | |
eval_expr = (stmt) -> | |
if typeof stmt is 'object' | |
return stmt.op eval_expr(stmt.left), eval_expr(stmt.right) | |
else if typeof stmt is 'string' | |
return vars[stmt] | |
else | |
return stmt | |
readline = () -> | |
add_msg '> ' + $('#input').val(), false | |
try | |
line = vvtb.parse $('#input').val() + '\n' | |
catch error | |
add_msg error.message, true | |
return | |
switch line.stmt.type | |
when 'new' then prgm = {} | |
when 'list' then print_prgm() | |
when 'run' then run_prgm() | |
when 'delete' then delete prgm[line.line] | |
else prgm[line.line] = { 'raw' : $('#input').val(), 'stmt' : line.stmt } | |
$('document').ready () -> | |
for line in intro | |
add_msg line, false | |
$('#input').focus() | |
$(document).click () -> | |
$('#input').focus() | |
$('#input').keydown (e) -> | |
if e.which is 13 | |
readline() | |
$('#input').val '' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
function make_stmt(s, args) { | |
var stmt = { 'type' : s }; | |
switch(s) { | |
case 'let': | |
stmt['dest'] = args[0]; | |
stmt['val'] = args[1]; | |
break; | |
case 'if': | |
stmt['cond'] = args[0]; | |
stmt['line'] = args[1]; | |
break; | |
case 'print': | |
stmt['items'] = args[0]; | |
break; | |
case 'rem': | |
stmt['comment'] = args[0]; | |
break; | |
case 'goto': | |
stmt['line'] = args[0]; | |
break; | |
} | |
return stmt; | |
} | |
ops = { | |
'+' : function(x,y) { return x + y }, | |
'-' : function(x,y) { return x - y }, | |
'*' : function(x,y) { return x * y }, | |
'/' : function(x,y) { return x / y }, | |
'<' : function(x,y) { return x < y }, | |
'>' : function(x,y) { return x > y }, | |
'=' : function(x,y) { return x == y }, | |
'<>' : function(x,y) { return x != y }, | |
'<=' : function(x,y) { return x <= y }, | |
'>=' : function(x,y) { return x >= y }, | |
} | |
} | |
line | |
= line:cmd_line ws '\n' { return line } | |
/ line:prog_line ws '\n' { return line } | |
cmd_line | |
= 'RUN' { return { 'stmt' : make_stmt('run') } } | |
/ 'LIST' { return { 'stmt' : make_stmt('list') } } | |
/ 'NEW' { return { 'stmt' : make_stmt('new') } } | |
/ 'QUIT' { return { 'stmt' : make_stmt('quit') } } | |
prog_line | |
= line:number ws s:stmt? { if(s=='') s = make_stmt('delete',[]); return { 'line' : line, 'stmt' : s} } | |
stmt | |
= 'LET' ws v:variable ws '=' ws e:expr { return make_stmt('let', [v, e]) } | |
/ 'IF' ws cond:test ws 'THEN' ws line:number { return make_stmt('if', [cond, line]) } | |
/ 'PRINT' ws p:print_items { return make_stmt('print', [p]) } | |
/ 'REM' ws line:[^\n]+ { return make_stmt('rem', [line.join('')]) } | |
/ 'GOTO' ws line:number { return make_stmt('goto', [line]) } | |
print_items | |
= p:print_item ws ',' ws ps:print_items { ps.unshift(p); return ps } | |
/ p:print_item ws ';' ws ps:print_items { ps.unshift(p); return ps } | |
/ p:print_item { return [p] } | |
separator | |
= ',' | |
/ ';' | |
print_item | |
= expr | |
/ string | |
test | |
= left:expr ws comp:comparison ws right:expr { return { 'left' : left, 'right' : right, 'op' : ops[comp] } } | |
comparison | |
= '=' | |
/ '<>' | |
/ '<' | |
/ '<=' | |
/ '>' | |
/ '>=' | |
expr | |
= left:secondary ws op:[+-] ws right:expr { return { 'op' : ops[op], 'left' : left, 'right' : right } } | |
/ secondary | |
secondary | |
= left:primary ws op:[*/] ws right:secondary { return { 'op' : ops[op], 'left' : left, 'right' : right } } | |
/ p:primary { return p } | |
primary | |
= '(' e:expr ')' { return e } | |
/ variable | |
/ number | |
string | |
= ["] data:[^"]+ ["] { return data.join('') } | |
variable | |
= [A-Z] | |
number | |
= digits:[0-9]+ { return parseInt(digits.join('')) } | |
ws | |
= [ \t\v\f]* |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment