resource_type make_resource(id_type id, const_type c) { resource_type r = (resource_type) SafeMalloc(sizeof(resource_struct)); id_type old_id; id->ownernum = st.curclass; /* Left-hand side must not have appeared before, except maybe in dbase */ old_id = lookup_id(id); switch(id->type) { case I_UNDEFINED: id->source = COMPILE; add_identifier(id, I_RESOURCE); break; case I_RESOURCE: /* Allow redefinition of resources listed in database file */ if (id->source == COMPILE) action_error("Resource %s is defined twice", id->name); else old_id->source = COMPILE; id->source = COMPILE; break; default: action_error("Duplicate identifier %s", id->name); } r->lhs = id; r->rhs = c; return r; }
static void parse_next_action(struct action_context *ctx) { if (!ctx->n_tables) { action_error(ctx, "\"next\" action not allowed here."); } else if (lexer_match(ctx->lexer, LEX_T_LPAREN)) { int ltable; if (!action_get_int(ctx, <able)) { return; } if (!lexer_match(ctx->lexer, LEX_T_RPAREN)) { action_syntax_error(ctx, "expecting `)'"); return; } if (ltable >= ctx->n_tables) { action_error(ctx, "\"next\" argument must be in range 0 to %d.", ctx->n_tables - 1); return; } emit_resubmit(ctx, ctx->first_ptable + ltable); } else { if (ctx->cur_ltable < ctx->n_tables) { emit_resubmit(ctx, ctx->first_ptable + ctx->cur_ltable + 1); } else { action_error(ctx, "\"next\" action not allowed in last table."); } } }
expr_type make_expr_from_id(id_type id) { expr_type e = (expr_type) SafeMalloc(sizeof(expr_struct)); /* Id must be a parameter, local, property, constant, or resource */ lookup_id(id); switch(id->type) { case I_LOCAL: case I_PROPERTY: case I_CLASSVAR: e->type = E_IDENTIFIER; e->value.idval = id; break; case I_RESOURCE: { const_type c = (const_type) SafeMalloc(sizeof(const_struct)); /* Turn resource id reference into the resource # itself */ c->type = C_RESOURCE; c->value.numval = id->idnum; e->type = E_CONSTANT; e->value.constval = c; return e; } case I_CONSTANT: { const_type c = (const_type) SafeMalloc(sizeof(const_struct)); id_type temp; /* Turn constant id reference into the constant itself */ c->type = C_NUMBER; temp = (id_type) list_find_item(st.constants, id, id_compare); c->value.numval = temp->source; /* Value is stored in source field */ e->type = E_CONSTANT; e->value.constval = c; break; } case I_UNDEFINED: case I_MISSING: action_error("Unknown identifier %s", id->name); /* Put in something so that compilation can continue */ e = make_expr_from_constant(make_nil_constant()); break; default: action_error("Identifier %s in expression has wrong type", id->name); /* Put in something so that compilation can continue */ e = make_expr_from_constant(make_nil_constant()); break; } e->lineno = lineno; return e; }
param_type make_parameter(id_type id, expr_type e) { param_type p = (param_type) SafeMalloc(sizeof(param_struct)); if (e->type != E_CONSTANT) { action_error("Parameter can only be initialized to a constant"); return p; } lookup_id(id); /* Left-hand side must not have appeared before, except perhaps as a parameter */ switch (id->type) { case I_MISSING: /* The parameter has been referenced in a function call, but not declared anywhere * We should use the existent id # and remove the id from the missing list. * First we must make sure that the missing id is supposed to be a missing parameter. */ if (id->source != I_PARAMETER) { action_error("Parameter %s was referenced elsewhere with different type", id->name); break; } /* Insert directly into global table to preserve id # */ id->type = I_PARAMETER; id->source = COMPILE; table_insert(st.globalvars, (void *) id, id_hash, id_compare); /* Remove from missing list */ table_delete_item(st.missingvars, id, id_hash, id_compare); break; case I_UNDEFINED: /* New parameter # */ id->ownernum = st.curmessage; add_identifier(id, I_PARAMETER); break; case I_PARAMETER: /* Legal only if it hasn't yet appeared in this message */ if (id->ownernum == st.curmessage && id->source == COMPILE) action_error("Parameter %s appears twice", id->name); break; default: /* Other types indicate name already used */ action_error("Duplicate identifier %s", id->name); } p->lhs = id; p->rhs = e->value.constval; return p; }
const_type make_literal_message(id_type id) { const_type c = (const_type) SafeMalloc(sizeof(const_struct)); lookup_id(id); switch (id->type) { case I_MESSAGE: break; case I_MISSING: if (id->source != I_MESSAGE) action_error("Identifier %s was referenced earlier with different type", id->name); break; default: add_identifier(id, I_MISSING); id->source = I_MESSAGE; break; } /* Make a constant expression whose value is the id # */ c->type = C_MESSAGE; c->value.numval = id->idnum; return c; }
const_type make_number_from_constant_id(id_type id) { const_type c = (const_type) SafeMalloc(sizeof(const_struct)); lookup_id(id); switch(id->type) { case I_CONSTANT: c->type = C_NUMBER; c->value.numval = id->source; /* Value is stored in source field */ break; case I_RESOURCE: /* Turn resource id reference into the resource # itself */ c->type = C_RESOURCE; c->value.numval = id->idnum; break; default: action_error("Identifier %s can only be a constant here", id->name); return NULL; } return c; }
message_handler_type make_message_handler(message_header_type header, char *comment, list_type locals, list_type stmts) { message_handler_type h = (message_handler_type) SafeMalloc(sizeof(message_handler_struct)); stmt_type stmt; /* Last statement of body must be PROPAGATE or RETURN */ stmt = (stmt_type) list_last_item(stmts); if (stmt == NULL || (stmt->type != S_RETURN && stmt->type != S_PROP)) action_error("Last statement must be PROPAGATE or RETURN"); h->header = header; h->locals = locals; h->body = stmts; if (comment == NULL) h->comment = NULL; else h->comment = make_string_constant(comment); /* Clean out local variable table. We must do this at the end of * each handler, since in make_message_header we have already checked * parameters names against old variables, which includes parameters * from the current function in the local table. */ table_delete(st.localvars); st.maxlocals = -1; /* So that first local is numbered 0 */ return h; }
static void emit_ct(struct action_context *ctx, bool recirc_next, bool commit) { struct ofpact_conntrack *ct = ofpact_put_CT(ctx->ofpacts); ct->flags |= commit ? NX_CT_F_COMMIT : 0; /* If "recirc" is set, we automatically go to the next table. */ if (recirc_next) { if (ctx->cur_ltable < ctx->n_tables) { ct->recirc_table = ctx->first_ptable + ctx->cur_ltable + 1; } else { action_error(ctx, "\"ct_next\" action not allowed in last table."); return; } } else { ct->recirc_table = NX_CT_RECIRC_NONE; } ct->zone_src.field = mf_from_id(MFF_LOG_CT_ZONE); ct->zone_src.ofs = 0; ct->zone_src.n_bits = 16; /* We do not support ALGs yet. */ ct->alg = 0; /* CT only works with IP, so set up a prerequisite. */ struct expr *expr; char *error; expr = expr_parse_string("ip", ctx->symtab, &error); ovs_assert(!error); ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr); }
int CompareParameters(void *param1, void *param2) { param_type p1 = (param_type) param1; param_type p2 = (param_type) param2; if (p1->lhs->idnum == p2->lhs->idnum) action_error("Duplicate parameter %s!", p1->lhs->name); return (p1->lhs->idnum < p2->lhs->idnum); }
classvar_type make_classvar(id_type id, expr_type e) { classvar_type cv; cv = (classvar_type) SafeMalloc(sizeof(classvar_struct)); if (e->type != E_CONSTANT) { action_error("Classvar can only be initialized to a constant"); return cv; } lookup_id(id); switch(id->type) { case I_CONSTANT: case I_PROPERTY: action_error("Duplicate identifier %s", id->name); break; /* Legal if it hasn't yet appeared in this class */ case I_CLASSVAR: if (id->ownernum == st.curclass && id->source == COMPILE) action_error("Class variable %s appears twice", id->name); else { id->ownernum = st.curclass; id->source = COMPILE; add_identifier(id, I_CLASSVAR); } break; default: id->source = COMPILE; id->ownernum = st.curclass; add_identifier(id, I_CLASSVAR); break; } cv->id = id; cv->rhs = e->value.constval; return cv; }
stmt_type make_for_stmt(id_type id, expr_type expr, list_type stmts) { stmt_type stmt = (stmt_type) SafeMalloc(sizeof(stmt_struct)); for_stmt_type s = (for_stmt_type) SafeMalloc(sizeof(for_stmt_struct)); /* Loop variable must be a local, property or parameter */ lookup_id(id); if (id->type == I_UNDEFINED || id->type == I_MISSING) action_error("Unknown identifier %s", id->name); else if (id->type != I_LOCAL && id->type != I_PROPERTY) action_error("Loop variable %s has wrong type", id->name); s->id = id; s->condition = expr; s->body = stmts; stmt->type = S_FOR; stmt->value.for_stmt_val = s; return stmt; }
stmt_type make_prop_stmt() { stmt_type stmt = (stmt_type) SafeMalloc(sizeof(stmt_struct)); list_type l; /* Find current class */ for (l = st.classes; l != NULL; l = l->next) if (st.curclass == ((class_type) (l->data))->class_id->idnum) break; if ( ((class_type) (l->data))->superclass == NULL) action_error("Can't PROPAGATE in a class with no superclass"); stmt->type = S_PROP; return stmt; }
stmt_type make_assign_stmt(id_type id, expr_type expr) { stmt_type stmt = (stmt_type) SafeMalloc(sizeof(stmt_struct)); assign_stmt_type s = (assign_stmt_type) SafeMalloc(sizeof(assign_stmt_struct)); /* Left-hand side must be a local or property */ lookup_id(id); if (id->type == I_UNDEFINED || id->type == I_MISSING) action_error("Unknown identifier %s", id->name); else if (id->type != I_PROPERTY && id->type != I_LOCAL) action_error("Identifier %s cannot be assigned to", id->name); /* Can't assign to SELF */ if (id->type == I_PROPERTY && id->idnum == 0) action_error("Can't assign to self"); s->lhs = id; s->rhs = expr; stmt->type = S_ASSIGN; stmt->value.assign_stmt_val = s; return stmt; }
/* Parses an assignment or exchange action. */ static void parse_set_action(struct action_context *ctx) { struct expr *prereqs; char *error; error = expr_parse_assignment(ctx->lexer, ctx->symtab, ctx->ports, ctx->ofpacts, &prereqs); if (error) { action_error(ctx, "%s", error); free(error); return; } ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, prereqs); }
id_type make_var(id_type id) { /* Add to list of local variables, if it hasn't been defined */ lookup_id(id); switch(id->type) { case I_LOCAL: action_error("Duplicate identifier %s", id->name); default: id->ownernum = st.curmessage; add_identifier(id, I_LOCAL); break; } return id; }
void check_continue(void) { if (loop_depth == 0) action_error("Continue statement must appear inside a loop"); }
void check_break(void) { if (loop_depth == 0) action_error("Break statement must appear inside a loop"); }
property_type make_property(id_type id, expr_type e) { property_type p = (property_type) SafeMalloc(sizeof(property_struct)); if (e->type != E_CONSTANT) { action_error("Property can only be initialized to a constant"); return p; } /* Left-hand side must not have appeared as a property before, except possibly as a * property of one of our superclasses. Properties shadow other global names. */ lookup_id(id); switch(id->type) { case I_CONSTANT: action_error("Duplicate identifier %s", id->name); break; /* Legal if it hasn't yet appeared in this class */ case I_PROPERTY: if (id->ownernum == st.curclass && id->source == COMPILE) action_error("Property %s appears twice", id->name); else { id->ownernum = st.curclass; id->source = COMPILE; add_identifier(id, I_PROPERTY); } break; case I_CLASSVAR: if (id->ownernum == st.curclass && id->source == COMPILE) action_error("Property and classvar %s both appear in same class\n", id->name); else { classvar_type new_cv; id_type new_id; const_type new_const; // Override classvar with special tag value new_cv = (classvar_type) SafeMalloc(sizeof(classvar_struct)); new_const = (const_type) SafeMalloc(sizeof(const_struct)); new_id = duplicate_id(id); new_cv->id = new_id; new_cv->rhs = new_const; new_id->ownernum = st.curclass; new_id->source = COMPILE; new_const->type = C_OVERRIDE; // Replace classvar with property in table table_delete_item(st.classvars, id, id_hash, id_compare); id->ownernum = st.curclass; id->source = COMPILE; add_identifier(id, I_PROPERTY); // Store # of property in class var new_const->value.numval = id->idnum; st.override_classvars = list_add_item(st.override_classvars, new_cv); } break; default: id->source = COMPILE; id->ownernum = st.curclass; add_identifier(id, I_PROPERTY); break; } p->id = id; p->rhs = e->value.constval; return p; }
message_header_type make_message_header(id_type id, list_type args) { message_header_type s = (message_header_type) SafeMalloc(sizeof(message_header_struct)); id_type old_id, temp_id; param_type param; list_type l; /* Messsage name must be unique in this class, but may be the same * as a message in a different class. */ old_id = lookup_id(id); switch (id->type) { case I_MISSING: /* The message has been referenced in a function call, but not declared anywhere. * We should use the existent message # and remove the id from the missing list */ if (id->source != I_MESSAGE) { action_error("Message %s was referenced elsewhere with different type", id->name); break; } /* Insert directly into global table to preserve id # */ id->type = I_MESSAGE; id->ownernum = st.curclass; id->source = COMPILE; table_insert(st.globalvars, (void *) id, id_hash, id_compare); /* Remove from missing list */ table_delete_item(st.missingvars, id, id_hash, id_compare); break; case I_UNDEFINED: /* New message # */ id->ownernum = st.curclass; add_identifier(id, I_MESSAGE); break; case I_MESSAGE: /* Make sure message hasn't appeared in this class */ if (id->ownernum == st.curclass && id->source == COMPILE) action_error("Message handler %s defined twice in same class", id->name); old_id->ownernum = st.curclass; old_id->source = COMPILE; break; default: /* Other types indicate name already used */ action_error("Duplicate identifier %s", id->name); } s->message_id = id; /* Sort parameters in increasing id # order */ s->params = SortParameterList(args); /* Add parameters as handler's local variables--this must be done AFTER sorting */ for (l = s->params; l != NULL; l = l->next) { param = (param_type) l->data; /* Make a copy of the id for the local table */ temp_id = duplicate_id(param->lhs); temp_id->type = I_LOCAL; if (table_insert(st.localvars, (void *) temp_id, id_hash, id_compare) == 0) temp_id->idnum = ++st.maxlocals; } st.curmessage = id->idnum; return s; }
class_type make_class_signature(id_type class_id, id_type superclass_id) { list_type l; id_type old_id; class_type c = (class_type) SafeMalloc(sizeof(class_struct)); c->superclass = NULL; /* Will be set for real below */ c->class_id = class_id; /* Class name must not have appeared before */ old_id = lookup_id(class_id); switch(class_id->type) { case I_MISSING: /* The class has been referenced in a function call, but not declared anywhere * We should use the existent class # and remove the id from the missing list */ if (class_id->source != I_CLASS) { action_error("Class %s was referenced elsewhere with different type", class_id->name); break; } /* Insert directly into global table to preserve id # */ class_id->type = I_CLASS; class_id->source = COMPILE; table_insert(st.globalvars, (void *) class_id, id_hash, id_compare); /* Remove from missing list */ table_delete_item(st.missingvars, class_id, id_hash, id_compare); break; case I_UNDEFINED: /* New class name--continue normally */ add_identifier(class_id, I_CLASS); break; case I_CLASS: /* We are recompiling a previously existing class. This is rather ugly, since * we want to replace all the old class's data with our new data. However, to give * previously compiled subclasses a chance of working with the new version, we * should try to match class numbers, message #s, etc. with the old class. * At this point, all the old class's data have been inserted into our hash * tables. The new class will be inserted into st.globalvars. We must remove the old class * from the class list. */ /* If class is given twice in source files, that's an error */ if (class_id->source == COMPILE) action_error("Class %s is given twice", class_id->name); else /* Change the existent class id to reflect the fact that the class has now * been recompiled. */ old_id->source = COMPILE; class_id->source = COMPILE; /* Delete self from list of existent classes. Give warnings for subclasses. */ for (l = st.classes; l != NULL; l = l->next) if (is_parent(c, (class_type) l->data)) { if (((class_type) l->data)->class_id->idnum == c->class_id->idnum) st.classes = list_delete_item(st.classes, l->data, class_compare); else /* Don't give warning if deleted self from list */ { recompile_type recompile_info = (recompile_type) SafeMalloc(sizeof(recompile_struct)); recompile_info->class_id = ((class_type) (l->data))->class_id; recompile_info->superclass = c->class_id; /* Only add to list if it isn't already there */ if (list_find_item(st.recompile_list, recompile_info->class_id, recompile_compare) == NULL) st.recompile_list = list_add_item(st.recompile_list, (void *) recompile_info); } } break; default: action_error("Duplicate identifier %s", class_id->name); } /* Delete this class from list of those that need to be recompiled */ st.recompile_list = list_delete_item(st.recompile_list, (void *) c->class_id, recompile_compare); c->resources = NULL; c->properties = NULL; c->messages = NULL; c->is_new = True; /* We should generate code for this class */ /* Superclass must be defined, if one is given */ if (superclass_id != NULL) { lookup_id(superclass_id); if (superclass_id->type != I_CLASS) action_error("Can't find superclass %s", superclass_id->name); else if (class_id->idnum == superclass_id->idnum) action_error("Can't subclass from self", superclass_id->name); else { /* Find superclass's data and store a pointer to it. */ for (l = st.classes; l != NULL; l = l->next) if (superclass_id->idnum == ((class_type) (l->data))->class_id->idnum) { c->superclass = (class_type) l->data; break; } if (c->superclass == NULL) action_error("Unable to find superclass %s", superclass_id->name); } } else c->superclass = NULL; st.curclass = class_id->idnum; /* Now add superclasses' properties to our own property table, but delete * them from our property list. This way the table will hold all properties * that can be referenced in the class, but the property list will only * hold those that were declared in this class (need to know this for code gen) */ add_parent_properties(c, c->superclass); /* Similarly, add superclasses' classvars. This must be done AFTER adding the properties, * since some properties in a superclass could be overriding classvars in a superclass */ add_parent_classvars(NULL, c, c->superclass); /* Add to list of classes */ st.classes = list_add_item(st.classes, (void *) c); return c; }
stmt_type make_call(id_type function_id, list_type args) { stmt_type stmt = (stmt_type) SafeMalloc(sizeof(stmt_struct)); call_stmt_type s = (call_stmt_type) SafeMalloc(sizeof(call_stmt_struct)); int argnum = 0, argtype, continuation = ANONE, minargs = 0, i, index; const char *fname; arg_type arg; id_type id, new_id; s->args = NULL; /* Verify that id is the name of a built-in function */ lookup_id(function_id); if (function_id->type != I_FUNCTION) { action_error("Expecting a function name; found %s", function_id->name); return stmt; } index = function_id->idnum; /* index # of function to call */ fname = Functions[index].name; s->function = Functions[index].opcode; /* Check that types of arguments match "function prototype" in table */ for ( ; args != NULL; args = args->next) { argtype = Functions[index].params[argnum]; /* See if we are looking for one or more expressions or parameters */ if (continuation != ANONE) argtype = continuation; arg = (arg_type) args->data; switch (argtype) { case ANONE: action_error("Extra argument #%d to function %s", argnum+1, fname); return stmt; /* Ignore additional extra arguments */ break; case AEXPRESSIONS: continuation = AEXPRESSION; /* fall through */ case AEXPRESSION: /* Must have an expression here */ if (arg->type != ARG_EXPR) action_error("Expecting expression in argument #%d", argnum+1, fname); else s->args = list_add_item(s->args, (void *) arg); break; case ASETTINGS: continuation = ASETTING; /* fall through */ case ASETTING: if (arg->type != ARG_SETTING) { action_error("Expecting setting (i.e. #a=b ) in argument #%d", argnum+1, fname); break; } /* Find parameter id */ id = arg->value.setting_val->id; lookup_id(id); switch(id->type) { case I_UNDEFINED: /* If parameter hasn't been defined yet, put on missing list */ add_identifier(id, I_MISSING); /* Use source field to indicate where id came from for later checking */ id->source = I_PARAMETER; s->args = list_add_item(s->args, (void *) arg); break; case I_MISSING: if (id->source != I_PARAMETER) { action_error("Duplicate identifier %s", id->name); break; } s->args = list_add_item(s->args, (void *) arg); break; /* The tag here should be I_PARAMETER, but parameters also inserted as locals. */ case I_LOCAL: /* Unfortunately, we want the parameter id #, and not the local id #. So * we have to look up the id again in the global table. */ new_id = (id_type) table_lookup(st.globalvars, (void *) id, id_hash, id_compare); /* If it isn't there, then there happens to be a local variable of the same * name as this parameter, and the parameter hasn't appeared before. Thus the * parameter id should be added as a missing variable. We can't use the normal * lookup_id and add_identifier procs, since the local variable will mask * the missing one. */ if (new_id == NULL) { /* Of course, the id might already have been inserted as a missing var */ new_id = (id_type) table_lookup(st.missingvars, (void *) id, id_hash, id_compare); if (new_id == NULL) { id->source = I_PARAMETER; id->type = I_MISSING; id->idnum = ++st.maxid; table_insert(st.missingvars, (void *) id, id_hash, id_compare); } else { /* If it was already there, make sure that it was a parameter */ if (new_id->source != I_PARAMETER) action_error("Duplicate identifier %s", id->name); id->source = new_id->source; id->type = I_MISSING; id->source = I_PARAMETER; id->idnum = new_id->idnum; } } else { id = new_id; if (id->type != I_PARAMETER) action_error("Can't find parameter %s", id->name); } arg->value.setting_val->id = id; /* If literal exists, proceed normally */ s->args = list_add_item(s->args, (void *) arg); break; /* But if the identifier is from another handler, might not be local */ case I_PARAMETER: s->args = list_add_item(s->args, (void *) arg); break; default: action_error("Literal %s is a duplicate identifier", id->name); } break; } argnum++; } /* Check that no arguments left out */ for (i=0; i < MAXARGS; i++) { argtype = Functions[index].params[i]; if (argtype == ANONE || argtype == ASETTINGS || argtype == AEXPRESSIONS) break; /* Zero or more arguments follow */ minargs++; } if (argnum < minargs) action_error("Expecting %d arguments to %s; found %d", minargs, fname, argnum); /* Sort parameter arguments in increasing order for server efficiency */ s->args = SortArgumentList(s->args); stmt->type = S_CALL; stmt->value.call_stmt_val = s; return stmt; }
/* * SimplifyExpression: Attempt to simplify given expression. Modifies e. */ void SimplifyExpression(expr_type e) { expr_type e1, e2; const_type c1, c2; switch (e->type) { case E_UNARY_OP: e1 = e->value.unary_opval.exp; if (e1->type != E_CONSTANT) break; c1 = e1->value.constval; if (c1->type != C_NUMBER) break; switch (e->value.unary_opval.op) { case NEG_OP: c1->value.numval = -c1->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; case NOT_OP: c1->value.numval = !c1->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; case BITNOT_OP: c1->value.numval = ~c1->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; case PRE_INC_OP: c1->value.numval = ++c1->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; case PRE_DEC_OP: c1->value.numval = --c1->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; } break; case E_BINARY_OP: e1 = e->value.binary_opval.left_exp; e2 = e->value.binary_opval.right_exp; if (e1->type != E_CONSTANT || e2->type != E_CONSTANT) break; c1 = e1->value.constval; c2 = e2->value.constval; if (c1->type != C_NUMBER || c2->type != C_NUMBER) break; switch (e->value.binary_opval.op) { case PLUS_OP: c1->value.numval = c1->value.numval + c2->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; case MINUS_OP: c1->value.numval = c1->value.numval - c2->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; case AND_OP: c1->value.numval = c1->value.numval && c2->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; case OR_OP: c1->value.numval = c1->value.numval || c2->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; case MULT_OP: c1->value.numval = c1->value.numval * c2->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; case DIV_OP: if (c2->value.numval == 0) { action_error("Division by zero"); break; } c1->value.numval = c1->value.numval / c2->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; case MOD_OP: if (c2->value.numval == 0) { action_error("Division by zero"); break; } c1->value.numval = c1->value.numval % c2->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; case BITAND_OP: c1->value.numval = c1->value.numval & c2->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; case BITOR_OP: c1->value.numval = c1->value.numval | c2->value.numval; e->type = E_CONSTANT; e->value.constval = c1; break; } break; } }
id_type make_constant_id(id_type id, expr_type expr) { int numeric_val; /* Right hand side must be a number or a negative number */ switch (expr->type) { case E_CONSTANT: { const_type c = (const_type) expr->value.constval; if (c->type == C_NUMBER) numeric_val = c->value.numval; else action_error("Right hand side must be a numeric constant"); break; } case E_UNARY_OP: { const_type c; expr_type sub_expr = expr->value.unary_opval.exp; int op = expr->value.unary_opval.op; if (op != NEG_OP || sub_expr->type != E_CONSTANT) { action_error("Right hand side must be a numeric constant"); break; } c = (const_type) sub_expr->value.constval; if (c->type == C_NUMBER) numeric_val = - c->value.numval; else action_error("Right hand side must be a numeric constant"); break; } default: action_error("Right hand side must be a numeric constant"); } lookup_id(id); /* Left hand side cannot have appeared before */ switch (id->type) { case I_UNDEFINED: id->ownernum = st.curclass; /* Store value in source field. This is kind of a hack, but now we can insert just the id in st.constants, making it easy to find later. */ id->source = numeric_val; add_identifier(id, I_CONSTANT); break; default: action_error("Duplicate identifier %s", id->name); break; } /* Add to list of constants in this class */ st.constants = list_add_item(st.constants, id); return id; }