/* * expr_cpp.tc - Expression example treecc input file for C++. * * Copyright (C) 2001 Southern Storm Software, Pty Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ %option lang = "C++" %option reentrant %header "expr_cpp.h" %output "expr_cpp.cc" /* * Include the following declarations into the ".h" file. */ %decls %{ /* * Value that is computed by "eval_expr" below. */ typedef union { int int_value; float float_value; } eval_value; %} /* * Include the following declarations into the ".cc" file. */ %{ #include #include #include #include #include "expr_cpp.h" %} /* * Define the type code that is associated with a node * in the syntax tree. We use "error_type" to indicate * a failure during type inferencing. */ %enum type_code = { error_type, int_type, float_type } /* * Define the node types that make up the syntax. */ %node expression %abstract %typedef = { %nocreate type_code type = {error_type}; } %node binary expression %abstract = { expression *expr1; expression *expr2; } %node unary expression %abstract = { expression *expr; } %node intnum expression = { int num; } %node floatnum expression = { float num; } %node plus binary %node minus binary %node multiply binary %node divide binary %node power binary %node negate unary %node cast expression = { type_code new_type; expression *expr; } /* * Define the "infer_type" operation as a non-virtual. */ %operation void infer_type(expression *e) infer_type(binary) { infer_type(e->expr1); infer_type(e->expr2); if(e->expr1->type == error_type || e->expr2->type == error_type) { e->type = error_type; } else if(e->expr1->type == float_type || e->expr2->type == float_type) { e->type = float_type; } else { e->type = int_type; } } infer_type(unary) { infer_type(e->expr); e->type = e->expr->type; } infer_type(intnum) { e->type = int_type; } infer_type(floatnum) { e->type = float_type; } infer_type(power) { infer_type(e->expr1); infer_type(e->expr2); if(e->expr1->type == error_type || e->expr2->type == error_type) { e->type = error_type; } else if(e->expr2->type != int_type) { cerr << e->getFilename() << ":" << e->getLinenum() << ": second argument to `^' is not an integer" << endl; e->type = error_type; } else { e->type = e->expr1->type; } } infer_type(cast) { infer_type(e->expr); if(e->expr->type != error_type) { e->type = e->new_type; } else { e->type = error_type; } } /* * Define the "eval_expr" operation as a virtual. */ %operation %virtual eval_value eval_expr(expression *this) eval_expr(plus) { /* Evaluate the sub-expressions */ eval_value value1 = expr1->eval_expr(); eval_value value2 = expr2->eval_expr(); /* Coerce to the common type */ coerce(&value1, expr1->type, type); coerce(&value2, expr2->type, type); /* Evaluate the operator */ if(type == int_type) { value1.int_value += value2.int_value; } else { value1.float_value += value2.float_value; } /* Return the result to the caller */ return value1; } eval_expr(minus) { /* Evaluate the sub-expressions */ eval_value value1 = expr1->eval_expr(); eval_value value2 = expr2->eval_expr(); /* Coerce to the common type */ coerce(&value1, expr1->type, type); coerce(&value2, expr2->type, type); /* Evaluate the operator */ if(type == int_type) { value1.int_value -= value2.int_value; } else { value1.float_value -= value2.float_value; } /* Return the result to the caller */ return value1; } eval_expr(multiply) { /* Evaluate the sub-expressions */ eval_value value1 = expr1->eval_expr(); eval_value value2 = expr2->eval_expr(); /* Coerce to the common type */ coerce(&value1, expr1->type, type); coerce(&value2, expr2->type, type); /* Evaluate the operator */ if(type == int_type) { value1.int_value *= value2.int_value; } else { value1.float_value *= value2.float_value; } /* Return the result to the caller */ return value1; } eval_expr(divide) { /* Evaluate the sub-expressions */ eval_value value1 = expr1->eval_expr(); eval_value value2 = expr2->eval_expr(); /* Coerce to the common type */ coerce(&value1, expr1->type, type); coerce(&value2, expr2->type, type); /* Evaluate the operator */ if(type == int_type) { if(value2.int_value != 0) { value1.int_value /= value2.int_value; } else { cerr << getFilename() << ":" << getLinenum() << ": division by zero" << endl; value1.int_value = 0; } } else { value1.float_value /= value2.float_value; } /* Return the result to the caller */ return value1; } eval_expr(power) { /* Evaluate the sub-expressions */ eval_value value1 = expr1->eval_expr(); eval_value value2 = expr2->eval_expr(); /* Evaluate the operator */ if(type == int_type) { value1.int_value = (int)(pow((double)(value1.int_value), (double)(value2.int_value))); } else { value1.float_value = (float)(pow((double)(value1.float_value), (double)(value2.int_value))); } /* Return the result to the caller */ return value1; } eval_expr(negate) { /* Evaluate the sub-expression */ eval_value value = expr->eval_expr(); /* Evaluate the operator */ if(type == int_type) { value.int_value = -(value.int_value); } else { value.float_value = -(value.float_value); } /* Return the result to the caller */ return value; } eval_expr(cast) { /* Evaluate the sub-expression */ eval_value value = expr->eval_expr(); /* Cast to the final type */ coerce(&value, expr->type, type); /* Return the result to the caller */ return value; } eval_expr(intnum) { eval_value value; value.int_value = num; return value; } eval_expr(floatnum) { eval_value value; value.float_value = num; return value; } /* * Define the "coerce" operation as an inline non-virtual. */ %operation %inline void coerce (eval_value *value, [type_code from], [type_code to]) coerce(int_type, float_type) { value->float_value = (float)(value->int_value); } coerce(float_type, int_type) { value->int_value = (int)(value->float_value); } coerce(type_code, type_code) { /* Nothing to do here */ } /* * Include the following code at the end of the ".h" file. */ %end %decls %{ /* * Inherit YYNODESTATE to provide additional functionality. */ class NodeState : public YYNODESTATE { private: char *progname; char *filename; long linenum; public: NodeState(char *_progname, char *_filename) : YYNODESTATE() { filename = _filename; linenum = 1; } virtual ~NodeState(); public: virtual char *currFilename(); virtual long currLinenum(); virtual void failed(); void incLine() { ++linenum; } }; %} /* * Include the following code at the end of the ".cc" file. */ %end %{ /* * Entry points that are imported from the yacc parser. */ extern void yyrestart(FILE *file); extern int yyparse(void *); /* * Main entry point for the expression parser and evaluator. */ int main(int argc, char *argv[]) { FILE *file; char *filename; int retval; /* Parse the command-line arguments and open the input file */ if(argc < 2) { filename = "stdin"; file = stdin; } else if((file = fopen(argv[1], "r")) == NULL) { perror(argv[1]); return 1; } else { filename = argv[1]; } /* Create the node factory and state object */ NodeState *state = new NodeState(argv[0], filename); /* Parse and evaluate the expressions in the input */ retval = yyparse(state); /* Clean up and exit */ delete state; return retval; } /* * Destructor for NodeState. */ NodeState::~NodeState() { /* Nothing needs to be done here */ } /* * Get the name of the current input file in use by the parser. */ char *NodeState::currFilename() { return filename; } /* * Get the line number for the current input line in use by the parser. */ long NodeState::currLinenum() { return linenum; } /* * Report memory failure and exit. */ void NodeState::failed() { cerr << progname << ": virtual memory exhausted" << endl; exit(1); } %}