/* a little basic interpreter written in paraflow. * the syntax of this language is: * label: statement * where statement is either * var = expression * print expression * goto label * if expression statement * gosub label * return */ include 'stringTo' string usage = " This is a little horrible basic patterned after microsoft basic of 1983. This is just a test program for ParaFlow mostly. Usage: basic file.basic "; if (args.size != 1) punt(usage); class codeLine // A single line of basic code. { codeLine next; // next line of code to execute string label; // label for the line, goto/gosub target string statement; // some sort of statement, we'll interpret on the fly } class retStack // Return addresss stack { retStack next; codeLine returnTo; } retStack retStack; dir of codeLine program = (); codeLine startLine, endLine; file f = fileOpen(args[0], "r"); int lineCount = 0; for (line in f.readLine()) { (string label, int pos) = line.nextToken(pos); if (label) { codeLine code = (nil, label, line.rest(pos)); if (startLine) { endLine.next = code; endLine = code; } else { startLine = code; endLine = code; } program[label] = code; lineCount += 1; } } print("read in " + lineCount + " lines of code"); print(startLine); dir of int vars = (); codeLine ip = startLine; int val; while (ip) { (string first, int pos) = ip.statement.nextToken(pos); if (first == "print") { (pos,val) = evalExp(ip.statement, pos); print(val); ip = ip.next; } else if (first == "goto") { (string where, int newPos) = ip.statement.nextToken(pos); ip = program[where]; if (!ip) punt("Can't find label " + where); } else if (first == "if") { (pos,val) = evalExp(ip.statement, pos); if (val) { (string gt, int newPos) = ip.statement.nextToken(pos); if (gt != "goto") punt("Expecting goto after if"); (string label, int np) = ip.statement.nextToken(newPos); ip = program[label]; if (!ip) punt("Can't find label " + label); } else { ip = ip.next; } } else if (first == "return") { if (retStack) { ip = retStack.returnTo; retStack = retStack.next; } else punt("Return without call"); } else if (first == "gosub") { retStack = (retStack, ip.next); (string label, int newPos) = ip.statement.nextToken(pos); ip = program[label]; if (!ip) punt("Can't find label " + label); } else if (isalpha(first[0])) { (string eq, int newPos) = ip.statement.nextToken(pos); if (eq != "=") punt("Expecting equals at " + ip.label + " " + ip.statement); int val; (newPos, val) = evalExp(ip.statement, newPos); vars[first] = val; ip = ip.next; } else { punt("I don't understand: " + ip.label + " " + ip.statement); } } to evalExp(string s, int pos) into int newPos,val { (newPos,val) = evalTerm(s, pos); } to evalTerm(string s, int pos) into int newPos,val { (newPos,val) = evalFactor(s, pos); for (;;) { (string w, int np) = s.nextToken(newPos); if (w == "+") { int v2; (newPos, v2) = evalFactor(s, np); val += v2; } else if (w == "-") { int v2; (newPos, v2) = evalFactor(s, np); val -= v2; } else break; } } to evalFactor(string s, int pos) into int newPos,val { (newPos,val) = evalAtom(s, pos); for (;;) { (string w, int np) = s.nextToken(newPos); if (w == "*") { int v2; (newPos, v2) = evalAtom(s, np); val *= v2; } else if (w == "/") { int v2; (newPos, v2) = evalAtom(s, np); val /= v2; } else break; } } to evalAtom(string s, int pos) into int newPos,val { string w; (w, newPos) = s.nextToken(pos); if (w == "(") { (newPos,val) = evalExp(s, newPos); (w, newPos) = s.nextToken(newPos); if (w != ")") punt("Unclosed parenthesis"); } else if (isnum(w[0])) { val = stringToInt(w); } else if (isalpha(w[0])) val = vars[w]; }