X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=3c5d237e17500ed86acd2e66ad80f937e55e552b;hp=805c28cf53536557f41ad780cfb987b439bbaa93;hb=4079835c7e75bb2b6a20ebb1f1e91e4c8c362c99;hpb=906f319673f6a2eddb62e59acc970b9497f3e96a diff --git a/parser.c b/parser.c index 805c28c..3c5d237 100644 --- a/parser.c +++ b/parser.c @@ -20,6 +20,9 @@ typedef struct { ast_value **imm_string; ast_value **imm_vector; + /* must be deleted first, they reference immediates and values */ + ast_value **accessors; + ast_value *imm_float_zero; ast_value *imm_vector_zero; @@ -48,6 +51,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield static ast_block* parse_block(parser_t *parser, bool warnreturn); static bool parse_block_into(parser_t *parser, ast_block *block, bool warnreturn); static ast_expression* parse_statement_or_block(parser_t *parser); +static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases); static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma); static ast_expression* parse_expression(parser_t *parser, bool stopatcomma); @@ -163,7 +167,8 @@ static ast_value* parser_const_float(parser_t *parser, double d) size_t i; ast_value *out; for (i = 0; i < vec_size(parser->imm_float); ++i) { - if (parser->imm_float[i]->constval.vfloat == d) + const double compare = parser->imm_float[i]->constval.vfloat; + if (memcmp((const void*)&compare, (const void *)&d, sizeof(double)) == 0) return parser->imm_float[i]; } out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_FLOAT); @@ -408,7 +413,7 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) ast_expression *exprs[3]; ast_block *blocks[3]; ast_value *asvalue[3]; - size_t i, assignop; + size_t i, assignop, addop; qcint generated_op = 0; char ty1[1024]; @@ -419,13 +424,13 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) return false; } - if (sy->ops[vec_size(sy->ops)-1].paren) { + if (vec_last(sy->ops).paren) { parseerror(parser, "unmatched parenthesis"); return false; } - op = &operators[sy->ops[vec_size(sy->ops)-1].etype - 1]; - ctx = sy->ops[vec_size(sy->ops)-1].ctx; + op = &operators[vec_last(sy->ops).etype - 1]; + ctx = vec_last(sy->ops).ctx; DEBUGSHUNTDO(con_out("apply %s\n", op->op)); @@ -761,6 +766,19 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); break; + case opid2('?',':'): + if (exprs[1]->expression.vtype != exprs[2]->expression.vtype) { + ast_type_to_string(exprs[1], ty1, sizeof(ty1)); + ast_type_to_string(exprs[2], ty2, sizeof(ty2)); + parseerror(parser, "iperands of ternary expression must have the same type, got %s and %s", ty1, ty2); + return false; + } + if (CanConstFold1(exprs[0])) + out = (ConstF(0) ? exprs[1] : exprs[2]); + else + out = (ast_expression*)ast_ternary_new(ctx, exprs[0], exprs[1], exprs[2]); + break; + case opid1('>'): generated_op += 1; /* INSTR_GT */ case opid1('<'): @@ -860,14 +878,59 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) } out = (ast_expression*)ast_store_new(ctx, assignop, exprs[0], exprs[1]); break; + case opid3('+','+','P'): + case opid3('-','-','P'): + /* prefix ++ */ + if (exprs[0]->expression.vtype != TYPE_FLOAT) { + ast_type_to_string(exprs[0], ty1, sizeof(ty1)); + parseerror(parser, "invalid type for prefix increment: %s", ty1); + return false; + } + if (op->id == opid3('+','+','P')) + addop = INSTR_ADD_F; + else + addop = INSTR_SUB_F; + if (ast_istype(exprs[0], ast_entfield)) { + out = (ast_expression*)ast_binstore_new(ctx, INSTR_STOREP_F, addop, + exprs[0], + (ast_expression*)parser_const_float(parser, 1)); + } else { + out = (ast_expression*)ast_binstore_new(ctx, INSTR_STORE_F, addop, + exprs[0], + (ast_expression*)parser_const_float(parser, 1)); + } + break; + case opid3('S','+','+'): + case opid3('S','-','-'): + /* prefix ++ */ + if (exprs[0]->expression.vtype != TYPE_FLOAT) { + ast_type_to_string(exprs[0], ty1, sizeof(ty1)); + parseerror(parser, "invalid type for prefix increment: %s", ty1); + return false; + } + if (op->id == opid3('+','+','P')) + addop = INSTR_ADD_F; + else + addop = INSTR_SUB_F; + if (ast_istype(exprs[0], ast_entfield)) { + out = (ast_expression*)ast_binstore_new(ctx, INSTR_STOREP_F, addop, + exprs[0], + (ast_expression*)parser_const_float(parser, 1)); + } else { + out = (ast_expression*)ast_binstore_new(ctx, INSTR_STORE_F, addop, + exprs[0], + (ast_expression*)parser_const_float(parser, 1)); + } + break; case opid2('+','='): case opid2('-','='): if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) { + ast_type_to_string(exprs[0], ty1, sizeof(ty1)); + ast_type_to_string(exprs[1], ty2, sizeof(ty2)); parseerror(parser, "invalid types used in expression: cannot add or subtract type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + ty1, ty2); return false; } if (ast_istype(exprs[0], ast_entfield)) @@ -1076,6 +1139,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma * end of a condition is an unmatched closing paren */ int parens = 0; + int ternaries = 0; sy.out = NULL; sy.ops = NULL; @@ -1237,13 +1301,12 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma else { /* classify the operator */ - /* TODO: suffix operators */ const oper_info *op; const oper_info *olast = NULL; size_t o; for (o = 0; o < operator_count; ++o) { if ((!(operators[o].flags & OP_PREFIX) == wantop) && - !(operators[o].flags & OP_SUFFIX) && /* remove this */ + /* !(operators[o].flags & OP_SUFFIX) && / * remove this */ !strcmp(parser_tokval(parser), operators[o].op)) { break; @@ -1263,6 +1326,12 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma break; } + /* a colon without a pervious question mark cannot be a ternary */ + if (!ternaries && op->id == opid2(':','?')) { + parser->tok = ':'; + break; + } + if (vec_size(sy.ops) && !vec_last(sy.ops).paren) olast = &operators[vec_last(sy.ops).etype-1]; @@ -1319,16 +1388,27 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma vec_push(sy.ops, syop(parser_ctx(parser), op)); vec_push(sy.ops, syparen(parser_ctx(parser), SY_PAREN_INDEX, 0)); wantop = false; + } else if (op->id == opid2('?',':')) { + wantop = false; + vec_push(sy.ops, syop(parser_ctx(parser), op)); + wantop = false; + --ternaries; + } else if (op->id == opid2(':','?')) { + /* we don't push this operator */ + wantop = false; + ++ternaries; } else { DEBUGSHUNTDO(con_out("push operator %s\n", op->op)); vec_push(sy.ops, syop(parser_ctx(parser), op)); - wantop = false; + wantop = !!(op->flags & OP_SUFFIX); } } if (!parser_next(parser)) { goto onerr; } - if (parser->tok == ';' || (!parens && parser->tok == ']')) { + if (parser->tok == ';' || + (!parens && parser->tok == ']')) + { break; } } @@ -1376,6 +1456,8 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out) lex_ctx ctx = parser_ctx(parser); + (void)block; /* not touching */ + /* skip the 'if', parse an optional 'not' and check for an opening paren */ if (!parser_next(parser)) { parseerror(parser, "expected condition or 'not'"); @@ -1450,6 +1532,8 @@ static bool parse_while(parser_t *parser, ast_block *block, ast_expression **out lex_ctx ctx = parser_ctx(parser); + (void)block; /* not touching */ + /* skip the 'while' and check for opening paren */ if (!parser_next(parser) || parser->tok != '(') { parseerror(parser, "expected 'while' condition in parenthesis"); @@ -1494,6 +1578,8 @@ static bool parse_dowhile(parser_t *parser, ast_block *block, ast_expression **o lex_ctx ctx = parser_ctx(parser); + (void)block; /* not touching */ + /* skip the 'do' and get the body */ if (!parser_next(parser)) { parseerror(parser, "expected loop body"); @@ -1675,7 +1761,214 @@ onerr: return false; } -static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out) +static bool parse_return(parser_t *parser, ast_block *block, ast_expression **out) +{ + ast_expression *exp = NULL; + ast_return *ret = NULL; + ast_value *expected = parser->function->vtype; + + (void)block; /* not touching */ + + if (!parser_next(parser)) { + parseerror(parser, "expected return expression"); + return false; + } + + if (parser->tok != ';') { + exp = parse_expression(parser, false); + if (!exp) + return false; + + if (exp->expression.vtype != expected->expression.next->expression.vtype) { + parseerror(parser, "return with invalid expression"); + } + + ret = ast_return_new(exp->expression.node.context, exp); + if (!ret) { + ast_delete(exp); + return false; + } + } else { + if (!parser_next(parser)) + parseerror(parser, "parse error"); + if (expected->expression.next->expression.vtype != TYPE_VOID) { + if (opts_standard != COMPILER_GMQCC) + (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value"); + else + parseerror(parser, "return without value"); + } + ret = ast_return_new(parser_ctx(parser), NULL); + } + *out = (ast_expression*)ret; + return true; +} + +static bool parse_break_continue(parser_t *parser, ast_block *block, ast_expression **out, bool is_continue) +{ + lex_ctx ctx = parser_ctx(parser); + + (void)block; /* not touching */ + + if (!parser_next(parser) || parser->tok != ';') { + parseerror(parser, "expected semicolon"); + return false; + } + + if (!parser_next(parser)) + parseerror(parser, "parse error"); + + *out = (ast_expression*)ast_breakcont_new(ctx, is_continue); + return true; +} + +static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **out) +{ + ast_expression *operand; + ast_value *opval; + ast_switch *switchnode; + ast_switch_case swcase; + + lex_ctx ctx = parser_ctx(parser); + + (void)block; /* not touching */ + + /* parse over the opening paren */ + if (!parser_next(parser) || parser->tok != '(') { + parseerror(parser, "expected switch operand in parenthesis"); + return false; + } + + /* parse into the expression */ + if (!parser_next(parser)) { + parseerror(parser, "expected switch operand"); + return false; + } + /* parse the operand */ + operand = parse_expression_leave(parser, false); + if (!operand) + return false; + + if (!OPTS_FLAG(RELAXED_SWITCH)) { + opval = (ast_value*)operand; + if (!ast_istype(operand, ast_value) || !opval->isconst) { + parseerror(parser, "case on non-constant values need to be explicitly enabled via -frelaxed-switch"); + ast_unref(operand); + return false; + } + } + + switchnode = ast_switch_new(ctx, operand); + + /* closing paren */ + if (parser->tok != ')') { + ast_delete(switchnode); + parseerror(parser, "expected closing paren after 'switch' operand"); + return false; + } + + /* parse over the opening paren */ + if (!parser_next(parser) || parser->tok != '{') { + ast_delete(switchnode); + parseerror(parser, "expected list of cases"); + return false; + } + + if (!parser_next(parser)) { + ast_delete(switchnode); + parseerror(parser, "expected 'case' or 'default'"); + return false; + } + + /* case list! */ + while (parser->tok != '}') { + ast_block *caseblock; + + if (parser->tok != TOKEN_KEYWORD) { + ast_delete(switchnode); + parseerror(parser, "expected 'case' or 'default'"); + return false; + } + if (!strcmp(parser_tokval(parser), "case")) { + if (!parser_next(parser)) { + ast_delete(switchnode); + parseerror(parser, "expected expression for case"); + return false; + } + swcase.value = parse_expression_leave(parser, false); + if (!swcase.value) { + ast_delete(switchnode); + parseerror(parser, "expected expression for case"); + return false; + } + } + else if (!strcmp(parser_tokval(parser), "default")) { + swcase.value = NULL; + if (!parser_next(parser)) { + ast_delete(switchnode); + parseerror(parser, "expected colon"); + return false; + } + } + + /* Now the colon and body */ + if (parser->tok != ':') { + if (swcase.value) ast_unref(swcase.value); + ast_delete(switchnode); + parseerror(parser, "expected colon"); + return false; + } + + if (!parser_next(parser)) { + if (swcase.value) ast_unref(swcase.value); + ast_delete(switchnode); + parseerror(parser, "expected statements or case"); + return false; + } + caseblock = ast_block_new(parser_ctx(parser)); + if (!caseblock) { + if (swcase.value) ast_unref(swcase.value); + ast_delete(switchnode); + return false; + } + swcase.code = (ast_expression*)caseblock; + vec_push(switchnode->cases, swcase); + while (true) { + ast_expression *expr; + if (parser->tok == '}') + break; + if (parser->tok == TOKEN_KEYWORD) { + if (!strcmp(parser_tokval(parser), "case") || + !strcmp(parser_tokval(parser), "default")) + { + break; + } + } + if (!parse_statement(parser, caseblock, &expr, true)) { + ast_delete(switchnode); + return false; + } + if (!expr) + continue; + vec_push(caseblock->exprs, expr); + } + } + + /* closing paren */ + if (parser->tok != '}') { + ast_delete(switchnode); + parseerror(parser, "expected closing paren of case list"); + return false; + } + if (!parser_next(parser)) { + ast_delete(switchnode); + parseerror(parser, "parse error after switch"); + return false; + } + *out = (ast_expression*)switchnode; + return true; +} + +static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases) { if (parser->tok == TOKEN_TYPENAME || parser->tok == '.') { @@ -1712,42 +2005,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * } else if (!strcmp(parser_tokval(parser), "return")) { - ast_expression *exp = NULL; - ast_return *ret = NULL; - ast_value *expected = parser->function->vtype; - - if (!parser_next(parser)) { - parseerror(parser, "expected return expression"); - return false; - } - - if (parser->tok != ';') { - exp = parse_expression(parser, false); - if (!exp) - return false; - - if (exp->expression.vtype != expected->expression.next->expression.vtype) { - parseerror(parser, "return with invalid expression"); - } - - ret = ast_return_new(exp->expression.node.context, exp); - if (!ret) { - ast_delete(exp); - return false; - } - } else { - if (!parser_next(parser)) - parseerror(parser, "parse error"); - if (expected->expression.next->expression.vtype != TYPE_VOID) { - if (opts_standard != COMPILER_GMQCC) - (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value"); - else - parseerror(parser, "return without value"); - } - ret = ast_return_new(parser_ctx(parser), NULL); - } - *out = (ast_expression*)ret; - return true; + return parse_return(parser, block, out); } else if (!strcmp(parser_tokval(parser), "if")) { @@ -1769,6 +2027,27 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * } return parse_for(parser, block, out); } + else if (!strcmp(parser_tokval(parser), "break")) + { + return parse_break_continue(parser, block, out, false); + } + else if (!strcmp(parser_tokval(parser), "continue")) + { + return parse_break_continue(parser, block, out, true); + } + else if (!strcmp(parser_tokval(parser), "switch")) + { + return parse_switch(parser, block, out); + } + else if (!strcmp(parser_tokval(parser), "case") || + !strcmp(parser_tokval(parser), "default")) + { + if (!allow_cases) { + parseerror(parser, "unexpected 'case' label"); + return false; + } + return true; + } parseerror(parser, "Unexpected keyword"); return false; } @@ -1804,9 +2083,11 @@ static bool GMQCC_WARN parser_pop_local(parser_t *parser) varentry_t *ve; ve = &vec_last(parser->locals); - if (ast_istype(ve->var, ast_value) && !(((ast_value*)(ve->var))->uses)) { - if (parsewarning(parser, WARN_UNUSED_VARIABLE, "unused variable: `%s`", ve->name)) - rv = false; + if (!parser->errors) { + if (ast_istype(ve->var, ast_value) && !(((ast_value*)(ve->var))->uses)) { + if (parsewarning(parser, WARN_UNUSED_VARIABLE, "unused variable: `%s`", ve->name)) + rv = false; + } } mem_d(ve->name); vec_pop(parser->locals); @@ -1832,7 +2113,7 @@ static bool parse_block_into(parser_t *parser, ast_block *block, bool warnreturn if (parser->tok == '}') break; - if (!parse_statement(parser, block, &expr)) { + if (!parse_statement(parser, block, &expr, false)) { /* parseerror(parser, "parse error"); */ block = NULL; goto cleanup; @@ -1884,13 +2165,13 @@ static ast_expression* parse_statement_or_block(parser_t *parser) ast_expression *expr = NULL; if (parser->tok == '{') return (ast_expression*)parse_block(parser, false); - if (!parse_statement(parser, NULL, &expr)) + if (!parse_statement(parser, NULL, &expr, false)) return NULL; return expr; } /* loop method */ -static bool create_vector_members(parser_t *parser, ast_value *var, varentry_t *ve) +static bool create_vector_members(ast_value *var, varentry_t *ve) { size_t i; size_t len = strlen(var->name); @@ -2152,7 +2433,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) continue; } - if (!create_vector_members(parser, param, ve)) { + if (!create_vector_members(param, ve)) { ast_block_delete(block); return false; } @@ -2249,10 +2530,11 @@ static ast_expression *array_setter_node(parser_t *parser, ast_value *array, ast lex_ctx ctx = ast_ctx(array); if (from+1 == afterend) { - // set this value + /* set this value */ ast_block *block; ast_return *ret; ast_array_index *subscript; + ast_store *st; int assignop = type_store_instr[value->expression.vtype]; if (value->expression.vtype == TYPE_FIELD && value->expression.next->expression.vtype == TYPE_VECTOR) @@ -2262,7 +2544,7 @@ static ast_expression *array_setter_node(parser_t *parser, ast_value *array, ast if (!subscript) return NULL; - ast_store *st = ast_store_new(ctx, assignop, (ast_expression*)subscript, (ast_expression*)value); + st = ast_store_new(ctx, assignop, (ast_expression*)subscript, (ast_expression*)value); if (!st) { ast_delete(subscript); return NULL; @@ -2307,11 +2589,12 @@ static ast_expression *array_field_setter_node( lex_ctx ctx = ast_ctx(array); if (from+1 == afterend) { - // set this value + /* set this value */ ast_block *block; ast_return *ret; ast_entfield *entfield; ast_array_index *subscript; + ast_store *st; int assignop = type_storep_instr[value->expression.vtype]; if (value->expression.vtype == TYPE_FIELD && value->expression.next->expression.vtype == TYPE_VECTOR) @@ -2330,7 +2613,7 @@ static ast_expression *array_field_setter_node( return NULL; } - ast_store *st = ast_store_new(ctx, assignop, (ast_expression*)entfield, (ast_expression*)value); + st = ast_store_new(ctx, assignop, (ast_expression*)entfield, (ast_expression*)value); if (!st) { ast_delete(entfield); return NULL; @@ -2396,6 +2679,7 @@ static bool parser_create_array_accessor(parser_t *parser, ast_value *array, con { ast_function *func = NULL; ast_value *fval = NULL; + ast_block *body = NULL; fval = ast_value_new(ast_ctx(array), funcname, TYPE_FUNCTION); if (!fval) { @@ -2410,15 +2694,25 @@ static bool parser_create_array_accessor(parser_t *parser, ast_value *array, con return false; } + body = ast_block_new(ast_ctx(array)); + if (!body) { + parseerror(parser, "failed to create block for array accessor"); + ast_delete(fval); + ast_delete(func); + return false; + } + + vec_push(func->blocks, body); *out = fval; + vec_push(parser->accessors, fval); + return true; } static bool parser_create_array_setter(parser_t *parser, ast_value *array, const char *funcname) { ast_expression *root = NULL; - ast_block *body = NULL; ast_value *index = NULL; ast_value *value = NULL; ast_function *func; @@ -2434,12 +2728,6 @@ static bool parser_create_array_setter(parser_t *parser, ast_value *array, const func = fval->constval.vfunc; fval->expression.next = (ast_expression*)ast_value_new(ast_ctx(array), "", TYPE_VOID); - body = ast_block_new(ast_ctx(array)); - if (!body) { - parseerror(parser, "failed to create block for array accessor"); - goto cleanup; - } - index = ast_value_new(ast_ctx(array), "index", TYPE_FLOAT); value = ast_value_copy((ast_value*)array->expression.next); @@ -2457,12 +2745,10 @@ static bool parser_create_array_setter(parser_t *parser, ast_value *array, const goto cleanup; } - vec_push(body->exprs, root); - vec_push(func->blocks, body); + vec_push(func->blocks[0]->exprs, root); array->setter = fval; return true; cleanup: - if (body) ast_delete(body); if (index) ast_delete(index); if (value) ast_delete(value); if (root) ast_delete(root); @@ -2474,7 +2760,6 @@ cleanup: static bool parser_create_array_field_setter(parser_t *parser, ast_value *array, const char *funcname) { ast_expression *root = NULL; - ast_block *body = NULL; ast_value *entity = NULL; ast_value *index = NULL; ast_value *value = NULL; @@ -2491,12 +2776,6 @@ static bool parser_create_array_field_setter(parser_t *parser, ast_value *array, func = fval->constval.vfunc; fval->expression.next = (ast_expression*)ast_value_new(ast_ctx(array), "", TYPE_VOID); - body = ast_block_new(ast_ctx(array)); - if (!body) { - parseerror(parser, "failed to create block for array accessor"); - goto cleanup; - } - entity = ast_value_new(ast_ctx(array), "entity", TYPE_ENTITY); index = ast_value_new(ast_ctx(array), "index", TYPE_FLOAT); value = ast_value_copy((ast_value*)array->expression.next); @@ -2515,12 +2794,10 @@ static bool parser_create_array_field_setter(parser_t *parser, ast_value *array, goto cleanup; } - vec_push(body->exprs, root); - vec_push(func->blocks, body); + vec_push(func->blocks[0]->exprs, root); array->setter = fval; return true; cleanup: - if (body) ast_delete(body); if (entity) ast_delete(entity); if (index) ast_delete(index); if (value) ast_delete(value); @@ -2533,7 +2810,6 @@ cleanup: static bool parser_create_array_getter(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname) { ast_expression *root = NULL; - ast_block *body = NULL; ast_value *index = NULL; ast_value *fval; ast_function *func; @@ -2551,12 +2827,6 @@ static bool parser_create_array_getter(parser_t *parser, ast_value *array, const func = fval->constval.vfunc; fval->expression.next = ast_type_copy(ast_ctx(array), elemtype); - body = ast_block_new(ast_ctx(array)); - if (!body) { - parseerror(parser, "failed to create block for array accessor"); - goto cleanup; - } - index = ast_value_new(ast_ctx(array), "index", TYPE_FLOAT); if (!index) { @@ -2571,12 +2841,10 @@ static bool parser_create_array_getter(parser_t *parser, ast_value *array, const goto cleanup; } - vec_push(body->exprs, root); - vec_push(func->blocks, body); + vec_push(func->blocks[0]->exprs, root); array->getter = fval; return true; cleanup: - if (body) ast_delete(body); if (index) ast_delete(index); if (root) ast_delete(root); ast_delete(func); @@ -2649,8 +2917,8 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) } /* sanity check */ - if (vec_size(params) > 8) - parseerror(parser, "more than 8 parameters are currently not supported"); + if (vec_size(params) > 8 && opts_standard == COMPILER_QCC) + (void)!parsewarning(parser, WARN_EXTENSIONS, "more than 8 parameters are not supported by this standard"); /* parse-out */ if (!parser_next(parser)) { @@ -3069,7 +3337,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield isvector = true; if (isvector) { - if (!create_vector_members(parser, var, ve)) { + if (!create_vector_members(var, ve)) { retval = false; goto cleanup; } @@ -3370,6 +3638,79 @@ static bool parser_global_statement(parser_t *parser) return true; } +static uint16_t progdefs_crc_sum(uint16_t old, const char *str) +{ + return util_crc16(old, str, strlen(str)); +} + +static void progdefs_crc_file(const char *str) +{ + /* write to progdefs.h here */ + (void)str; +} + +static uint16_t progdefs_crc_both(uint16_t old, const char *str) +{ + old = progdefs_crc_sum(old, str); + progdefs_crc_file(str); + return old; +} + +static void generate_checksum(parser_t *parser) +{ + uint16_t crc = 0xFFFF; + size_t i; + + crc = progdefs_crc_both(crc, "\n/* file generated by qcc, do not modify */\n\ntypedef struct\n{"); + crc = progdefs_crc_sum(crc, "\tint\tpad[28];\n"); + /* + progdefs_crc_file("\tint\tpad;\n"); + progdefs_crc_file("\tint\tofs_return[3];\n"); + progdefs_crc_file("\tint\tofs_parm0[3];\n"); + progdefs_crc_file("\tint\tofs_parm1[3];\n"); + progdefs_crc_file("\tint\tofs_parm2[3];\n"); + progdefs_crc_file("\tint\tofs_parm3[3];\n"); + progdefs_crc_file("\tint\tofs_parm4[3];\n"); + progdefs_crc_file("\tint\tofs_parm5[3];\n"); + progdefs_crc_file("\tint\tofs_parm6[3];\n"); + progdefs_crc_file("\tint\tofs_parm7[3];\n"); + */ + for (i = 0; i < parser->crc_globals; ++i) { + if (!ast_istype(parser->globals[i].var, ast_value)) + continue; + switch (parser->globals[i].var->expression.vtype) { + case TYPE_FLOAT: crc = progdefs_crc_both(crc, "\tfloat\t"); break; + case TYPE_VECTOR: crc = progdefs_crc_both(crc, "\tvec3_t\t"); break; + case TYPE_STRING: crc = progdefs_crc_both(crc, "\tstring_t\t"); break; + case TYPE_FUNCTION: crc = progdefs_crc_both(crc, "\tfunc_t\t"); break; + default: + crc = progdefs_crc_both(crc, "\tint\t"); + break; + } + crc = progdefs_crc_both(crc, parser->globals[i].name); + crc = progdefs_crc_both(crc, ";\n"); + } + crc = progdefs_crc_both(crc, "} globalvars_t;\n\ntypedef struct\n{\n"); + for (i = 0; i < parser->crc_fields; ++i) { + if (!ast_istype(parser->fields[i].var, ast_value)) + continue; + switch (parser->fields[i].var->expression.next->expression.vtype) { + case TYPE_FLOAT: crc = progdefs_crc_both(crc, "\tfloat\t"); break; + case TYPE_VECTOR: crc = progdefs_crc_both(crc, "\tvec3_t\t"); break; + case TYPE_STRING: crc = progdefs_crc_both(crc, "\tstring_t\t"); break; + case TYPE_FUNCTION: crc = progdefs_crc_both(crc, "\tfunc_t\t"); break; + default: + crc = progdefs_crc_both(crc, "\tint\t"); + break; + } + crc = progdefs_crc_both(crc, parser->fields[i].name); + crc = progdefs_crc_both(crc, ";\n"); + } + crc = progdefs_crc_both(crc, "} entvars_t;\n\n"); + + code_crc = crc; +} + static parser_t *parser; bool parser_init() @@ -3431,7 +3772,17 @@ bool parser_compile_file(const char *filename) { parser->lex = lex_open(filename); if (!parser->lex) { - con_out("failed to open file \"%s\"\n", filename); + con_err("failed to open file \"%s\"\n", filename); + return false; + } + return parser_compile(); +} + +bool parser_compile_string_len(const char *name, const char *str, size_t len) +{ + parser->lex = lex_open_string(str, len, name); + if (!parser->lex) { + con_err("failed to create lexer for string \"%s\"\n", name); return false; } return parser_compile(); @@ -3441,7 +3792,7 @@ bool parser_compile_string(const char *name, const char *str) { parser->lex = lex_open_string(str, strlen(str), name); if (!parser->lex) { - con_out("failed to create lexer for string \"%s\"\n", name); + con_err("failed to create lexer for string \"%s\"\n", name); return false; } return parser_compile(); @@ -3450,6 +3801,11 @@ bool parser_compile_string(const char *name, const char *str) void parser_cleanup() { size_t i; + for (i = 0; i < vec_size(parser->accessors); ++i) { + ast_delete(parser->accessors[i]->constval.vfunc); + parser->accessors[i]->constval.vfunc = NULL; + ast_delete(parser->accessors[i]); + } for (i = 0; i < vec_size(parser->functions); ++i) { ast_delete(parser->functions[i]); } @@ -3470,6 +3826,7 @@ void parser_cleanup() ast_delete(parser->globals[i].var); mem_d(parser->globals[i].name); } + vec_free(parser->accessors); vec_free(parser->functions); vec_free(parser->imm_vector); vec_free(parser->imm_string); @@ -3481,78 +3838,6 @@ void parser_cleanup() mem_d(parser); } -static uint16_t progdefs_crc_sum(uint16_t old, const char *str) -{ - return util_crc16(old, str, strlen(str)); -} - -static void progdefs_crc_file(const char *str) -{ - /* write to progdefs.h here */ -} - -static uint16_t progdefs_crc_both(uint16_t old, const char *str) -{ - old = progdefs_crc_sum(old, str); - progdefs_crc_file(str); - return old; -} - -static void generate_checksum(parser_t *parser) -{ - uint16_t crc = 0xFFFF; - size_t i; - - crc = progdefs_crc_both(crc, "\n/* file generated by qcc, do not modify */\n\ntypedef struct\n{"); - crc = progdefs_crc_sum(crc, "\tint\tpad[28];\n"); - /* - progdefs_crc_file("\tint\tpad;\n"); - progdefs_crc_file("\tint\tofs_return[3];\n"); - progdefs_crc_file("\tint\tofs_parm0[3];\n"); - progdefs_crc_file("\tint\tofs_parm1[3];\n"); - progdefs_crc_file("\tint\tofs_parm2[3];\n"); - progdefs_crc_file("\tint\tofs_parm3[3];\n"); - progdefs_crc_file("\tint\tofs_parm4[3];\n"); - progdefs_crc_file("\tint\tofs_parm5[3];\n"); - progdefs_crc_file("\tint\tofs_parm6[3];\n"); - progdefs_crc_file("\tint\tofs_parm7[3];\n"); - */ - for (i = 0; i < parser->crc_globals; ++i) { - if (!ast_istype(parser->globals[i].var, ast_value)) - continue; - switch (parser->globals[i].var->expression.vtype) { - case TYPE_FLOAT: crc = progdefs_crc_both(crc, "\tfloat\t"); break; - case TYPE_VECTOR: crc = progdefs_crc_both(crc, "\tvec3_t\t"); break; - case TYPE_STRING: crc = progdefs_crc_both(crc, "\tstring_t\t"); break; - case TYPE_FUNCTION: crc = progdefs_crc_both(crc, "\tfunc_t\t"); break; - default: - crc = progdefs_crc_both(crc, "\tint\t"); - break; - } - crc = progdefs_crc_both(crc, parser->globals[i].name); - crc = progdefs_crc_both(crc, ";\n"); - } - crc = progdefs_crc_both(crc, "} globalvars_t;\n\ntypedef struct\n{\n"); - for (i = 0; i < parser->crc_fields; ++i) { - if (!ast_istype(parser->fields[i].var, ast_value)) - continue; - switch (parser->fields[i].var->expression.next->expression.vtype) { - case TYPE_FLOAT: crc = progdefs_crc_both(crc, "\tfloat\t"); break; - case TYPE_VECTOR: crc = progdefs_crc_both(crc, "\tvec3_t\t"); break; - case TYPE_STRING: crc = progdefs_crc_both(crc, "\tstring_t\t"); break; - case TYPE_FUNCTION: crc = progdefs_crc_both(crc, "\tfunc_t\t"); break; - default: - crc = progdefs_crc_both(crc, "\tint\t"); - break; - } - crc = progdefs_crc_both(crc, parser->fields[i].name); - crc = progdefs_crc_both(crc, ";\n"); - } - crc = progdefs_crc_both(crc, "} entvars_t;\n\n"); - - code_crc = crc; -} - bool parser_finish(const char *output) { size_t i; @@ -3694,6 +3979,10 @@ bool parser_finish(const char *output) ir_builder_delete(ir); return false; } + } + if (opts_dump) + ir_builder_dump(ir, con_out); + for (i = 0; i < vec_size(parser->functions); ++i) { if (!ir_function_finalize(parser->functions[i]->ir_func)) { con_out("failed to finalize function %s\n", parser->functions[i]->name); ir_builder_delete(ir); @@ -3702,7 +3991,7 @@ bool parser_finish(const char *output) } if (retval) { - if (opts_dump) + if (opts_dumpfin) ir_builder_dump(ir, con_out); generate_checksum(parser);