}
/* returns true if it counts as an error */
-bool parsewarning(parser_t *parser, int warntype, const char *fmt, ...)
+bool GMQCC_WARN parsewarning(parser_t *parser, int warntype, const char *fmt, ...)
{
va_list ap;
int lvl = LVL_WARNING;
return true;
}
+static bool parser_parse_dowhile(parser_t *parser, ast_block *block, ast_expression **out)
+{
+ ast_loop *aloop;
+ ast_expression *cond, *ontrue;
+
+ lex_ctx ctx = parser_ctx(parser);
+
+ /* skip the 'do' and get the body */
+ if (!parser_next(parser) || parser->tok != '(') {
+ parseerror(parser, "expected loop body");
+ return false;
+ }
+ ontrue = parser_parse_statement_or_block(parser);
+ if (!ontrue)
+ return false;
+
+ /* expect the "while" */
+ if (parser->tok != TOKEN_KEYWORD ||
+ !strcmp(parser_tokval(parser), "while"))
+ {
+ parseerror(parser, "expected 'while' and condition");
+ ast_delete(ontrue);
+ return false;
+ }
+
+ /* skip the 'while' and check for opening paren */
+ if (!parser_next(parser) || parser->tok != '(') {
+ parseerror(parser, "expected 'while' condition in parenthesis");
+ ast_delete(ontrue);
+ return false;
+ }
+ /* parse into the expression */
+ if (!parser_next(parser)) {
+ parseerror(parser, "expected 'while' condition after opening paren");
+ ast_delete(ontrue);
+ return false;
+ }
+ /* parse the condition */
+ cond = parser_expression_leave(parser);
+ if (!cond)
+ return false;
+ /* closing paren */
+ if (parser->tok != ')') {
+ parseerror(parser, "expected closing paren after 'while' condition");
+ ast_delete(ontrue);
+ ast_delete(cond);
+ return false;
+ }
+ /* parse on */
+ if (!parser_next(parser)) {
+ parseerror(parser, "parse error");
+ ast_delete(ontrue);
+ ast_delete(cond);
+ return false;
+ }
+
+ aloop = ast_loop_new(ctx, NULL, NULL, cond, NULL, ontrue);
+ *out = (ast_expression*)aloop;
+ return true;
+}
+
static bool parser_parse_for(parser_t *parser, ast_block *block, ast_expression **out)
{
ast_loop *aloop;
/* parse the condition */
if (parser->tok != ';') {
- printf("going cond!\n");
cond = parser_expression_leave(parser);
if (!cond)
goto onerr;
- printf("going cond!\n");
}
/* move on to incrementor */
parseerror(parser, "cannot declare a variable from here");
return false;
}
+ if (opts_standard == COMPILER_QCC) {
+ if (parsewarning(parser, WARN_EXTENSIONS, "missing 'local' keyword when declaring a local variable"))
+ return false;
+ }
if (!parser_variable(parser, block))
return false;
*out = NULL;
}
else if (parser->tok == TOKEN_KEYWORD)
{
- if (!strcmp(parser_tokval(parser), "return"))
+ if (!strcmp(parser_tokval(parser), "local"))
+ {
+ if (!block) {
+ parseerror(parser, "cannot declare a local variable here");
+ return false;
+ }
+ if (!parser_next(parser)) {
+ parseerror(parser, "expected variable declaration");
+ return false;
+ }
+ if (!parser_variable(parser, block))
+ return false;
+ *out = NULL;
+ return true;
+ }
+ else if (!strcmp(parser_tokval(parser), "return"))
{
ast_expression *exp = NULL;
ast_return *ret = NULL;
{
return parser_parse_while(parser, block, out);
}
+ else if (!strcmp(parser_tokval(parser), "do"))
+ {
+ return parser_parse_dowhile(parser, block, out);
+ }
else if (!strcmp(parser_tokval(parser), "for"))
{
return parser_parse_for(parser, block, out);
return false;
}
- isfunc = false;
- func = NULL;
+ olddecl = NULL;
+ isfunc = false;
+ func = NULL;
ctx = parser_ctx(parser);
var = parser_parse_type(parser, basetype, &isfunc);
return false;
}
- if (!localblock && (olddecl = parser_find_global(parser, parser_tokval(parser)))) {
- ast_value_delete(var);
- parseerror(parser, "global %s already declared here: %s:%i\n",
- parser_tokval(parser), ast_ctx(olddecl).file, (int)ast_ctx(olddecl).line);
- return false;
- }
+ if (!isfunc) {
+ if (!localblock && (olddecl = parser_find_global(parser, parser_tokval(parser)))) {
+ ast_value_delete(var);
+ parseerror(parser, "global %s already declared here: %s:%i\n",
+ parser_tokval(parser), ast_ctx(olddecl).file, (int)ast_ctx(olddecl).line);
+ return false;
+ }
- if (localblock && parser_find_local(parser, parser_tokval(parser), parser->blocklocal)) {
- ast_value_delete(var);
- parseerror(parser, "local %s already declared here: %s:%i\n",
- parser_tokval(parser), ast_ctx(olddecl).file, (int)ast_ctx(olddecl).line);
- return false;
+ if (localblock && parser_find_local(parser, parser_tokval(parser), parser->blocklocal)) {
+ ast_value_delete(var);
+ parseerror(parser, "local %s already declared here: %s:%i\n",
+ parser_tokval(parser), ast_ctx(olddecl).file, (int)ast_ctx(olddecl).line);
+ return false;
+ }
}
if (!ast_value_set_name(var, parser_tokval(parser))) {
if (isfunc) {
/* a function was defined */
ast_value *fval;
+ ast_value *proto = NULL;
+
+ if (!localblock)
+ olddecl = parser_find_global(parser, parser_tokval(parser));
+ else
+ olddecl = parser_find_local(parser, parser_tokval(parser), parser->blocklocal);
+
+ if (olddecl) {
+ /* we had a prototype */
+ if (!ast_istype(olddecl, ast_value)) {
+ /* theoretically not possible you think?
+ * well:
+ * vector v;
+ * void() v_x = {}
+ * got it?
+ */
+ parseerror(parser, "cannot declare a function with the same name as a vector's member: %s",
+ parser_tokval(parser));
+ ast_value_delete(var);
+ return false;
+ }
+
+ proto = (ast_value*)olddecl;
+ }
/* turn var into a value of TYPE_FUNCTION, with the old var
* as return type
fval->expression.next = (ast_expression*)var;
MEM_VECTOR_MOVE(&var->expression, params, &fval->expression, params);
- if (!parser_t_functions_add(parser, func)) {
- ast_value_delete(var);
- if (fval) ast_value_delete(fval);
- if (func) ast_function_delete(func);
- return false;
+ /* we compare the type late here, but it's easier than
+ * messing with the parameter-vector etc. earlier
+ */
+ if (proto) {
+ if (!ast_compare_type((ast_expression*)proto, (ast_expression*)fval)) {
+ parseerror(parser, "prototype declared at %s:%i had a different type",
+ ast_ctx(proto).file, ast_ctx(proto).line);
+ ast_function_delete(func);
+ ast_value_delete(fval);
+ return false;
+ }
+ ast_function_delete(func);
+ ast_value_delete(fval);
+ var = proto;
+ func = var->constval.vfunc;
+ }
+ else
+ {
+ if (!parser_t_functions_add(parser, func)) {
+ ast_function_delete(func);
+ ast_value_delete(fval);
+ return false;
+ }
}
var = fval;
ast_block_delete(block);
return false;
}
+
+ if (parser->tok == ';')
+ return parser_next(parser) || parser->tok == TOKEN_EOF;
+ else if (opts_standard == COMPILER_QCC)
+ parseerror(parser, "missing semicolon after function body (mandatory with -std=qcc)");
return true;
} else {
parseerror(parser, "TODO, const assignment");
}
}
- ir_builder_dump(ir, printf);
+ if (opts_dump)
+ ir_builder_dump(ir, printf);
if (!ir_builder_generate(ir, output)) {
printf("*** failed to generate output file\n");