/* <expression> ::= <unary operator-name> <expression> ::= <binary operator-name> <expression> <expression> ::= <trinary operator-name> <expression> <expression> <expression> ::= st <type> ::= <template-param> ::= sr <type> <unqualified-name> # dependent name ::= sr <type> <unqualified-name> <template-args> # dependent template-id ::= <expr-primary> */ static int parseExpression(LargeStaticString &src, LargeStaticString &dest, demangle_t &data) { START("Expression"); if (src[0] == 'T') { if (parseTemplateParam(src, dest, data) == FAIL) END_FAIL("Expression"); else END_SUCCESS("Expression"); } else if (src[0] == 'L') { if (parseExprPrimary(src, dest, data) == FAIL) END_FAIL("Expression"); else END_SUCCESS("Expression"); } LargeStaticString op = src.left(2); src.stripFirst(2); #define UNARY_OP(prefix) { \ dest += prefix; \ if (parseExpression(src, dest, data) == FAIL) \ END_FAIL("Expression"); \ else \ END_SUCCESS("Expression"); \ } #define BINARY_OP(infix) { \ dest += "("; \ if (parseExpression(src, dest, data) == FAIL) \ END_FAIL("Expression"); \ dest += infix; \ if (parseExpression(src, dest, data) == FAIL) \ END_FAIL("Expression"); \ else \ { \ dest += ")"; \ END_SUCCESS("Expression"); \ } \ } if (op == "ps") UNARY_OP("+") else if (op == "ng") UNARY_OP("-") else if (op == "ad") UNARY_OP("&") else if (op == "de") UNARY_OP("*") else if (op == "co") UNARY_OP("~") else if (op == "nt") UNARY_OP("!") else if (op == "pl") BINARY_OP("+") else if (op == "mi") BINARY_OP("-") else if (op == "ml") BINARY_OP("*") else if (op == "dv") BINARY_OP("/") else if (op == "rm") BINARY_OP("%") else if (op == "an") BINARY_OP("&") else if (op == "or") BINARY_OP("|") else if (op == "eo") BINARY_OP("^") else if (op == "ls") BINARY_OP("<<") else if (op == "rs") BINARY_OP(">>") else if (op == "st") { dest += "sizeof ("; if (parseType(src, dest, data) == FAIL) END_FAIL("Expression"); dest += ")"; END_SUCCESS("Expression"); } END_FAIL("Expression"); }
/* return 0 on failure, 1 on success */ static int reduce_op() { long op_token = stack[sp - 1].value; assert(sp > 0); assert(stack[sp - 1].op == EXPR_OP); /* do some basic checking first: */ if (stack[sp].op != EXPR_VALUE) { errmsg = "Right-hand side is not value"; return 0; } if (UNARY_OP(op_token)) { if (stack[sp].svalue) { errmsg = "Syntax error: attempt to apply unary operator to string"; return 0; } } else { /* binary operator: */ if (sp == 1) { /* top of stack: don't attempt to use sp-2! */ errmsg = "Missing left-hand side for binary operator"; return 0; } if (stack[sp].op != EXPR_VALUE) { errmsg = "Left-hand side of binary operator is not a value"; return 0; } if ((!stack[sp - 2].svalue) != (!stack[sp].svalue)) { errmsg = "Can't mix strings and integers in expression"; return 0; } } if (stack[sp].svalue) { /* A binary string expression */ switch (stack[sp - 1].value) { case SWIG_TOKEN_EQUALTO: stack[sp - 2].value = (Strcmp(stack[sp - 2].svalue, stack[sp].svalue) == 0); Delete(stack[sp - 2].svalue); Delete(stack[sp].svalue); sp -= 2; break; case SWIG_TOKEN_NOTEQUAL: stack[sp - 2].value = (Strcmp(stack[sp - 2].svalue, stack[sp].svalue) != 0); Delete(stack[sp - 2].svalue); Delete(stack[sp].svalue); sp -= 2; break; default: errmsg = "Syntax error: bad binary operator for strings"; return 0; break; } } else { switch (op_token) { case SWIG_TOKEN_STAR: stack[sp - 2].value = stack[sp - 2].value * stack[sp].value; sp -= 2; break; case SWIG_TOKEN_EQUALTO: stack[sp - 2].value = stack[sp - 2].value == stack[sp].value; sp -= 2; break; case SWIG_TOKEN_NOTEQUAL: stack[sp - 2].value = stack[sp - 2].value != stack[sp].value; sp -= 2; break; case SWIG_TOKEN_PLUS: stack[sp - 2].value = stack[sp - 2].value + stack[sp].value; sp -= 2; break; case SWIG_TOKEN_MINUS: stack[sp - 2].value = stack[sp - 2].value - stack[sp].value; sp -= 2; break; case SWIG_TOKEN_AND: stack[sp - 2].value = stack[sp - 2].value & stack[sp].value; sp -= 2; break; case SWIG_TOKEN_LAND: stack[sp - 2].value = stack[sp - 2].value && stack[sp].value; sp -= 2; break; case SWIG_TOKEN_OR: stack[sp - 2].value = stack[sp - 2].value | stack[sp].value; sp -= 2; break; case SWIG_TOKEN_LOR: stack[sp - 2].value = stack[sp - 2].value || stack[sp].value; sp -= 2; break; case SWIG_TOKEN_XOR: stack[sp - 2].value = stack[sp - 2].value ^ stack[sp].value; sp -= 2; break; case SWIG_TOKEN_LESSTHAN: stack[sp - 2].value = stack[sp - 2].value < stack[sp].value; sp -= 2; break; case SWIG_TOKEN_GREATERTHAN: stack[sp - 2].value = stack[sp - 2].value > stack[sp].value; sp -= 2; break; case SWIG_TOKEN_LTEQUAL: stack[sp - 2].value = stack[sp - 2].value <= stack[sp].value; sp -= 2; break; case SWIG_TOKEN_GTEQUAL: stack[sp - 2].value = stack[sp - 2].value >= stack[sp].value; sp -= 2; break; case SWIG_TOKEN_NOT: stack[sp - 1].value = ~stack[sp].value; sp--; break; case SWIG_TOKEN_LNOT: stack[sp - 1].value = !stack[sp].value; sp--; break; case EXPR_UMINUS: stack[sp - 1].value = -stack[sp].value; sp--; break; case SWIG_TOKEN_SLASH: stack[sp - 2].value = stack[sp - 2].value / stack[sp].value; sp -= 2; break; case SWIG_TOKEN_PERCENT: stack[sp - 2].value = stack[sp - 2].value % stack[sp].value; sp -= 2; break; case SWIG_TOKEN_LSHIFT: stack[sp - 2].value = stack[sp - 2].value << stack[sp].value; sp -= 2; break; case SWIG_TOKEN_RSHIFT: stack[sp - 2].value = stack[sp - 2].value >> stack[sp].value; sp -= 2; break; default: errmsg = "Syntax error: bad operator"; return 0; break; } } stack[sp].op = EXPR_VALUE; stack[sp].svalue = 0; /* ensure it's not a string! */ return 1; }
// 'Main' function for parse string static struct calc_essence* parse_data_parse(struct parse_data* data, int priority) { struct calc_essence* result = NULL; // Operand switch(parse_data_next_token(data)) { case token_type_error: break;//error was already been traced in parse_data_next_token() case token_type_eof: print_error0("End of file while operand expected"); break; case token_type_value: case token_type_constant: result = calc_essence_val_create(data->current_token_value); if(result) parse_data_next_token(data);// advance to the next token break; case token_type_variable: result = calc_essence_var_create(data->current_token_index); if(result) parse_data_next_token(data);// advance to the next token break; case token_type_weak_variable: result = calc_essence_weak_var_create(data->current_token_index); if(result) parse_data_next_token(data);// advance to the next token break; case token_type_open_parenthesis: result = parse_data_parse(data, priority_min); if(!result) break; if(data->current_token_type != token_type_close_parenthesis) { print_error("Expected close parenthesis (')'), but token of type %d found.", (int)data->current_token_type); // rollback result calc_essence_free(result); result = NULL; break; } parse_data_next_token(data);// advance to the next token break; //unary operations without left operand #define UNARY_OP(essence_type_pure, priority_pure) {\ struct calc_essence* op = parse_data_parse(data, priority_##priority_pure);\ if(op == NULL) break;\ result = calc_essence_1op_create(calc_essence_type_##essence_type_pure, op);\ if(result == NULL) {calc_essence_free(op);}\ } case token_type_minus: UNARY_OP(unary_minus, unary_minus); break; case token_type_plus: UNARY_OP(unary_plus, unary_plus); break; case token_type_logical_not: UNARY_OP(logical_not, logical_not); break; case token_type_binary_not: UNARY_OP(binary_not, binary_not); break; #undef UNARY_OP default: print_error("Expected operand, but token of type %d found.", (int)data->current_token_type); } if(result == NULL) return NULL; //Determine operation and update operand in cycle, until error, delemiter or operation with lower priority is encountered while(1) { switch(data->current_token_type) { case token_type_error: calc_essence_free(result); return NULL;// error was already been traced in parse_data_next_token() // delimiters case token_type_eof: case token_type_close_parenthesis: case token_type_cond_second: return result; // operations with two operands #define TWO_OPERANDS_ESSENCE(essence_type_pure, left_priority_pure, right_priority_pure) \ if(priority > priority_##left_priority_pure) return result;\ {\ struct calc_essence* op1, *op2;\ debug("Evaluate second operand for essence of type %d...", (int)calc_essence_type_##essence_type_pure);\ op2 = parse_data_parse(data, priority_##right_priority_pure);\ if(op2 == NULL) {calc_essence_free(result); return NULL;}\ op1 = result;\ debug0("Create essence.");\ result = calc_essence_2op_create(calc_essence_type_##essence_type_pure, op1, op2);\ if(result == NULL) {calc_essence_free(op1); calc_essence_free(op2); return NULL;}\ } case token_type_multiply: TWO_OPERANDS_ESSENCE(multiply, multiply_left, multiply_right); break; case token_type_divide: TWO_OPERANDS_ESSENCE(divide, divide_left, divide_right); break; case token_type_rest: TWO_OPERANDS_ESSENCE(rest, rest_left, rest_right); break; case token_type_plus: TWO_OPERANDS_ESSENCE(plus, plus_left, plus_right); break; case token_type_minus: TWO_OPERANDS_ESSENCE(minus, minus_left, minus_right); break; case token_type_left_shift: TWO_OPERANDS_ESSENCE(left_shift, left_shift_left, left_shift_right); break; case token_type_right_shift: TWO_OPERANDS_ESSENCE(right_shift, right_shift_left, right_shift_right); break; case token_type_less: TWO_OPERANDS_ESSENCE(less, less_left, less_right); break; case token_type_greater: TWO_OPERANDS_ESSENCE(greater, greater_left, greater_right); break; case token_type_less_equal: TWO_OPERANDS_ESSENCE(less_equal, less_equal_left, less_equal_right); break; case token_type_greater_equal: TWO_OPERANDS_ESSENCE(greater_equal, greater_equal_left, greater_equal_right); break; case token_type_equal: TWO_OPERANDS_ESSENCE(equal, equal_left, equal_right); break; case token_type_inequal: TWO_OPERANDS_ESSENCE(inequal, inequal_left, inequal_right); break; case token_type_binary_or: TWO_OPERANDS_ESSENCE(binary_or, binary_or_left, binary_or_right); break; case token_type_binary_xor: TWO_OPERANDS_ESSENCE(binary_xor, binary_xor_left, binary_xor_right); break; case token_type_binary_and: TWO_OPERANDS_ESSENCE(binary_and, binary_and_left, binary_and_right); break; case token_type_logical_or: TWO_OPERANDS_ESSENCE(logical_or, logical_or_left, logical_or_right); break; case token_type_logical_and: TWO_OPERANDS_ESSENCE(logical_and, logical_and_left, logical_and_right); break; #undef TWO_OPERANDS_ESSENCE //Only one three operand essence, so without macro case token_type_cond_first: if(priority > priority_cond_left) return result; { struct calc_essence *op1, *op2, *op3; debug0("Evaluate second operand for 'a ? b : c' operation..."); \ op2 = parse_data_parse(data, priority_min); if(op2 == NULL) { calc_essence_free(result); return NULL; } if(data->current_token_type != token_type_cond_second) { print_error("Expected ':', but token of type %d encountered.", (int)data->current_token_type); } debug0("Evaluate third operand for 'a ? b : c' operation..."); \ op3 = parse_data_parse(data, priority_cond_right); if(op3 == NULL) { calc_essence_free(op2); calc_essence_free(result); return NULL; } op1 = result; debug0("Create essence."); result = calc_essence_3op_create(calc_essence_type_cond, op1, op2, op3); if(result == NULL) { calc_essence_free(op1); calc_essence_free(op2); calc_essence_free(op3); return NULL; } } break; //... default: print_error("Expected operation, but token of type %d found.", (int)data->current_token_type); calc_essence_free(result); return NULL; } } return result; }