/* astci.cpp Script Language Development Kit Compile bytecode from an Abstract Syntax Tree Copyright (c) 1996-2002 Parsifal Software. All Rights Reserved. For further information about this program or the AnaGram parser generator, please contact: Parsifal Software http://www.parsifalsoft.com info@parsifalsoft.com +1-800-879-2577, Voice/Fax +1-508-358-2564 P.O. Box 219 Wayland, MA 01778 USA */ #include "comdefs.h" #include "astci.h" /* Function to do constant arithmetic prior to compilation Note that node pointer is passed by reference rather than value so the node can be replaced if necessary */ #ifdef OPTIMIZE void Compiler::doConstantArithmetic(AstNode *&node) { try { // Recurse on subnodes int i; for (i = 0; i < nSubnodes[node->type]; i++) doConstantArithmetic(node->subnode[i]); switch(node->type) { // Handle ListNode nodes case typeStatementBlock: case typeDump: case typePrint: { ListNode *listNode = (ListNode *) node; for (int i = 0; i < listNode->list.size(); i++) { doConstantArithmetic(listNode->list[i]); } return; } // Handle arithmetic operators case typeUnary: { if (node->subnodesUnary.operand->type == typeConstant) { ConstantNode *constant = (ConstantNode *) node->subnodesUnary.operand; Value value = constant->value; UnaryNode *unary = (UnaryNode *) node; switch (unary->opcode) { case NEG: value = -value; break; case NOT: value = !value; break; case COM: value = ~value; break; case CAST_LONG: value.makeInteger(); break; case CAST_DOUBLE: value.makeReal(); break; } constant->value = value; constant->context = node->context; node = constant; } return; } case typeBinary:{ if (node->subnodesBinary.left->type == typeConstant && node->subnodesBinary.right->type == typeConstant) { BinaryNode *binary = (BinaryNode *) node; ConstantNode *leftConstant = (ConstantNode *) node->subnodesBinary.left; ConstantNode *rightConstant = (ConstantNode *) node->subnodesBinary.right; Value leftValue = leftConstant->value; Value rightValue = rightConstant->value; switch (binary->opcode) { case EQ: leftValue == rightValue; break; case NE: leftValue != rightValue; break; case LT: leftValue < rightValue; break; case LE: leftValue <= rightValue; break; case GT: leftValue > rightValue; break; case GE: leftValue >= rightValue; break; case ADD: leftValue += rightValue; break; case SUB: leftValue -= rightValue; break; case MUL: leftValue *= rightValue; break; case DIV: leftValue /= rightValue; break; case IDIV: { leftValue.assertInteger(); rightValue.assertInteger(); leftValue /= rightValue; break; } case RDIV: leftValue.makeReal() /= rightValue; break; case MOD: leftValue %= rightValue; break; case POW: leftValue = pow(leftValue, rightValue); break; case AND: leftValue &= rightValue; break; case IOR: leftValue |= rightValue; break; case XOR: leftValue ^= rightValue; break; case LS: leftValue <<= rightValue; break; case RS: leftValue >>= rightValue; break; } leftConstant->value = leftValue; node = leftConstant; } return; } } } catch(ErrorMessage e) { node->reportError(e.message()); } } #endif CodeFragment Compiler::compile(const AstNode *node) { int index; try { switch(node->type) { case typeStatementBlock: { CodeFragment code; ListNode *listNode = (ListNode *) node; for (int i = 0; i < listNode->list.size(); i++) { code.concat(compile(listNode->list[i])); } return code; } case typeVariable: { VariableNode *variable = (VariableNode *) node; index = dictionary.intern(variable->name); return CodeFragment().append(LOCATE,index); } case typeDump: { ListNode *listNode = (ListNode *) node; const AgArray &list = listNode-> list; CodeFragment code; for (int i = 0; i < list.size(); i++) { VariableNode *variable = (VariableNode *) list[i]; index = dictionary.intern(variable->name); code.append(DUMP, index); } return code; } case typePrint: { ListNode *listNode = (ListNode *) node; const AgArray &list = listNode-> list; CodeFragment code; for (int i = 0; i < list.size(); i++) { code.concat(compile(list[i]).append(PRINT)); } return code; } case typeReturn: { Opcode op = HLT; CodeFragment code; if (node->subnodesReturn.expression->type != typeNull) { code = compile(node->subnodesReturn.expression); op = RETURN;; } return code.append(op); } case typeConstant: { ConstantNode *constantNode = (ConstantNode *) node; index = constants.intern(constantNode->value); return CodeFragment().append(PUSHC, index); } case typeUnary: { UnaryNode *unary = (UnaryNode *) node; return compile(node->subnodesUnary.operand) .append(unary->opcode); } case typeBinary: { BinaryNode *binary = (BinaryNode *) node; return compile(node->subnodesBinary.left) .concat(compile(node->subnodesBinary.right)) .append(binary->opcode); } case typeCommaExpression: { return compile(node->subnodesBinary.left) .append(POP) .concat(compile(node->subnodesBinary.right)); } case typeExpressionStatement: { return compile(node->subnodesExpressionStatement.expression) .append(POP); } case typeAssignment: { AssignmentNode *assignment = (AssignmentNode *) node; return compile(node->subnodesAssignment.lvalue) .concat(compile(node->subnodesAssignment.expression)) .append(assignment->opcode); } case typeConditionalExpression: { CodeFragment condition = compile(node->subnodesConditionalExpression.condition); CodeFragment trueCode = compile(node->subnodesConditionalExpression.onTrue); CodeFragment falseCode = compile(node->subnodesConditionalExpression.onFalse); return CodeFragment::ifElse(condition, trueCode, falseCode); } case typeLogicalOrExpression: { CodeFragment rightCode = compile(node->subnodesLogicalOrExpression.right); return compile(node->subnodesLogicalOrExpression.left) .append(LOR, rightCode.size()) .concat(rightCode); } case typeLogicalAndExpression: { CodeFragment rightCode = compile(node->subnodesLogicalAndExpression.right); return compile(node->subnodesLogicalOrExpression.left) .append(LAND, rightCode.size()) .concat(rightCode); } case typeIfElseStatement: { #ifdef OPTIMIZE // Check for constant condition if (node->subnodesIfElseStatement.condition->type == typeConstant) { // Condition is constant ConstantNode *constantNode = (ConstantNode *) node->subnodesIfElseStatement.condition; // If condition is true, compile true code if (constantNode->value.isTrue()) return compile(node->subnodesIfElseStatement.onTrue); // Condition is false, return false option return compile(node->subnodesIfElseStatement.onFalse); } #endif CodeFragment condition = compile(node->subnodesIfElseStatement.condition); CodeFragment trueCode = compile(node->subnodesIfElseStatement.onTrue); CodeFragment falseCode = compile(node->subnodesIfElseStatement.onFalse); return CodeFragment::ifElse(condition, trueCode, falseCode); } case typeIfStatement: { #ifdef OPTIMIZE // Check for constant condition if (node->subnodesIfStatement.condition->type == typeConstant) { // Condition is constant ConstantNode *constantNode = (ConstantNode *) node->subnodesIfStatement.condition; // If condition is false, don't compile any code. if (constantNode->value.isFalse()) return CodeFragment(); // Condition is true, compile code without any conditional return compile(node->subnodesIfStatement.statement); } #endif CodeFragment condition = compile(node->subnodesIfElseStatement.condition); CodeFragment statementCode = compile(node->subnodesIfStatement.statement); return CodeFragment::ifStatement(condition, statementCode); } case typeWhileStatement: { #ifdef OPTIMIZE // Check for constant loop condition if (node->subnodesWhileStatement.condition->type == typeConstant) { // Loop condition is constant ConstantNode *constantNode = (ConstantNode *) node->subnodesWhileStatement.condition; // If loop condition is false, don't compile any code. if (constantNode->value.isFalse()) return CodeFragment(); CodeFragment code = compile(node->subnodesWhileStatement.statement); if (!code.containsBreak()) node->reportError("Loop has no exit"); // Otherwise, compile loop without any testing return code.appendContinue(BR).patchBranches(); } // Loop condition is not constant #endif CodeFragment condition = compile(node->subnodesWhileStatement.condition); CodeFragment statementCode = compile(node->subnodesWhileStatement.statement); return CodeFragment::whileLoop(condition, statementCode); } case typeDoStatement: { CodeFragment statement = compile(node->subnodesDoStatement.statement); CodeFragment condition = compile(node->subnodesDoStatement.condition); return CodeFragment::doLoop(statement, condition); } case typeRepeatStatement: { CodeFragment statement = compile(node->subnodesDoStatement.statement); CodeFragment condition = compile(node->subnodesDoStatement.condition); return CodeFragment::repeatLoop(statement, condition); } case typeSimpleFor: { CodeFragment lvalue = compile(node->subnodesSimpleFor.lvalue); CodeFragment begin = compile(node->subnodesSimpleFor.begin); CodeFragment inc = compile(node->subnodesSimpleFor.inc); CodeFragment end = compile(node->subnodesSimpleFor.end); CodeFragment statement = compile(node->subnodesSimpleFor.statement); return CodeFragment::simpleForLoop(lvalue, begin, inc, end, statement); } case typeForStatement: { CodeFragment initCode = compile(node->subnodesForStatement.init); CodeFragment condCode = compile(node->subnodesForStatement.cond); CodeFragment incCode = compile(node->subnodesForStatement.inc); CodeFragment statementCode = compile(node->subnodesForStatement.statement); return CodeFragment::forLoop(initCode, condCode, incCode, statementCode); } case typeBreak: { return CodeFragment().appendBreak(BR); } case typeContinue: { return CodeFragment().appendContinue(BR); } case typeFunctionCall: { FunctionCallNode *function = (FunctionCallNode *) node; int argCount = function->argList.size(); CodeFragment code; for (int i = 0; i < argCount; i++) { code.concat(compile(function->argList[i])); } int k = idFunction(function->name, argCount); return code.append(CALL, k); } default: { CodeFragment code; for (int i = 0; i < nSubnodes[node->type]; i++) code.concat(compile(node->subnode[i])); return code; } } } catch(ErrorMessage e) { node->reportError(e.message()); } return CodeFragment(); } ScriptMethod::ScriptMethod(const char *text, AgDictionary &d) : dictionary(d), bytecode(), constantList() { Compiler compiler(text, d); bytecode = compiler.compile().getBytecode(); constantList = compiler.constants.contents(); } CodeFragment Compiler::compile() { #ifdef OPTIMIZE // Perform constant arithmetic doConstantArithmetic(tree.root); #endif // Compile code, add Halt instruction on end return compile(tree.root).append(HLT); } Value interpret(const char *text, Dataset &d) { ScriptMethod method(text,d.dictionary); // List the generated code //method.list(cout); // Execute the generated code return method.apply(d); }