static struct block *primary_expression(struct block *block) { const struct symbol *sym; struct token tok; switch ((tok = next()).token) { case IDENTIFIER: sym = sym_lookup(&ns_ident, tok.strval); if (!sym) { error("Undefined symbol '%s'.", tok.strval); exit(1); } /* Special handling for builtin pseudo functions. These are expected to * behave as macros, thus should be no problem parsing as function call * in primary expression. Constructs like (va_arg)(args, int) will not * work with this scheme. */ if (!strcmp("__builtin_va_start", sym->name)) { block = parse__builtin_va_start(block); } else if (!strcmp("__builtin_va_arg", sym->name)) { block = parse__builtin_va_arg(block); } else { block->expr = var_direct(sym); } break; case INTEGER_CONSTANT: block->expr = var_int(tok.intval); break; case '(': block = expression(block); consume(')'); break; case STRING: sym = sym_add(&ns_ident, ".LC", type_init(T_ARRAY, &basic_type__char, strlen(tok.strval) + 1), SYM_STRING_VALUE, LINK_INTERN); /* Store string value directly on symbol, memory ownership is in string * table from previously called str_register. The symbol now exists as * if it was declared static char .LC[] = "...". */ ((struct symbol *) sym)->string_value = tok.strval; /* Result is an IMMEDIATE of type [] char, with a reference to the new * symbol containing the string literal. Will decay into char * on * evaluation. */ block->expr = var_direct(sym); assert(block->expr.kind == IMMEDIATE); break; default: error("Unexpected '%s', not a valid primary expression.", tok.strval); exit(1); } return block; }
static struct block *equality_expression(struct block *block) { struct var value; block = relational_expression(block); while (1) { value = block->expr; if (peek().token == EQ) { consume(EQ); block = relational_expression(block); block->expr = eval_expr(block, IR_OP_EQ, value, block->expr); } else if (peek().token == NEQ) { consume(NEQ); block = relational_expression(block); block->expr = eval_expr(block, IR_OP_EQ, var_int(0), eval_expr(block, IR_OP_EQ, value, block->expr)); } else break; } return block; }
static struct block *unary_expression(struct block *block) { struct var value; switch (peek().token) { case '&': consume('&'); block = cast_expression(block); block->expr = eval_addr(block, block->expr); break; case '*': consume('*'); block = cast_expression(block); block->expr = eval_deref(block, block->expr); break; case '!': consume('!'); block = cast_expression(block); block->expr = eval_expr(block, IR_OP_EQ, var_int(0), block->expr); break; case '~': consume('~'); block = cast_expression(block); block->expr = eval_expr(block, IR_NOT, block->expr); break; case '+': consume('+'); block = cast_expression(block); block->expr.lvalue = 0; break; case '-': consume('-'); block = cast_expression(block); block->expr = eval_expr(block, IR_OP_SUB, var_int(0), block->expr); break; case SIZEOF: { struct typetree *type; struct block *head = cfg_block_init(), *tail; consume(SIZEOF); if (peek().token == '(') { switch (peekn(2).token) { case FIRST(type_name): consume('('); type = declaration_specifiers(NULL); if (peek().token != ')') { type = declarator(type, NULL); } consume(')'); break; default: tail = unary_expression(head); type = (struct typetree *) tail->expr.type; break; } } else { tail = unary_expression(head); type = (struct typetree *) tail->expr.type; } if (is_function(type)) { error("Cannot apply 'sizeof' to function type."); } if (!size_of(type)) { error("Cannot apply 'sizeof' to incomplete type."); } block->expr = var_int(size_of(type)); break; } case INCREMENT: consume(INCREMENT); block = unary_expression(block); value = block->expr; block->expr = eval_expr(block, IR_OP_ADD, value, var_int(1)); block->expr = eval_assign(block, value, block->expr); break; case DECREMENT: consume(DECREMENT); block = unary_expression(block); value = block->expr; block->expr = eval_expr(block, IR_OP_SUB, value, var_int(1)); block->expr = eval_assign(block, value, block->expr); break; default: block = postfix_expression(block); break; } return block; }
static struct block *postfix_expression(struct block *block) { struct var root; block = primary_expression(block); root = block->expr; while (1) { const struct member *field; const struct typetree *type; struct var expr, copy, *arg; struct token tok; int i, j; switch ((tok = peek()).token) { case '[': do { /* Evaluate a[b] = *(a + b). The semantics of pointer arithmetic * takes care of multiplying b with the correct width. */ consume('['); block = expression(block); root = eval_expr(block, IR_OP_ADD, root, block->expr); root = eval_deref(block, root); consume(']'); } while (peek().token == '['); break; case '(': type = root.type; if (is_pointer(root.type) && is_function(root.type->next)) type = type_deref(root.type); else if (!is_function(root.type)) { error("Expression must have type pointer to function, was %t.", root.type); exit(1); } consume('('); arg = calloc(nmembers(type), sizeof(*arg)); for (i = 0; i < nmembers(type); ++i) { if (peek().token == ')') { error("Too few arguments, expected %d but got %d.", nmembers(type), i); exit(1); } block = assignment_expression(block); arg[i] = block->expr; /* todo: type check here. */ if (i < nmembers(type) - 1) { consume(','); } } while (is_vararg(type) && peek().token != ')') { consume(','); arg = realloc(arg, (i + 1) * sizeof(*arg)); block = assignment_expression(block); arg[i] = block->expr; i++; } consume(')'); for (j = 0; j < i; ++j) param(block, arg[j]); free(arg); root = eval_call(block, root); break; case '.': consume('.'); tok = consume(IDENTIFIER); field = find_type_member(root.type, tok.strval); if (!field) { error("Invalid field access, no member named '%s'.", tok.strval); exit(1); } root.type = field->type; root.offset += field->offset; break; case ARROW: consume(ARROW); tok = consume(IDENTIFIER); if (is_pointer(root.type) && is_struct_or_union(root.type->next)) { field = find_type_member(type_deref(root.type), tok.strval); if (!field) { error("Invalid field access, no member named '%s'.", tok.strval); exit(1); } /* Make it look like a pointer to the field type, then perform * normal dereferencing. */ root.type = type_init(T_POINTER, field->type); root = eval_deref(block, root); root.offset = field->offset; } else { error("Invalid field access."); exit(1); } break; case INCREMENT: consume(INCREMENT); copy = create_var(root.type); eval_assign(block, copy, root); expr = eval_expr(block, IR_OP_ADD, root, var_int(1)); eval_assign(block, root, expr); root = copy; break; case DECREMENT: consume(DECREMENT); copy = create_var(root.type); eval_assign(block, copy, root); expr = eval_expr(block, IR_OP_SUB, root, var_int(1)); eval_assign(block, root, expr); root = copy; break; default: block->expr = root; return block; } } }
//--------------------------------------------------------------------------- void Var::fromString( const string &value ) { if ( type == Var_Float ) var_float() = ofToFloat( value ); if ( type == Var_Int ) var_int() = ofToInt( value ); if ( type == Var_String ) var_string() = value; }
//--------------------------------------------------------------------------- void Var::loadIni( ParamMap &ini ) { if ( type == Var_Float ) { var_float() = ini.getFloat(name, var_float() ); } if ( type == Var_Int ) { var_int() = ini.getInt(name, var_int() ); } if ( type == Var_String ) { var_string() = ini.getString(name, var_string() ); } }
//--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- void Var::saveIni( ParamMap &ini ) { if ( type == Var_Float ) { ini.setFloat(name, var_float() ); } if ( type == Var_Int ) { ini.setInt(name, var_int() ); } if ( type == Var_String ) { ini.setString(name, var_string() ); } }
//~~ var_str(const Payload& data, unsigned int& index) [var_str] ~~ unsigned int len = var_int(data,index).getValue(); if (index+len > data.size()) throw Malformated(); std::string::operator=(std::string((const char*)&(*data)[index],len)); index += len;