* anything else: type error
*/
qcint memberof;
+
+ /* Keep track of our ternary vs parenthesis nesting state.
+ * If we reach a 'comma' operator in a ternary without a paren,
+ * we shall trigger -Wternary-precedence.
+ */
+ enum { POT_PAREN, POT_TERNARY1, POT_TERNARY2 } *pot;
+
+ /* pragma flags */
+ bool noref;
} parser_t;
static void parser_enterblock(parser_t *parser);
static bool parser_leaveblock(parser_t *parser);
static void parser_addlocal(parser_t *parser, const char *name, ast_expression *e);
static bool parse_typedef(parser_t *parser);
-static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef);
+static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref);
static ast_block* parse_block(parser_t *parser);
static bool parse_block_into(parser_t *parser, ast_block *block);
-static ast_expression* parse_statement_or_block(parser_t *parser);
+static bool parse_statement_or_block(parser_t *parser, ast_expression **out);
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);
}
va_start(ap, fmt);
- con_vprintmsg(lvl, parser->lex->tok.ctx.file, parser->lex->tok.ctx.line, "warning", fmt, ap);
+ con_vprintmsg(lvl, parser->lex->tok.ctx.file, parser->lex->tok.ctx.line, (opts_werror ? "error" : "warning"), fmt, ap);
va_end(ap);
return opts_werror;
lvl = LVL_ERROR;
va_start(ap, fmt);
- con_vprintmsg(lvl, ctx.file, ctx.line, "warning", fmt, ap);
+ con_vprintmsg(lvl, ctx.file, ctx.line, (opts_werror ? "error" : "warning"), fmt, ap);
va_end(ap);
return opts_werror;
#define SY_PAREN_EXPR '('
#define SY_PAREN_FUNC 'f'
#define SY_PAREN_INDEX '['
+#define SY_PAREN_TERNARY '?'
static sy_elem syexp(lex_ctx ctx, ast_expression *v) {
sy_elem e;
return true;
}
-static bool parser_sy_pop(parser_t *parser, shunt *sy)
+static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
{
const oper_info *op;
lex_ctx ctx;
vec_shrinkby(sy->ops, 1);
+ /* op(:?) has no input and no output */
+ if (!op->operands)
+ return true;
+
vec_shrinkby(sy->out, op->operands);
for (i = 0; i < op->operands; ++i) {
exprs[i] = sy->out[vec_size(sy->out)+i].out;
case opid1(','):
if (blocks[0]) {
- ast_block_add_expr(blocks[0], exprs[1]);
+ if (!ast_block_add_expr(blocks[0], exprs[1]))
+ return false;
} else {
blocks[0] = ast_block_new(ctx);
- ast_block_add_expr(blocks[0], exprs[0]);
- ast_block_add_expr(blocks[0], exprs[1]);
+ if (!ast_block_add_expr(blocks[0], exprs[0]) ||
+ !ast_block_add_expr(blocks[0], exprs[1]))
+ {
+ return false;
+ }
}
if (!ast_block_set_type(blocks[0], exprs[1]))
return false;
break;
case opid2('?',':'):
+ if (vec_last(parser->pot) != POT_TERNARY2) {
+ parseerror(parser, "mismatched parenthesis/ternary");
+ return false;
+ }
+ vec_pop(parser->pot);
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));
/* pop off the parenthesis */
vec_shrinkby(sy->ops, 1);
/* then apply the index operator */
- if (!parser_sy_pop(parser, sy))
+ if (!parser_sy_apply_operator(parser, sy))
+ return false;
+ return true;
+ }
+ if (sy->ops[vec_size(sy->ops)-1].paren == SY_PAREN_TERNARY) {
+ if (functions_only)
return false;
+ if (vec_last(parser->pot) != POT_TERNARY1) {
+ parseerror(parser, "mismatched colon in ternary expression (missing closing paren?)");
+ return false;
+ }
+ vec_last(parser->pot) = POT_TERNARY2;
+ /* pop off the parenthesis */
+ vec_shrinkby(sy->ops, 1);
return true;
}
- if (!parser_sy_pop(parser, sy))
+ if (!parser_sy_apply_operator(parser, sy))
return false;
}
return true;
/* closing an opening paren */
if (!parser_close_paren(parser, &sy, false))
goto onerr;
+ if (vec_last(parser->pot) != POT_PAREN) {
+ parseerror(parser, "mismatched parentheses (closing paren during ternary expression?)");
+ goto onerr;
+ }
+ vec_pop(parser->pot);
} else {
DEBUGSHUNTDO(con_out("do[nop] )\n"));
--parens;
/* allowed for function calls */
if (!parser_close_paren(parser, &sy, true))
goto onerr;
+ if (vec_last(parser->pot) != POT_PAREN) {
+ parseerror(parser, "mismatched parentheses (closing paren during ternary expression?)");
+ goto onerr;
+ }
+ vec_pop(parser->pot);
}
wantop = true;
}
break;
if (!parser_close_paren(parser, &sy, false))
goto onerr;
+ if (vec_last(parser->pot) != POT_PAREN) {
+ parseerror(parser, "mismatched parentheses (closing paren during ternary expression?)");
+ goto onerr;
+ }
+ vec_pop(parser->pot);
wantop = true;
}
else if (parser->tok != TOKEN_OPERATOR) {
break;
}
+ if (op->id == opid1(',')) {
+ if (vec_size(parser->pot) && vec_last(parser->pot) == POT_TERNARY2) {
+ (void)!parsewarning(parser, WARN_TERNARY_PRECEDENCE, "suggesting parenthesis around ternary expression");
+ }
+ }
+
if (vec_size(sy.ops) && !vec_last(sy.ops).paren)
olast = &operators[vec_last(sy.ops).etype-1];
(op->prec < olast->prec) ||
(op->assoc == ASSOC_LEFT && op->prec <= olast->prec) ) )
{
- if (!parser_sy_pop(parser, &sy))
+ if (!parser_sy_apply_operator(parser, &sy))
goto onerr;
if (vec_size(sy.ops) && !vec_last(sy.ops).paren)
olast = &operators[vec_last(sy.ops).etype-1];
if (wantop) {
size_t sycount = vec_size(sy.out);
DEBUGSHUNTDO(con_out("push [op] (\n"));
- ++parens;
+ ++parens; vec_push(parser->pot, POT_PAREN);
/* we expected an operator, this is the function-call operator */
vec_push(sy.ops, syparen(parser_ctx(parser), SY_PAREN_FUNC, sycount-1));
} else {
- ++parens;
+ ++parens; vec_push(parser->pot, POT_PAREN);
vec_push(sy.ops, syparen(parser_ctx(parser), SY_PAREN_EXPR, 0));
DEBUGSHUNTDO(con_out("push [nop] (\n"));
}
parseerror(parser, "unexpected array subscript");
goto onerr;
}
- ++parens;
+ ++parens; vec_push(parser->pot, POT_PAREN);
/* push both the operator and the paren, this makes life easier */
vec_push(sy.ops, syop(parser_ctx(parser), op));
vec_push(sy.ops, syparen(parser_ctx(parser), SY_PAREN_INDEX, 0));
} else if (op->id == opid2('?',':')) {
wantop = false;
vec_push(sy.ops, syop(parser_ctx(parser), op));
+ vec_push(sy.ops, syparen(parser_ctx(parser), SY_PAREN_TERNARY, 0));
wantop = false;
- --ternaries;
+ ++ternaries;
+ vec_push(parser->pot, POT_TERNARY1);
} else if (op->id == opid2(':','?')) {
- /* we don't push this operator */
+ if (!vec_size(parser->pot)) {
+ parseerror(parser, "unexpected colon outside ternary expression (missing parenthesis?)");
+ goto onerr;
+ }
+ if (vec_last(parser->pot) != POT_TERNARY1) {
+ parseerror(parser, "unexpected colon outside ternary expression (missing parenthesis?)");
+ goto onerr;
+ }
+ if (!parser_close_paren(parser, &sy, false))
+ goto onerr;
+ vec_push(sy.ops, syop(parser_ctx(parser), op));
wantop = false;
- ++ternaries;
+ --ternaries;
} else {
DEBUGSHUNTDO(con_out("push operator %s\n", op->op));
vec_push(sy.ops, syop(parser_ctx(parser), op));
}
while (vec_size(sy.ops)) {
- if (!parser_sy_pop(parser, &sy))
+ if (!parser_sy_apply_operator(parser, &sy))
goto onerr;
}
vec_free(sy.out);
vec_free(sy.ops);
DEBUGSHUNTDO(con_out("shunt done\n"));
+ if (vec_size(parser->pot)) {
+ parseerror(parser, "internal error: vec_size(parser->pot) = %lu", (unsigned long)vec_size(parser->pot));
+ return NULL;
+ }
+ vec_free(parser->pot);
return expr;
onerr:
ast_delete(cond);
return false;
}
- ontrue = parse_statement_or_block(parser);
- if (!ontrue) {
+ if (!parse_statement_or_block(parser, &ontrue)) {
ast_delete(cond);
return false;
}
ast_delete(cond);
return false;
}
- onfalse = parse_statement_or_block(parser);
- if (!onfalse) {
+ if (!parse_statement_or_block(parser, &onfalse)) {
ast_delete(ontrue);
ast_delete(cond);
return false;
ast_delete(cond);
return false;
}
- ontrue = parse_statement_or_block(parser);
- if (!ontrue) {
+ if (!parse_statement_or_block(parser, &ontrue)) {
ast_delete(cond);
return false;
}
parseerror(parser, "expected loop body");
return false;
}
- ontrue = parse_statement_or_block(parser);
- if (!ontrue)
+ if (!parse_statement_or_block(parser, &ontrue))
return false;
/* expect the "while" */
"current standard does not allow variable declarations in for-loop initializers"))
goto onerr;
}
- if (!parse_variable(parser, block, true, CV_VAR, typevar))
+ if (!parse_variable(parser, block, true, CV_VAR, typevar, false))
goto onerr;
}
else if (parser->tok != ';')
parseerror(parser, "expected for-loop body");
goto onerr;
}
- ontrue = parse_statement_or_block(parser);
- if (!ontrue) {
+ if (!parse_statement_or_block(parser, &ontrue))
goto onerr;
- }
aloop = ast_loop_new(ctx, initexpr, cond, NULL, increment, ontrue);
*out = (ast_expression*)aloop;
return true;
}
+/* returns true when it was a variable qualifier, false otherwise!
+ * on error, cvq is set to CV_WRONG
+ */
+static bool parse_var_qualifiers(parser_t *parser, bool with_local, int *cvq, bool *noref)
+{
+ bool had_const = false;
+ bool had_var = false;
+ bool had_noref = false;
+
+ for (;;) {
+ if (!strcmp(parser_tokval(parser), "const"))
+ had_const = true;
+ else if (!strcmp(parser_tokval(parser), "var"))
+ had_var = true;
+ else if (with_local && !strcmp(parser_tokval(parser), "local"))
+ had_var = true;
+ else if (!strcmp(parser_tokval(parser), "noref"))
+ had_noref = true;
+ else if (!had_const && !had_var && !had_noref) {
+ return false;
+ }
+ else
+ break;
+ if (!parser_next(parser))
+ goto onerr;
+ }
+ if (had_const)
+ *cvq = CV_CONST;
+ else if (had_var)
+ *cvq = CV_VAR;
+ else
+ *cvq = CV_NONE;
+ *noref = had_noref;
+ return true;
+onerr:
+ parseerror(parser, "parse error after variable qualifier");
+ *cvq = CV_WRONG;
+ return true;
+}
+
static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **out)
{
ast_expression *operand;
ast_value *opval;
+ ast_value *typevar;
ast_switch *switchnode;
ast_switch_case swcase;
+ int cvq;
+ bool noref;
+
lex_ctx ctx = parser_ctx(parser);
(void)block; /* not touching */
return false;
}
+ /* new block; allow some variables to be declared here */
+ parser_enterblock(parser);
+ while (true) {
+ typevar = NULL;
+ if (parser->tok == TOKEN_IDENT)
+ typevar = parser_find_typedef(parser, parser_tokval(parser), 0);
+ if (typevar || parser->tok == TOKEN_TYPENAME) {
+ if (!parse_variable(parser, block, false, CV_NONE, typevar, false)) {
+ ast_delete(switchnode);
+ return false;
+ }
+ continue;
+ }
+ if (parse_var_qualifiers(parser, true, &cvq, &noref))
+ {
+ if (cvq == CV_WRONG) {
+ ast_delete(switchnode);
+ return false;
+ }
+ if (!parse_variable(parser, block, false, cvq, NULL, noref)) {
+ ast_delete(switchnode);
+ return false;
+ }
+ continue;
+ }
+ break;
+ }
+
/* case list! */
while (parser->tok != '}') {
ast_block *caseblock;
}
if (!expr)
continue;
- ast_block_add_expr(caseblock, expr);
+ if (!ast_block_add_expr(caseblock, expr)) {
+ ast_delete(switchnode);
+ return false;
+ }
}
}
+ parser_leaveblock(parser);
+
/* closing paren */
if (parser->tok != '}') {
ast_delete(switchnode);
return true;
}
+static bool parse_skipwhite(parser_t *parser)
+{
+ do {
+ if (!parser_next(parser))
+ return false;
+ } while (parser->tok == TOKEN_WHITE && parser->tok < TOKEN_ERROR);
+ return parser->tok < TOKEN_ERROR;
+}
+
+static bool parse_eol(parser_t *parser)
+{
+ if (!parse_skipwhite(parser))
+ return false;
+ return parser->tok == TOKEN_EOL;
+}
+
+static bool parse_pragma_do(parser_t *parser)
+{
+ if (!parser_next(parser) ||
+ parser->tok != TOKEN_IDENT ||
+ strcmp(parser_tokval(parser), "pragma"))
+ {
+ parseerror(parser, "expected `pragma` keyword after `#`, got `%s`", parser_tokval(parser));
+ return false;
+ }
+ if (!parse_skipwhite(parser) || parser->tok != TOKEN_IDENT) {
+ parseerror(parser, "expected pragma, got `%s`", parser_tokval(parser));
+ return false;
+ }
+
+ if (!strcmp(parser_tokval(parser), "noref")) {
+ if (!parse_skipwhite(parser) || parser->tok != TOKEN_INTCONST) {
+ parseerror(parser, "`noref` pragma requires an argument: 0 or 1");
+ return false;
+ }
+ parser->noref = !!parser_token(parser)->constval.i;
+ if (!parse_eol(parser)) {
+ parseerror(parser, "parse error after `noref` pragma");
+ return false;
+ }
+ }
+ else
+ {
+ parseerror(parser, "unrecognized hash-keyword: `%s`", parser_tokval(parser));
+ return false;
+ }
+
+ return true;
+}
+
+static bool parse_pragma(parser_t *parser)
+{
+ bool rv;
+ parser->lex->flags.preprocessing = true;
+ parser->lex->flags.mergelines = true;
+ rv = parse_pragma_do(parser);
+ if (parser->tok != TOKEN_EOL) {
+ parseerror(parser, "junk after pragma");
+ rv = false;
+ }
+ parser->lex->flags.preprocessing = false;
+ parser->lex->flags.mergelines = false;
+ if (!parser_next(parser)) {
+ parseerror(parser, "parse error after pragma");
+ rv = false;
+ }
+ return rv;
+}
+
static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases)
{
- int cvq;
+ bool noref;
+ int cvq = CV_NONE;
ast_value *typevar = NULL;
+
*out = NULL;
if (parser->tok == TOKEN_IDENT)
if (parsewarning(parser, WARN_EXTENSIONS, "missing 'local' keyword when declaring a local variable"))
return false;
}
- if (!parse_variable(parser, block, false, CV_NONE, typevar))
+ if (!parse_variable(parser, block, false, CV_NONE, typevar, false))
return false;
- *out = NULL;
return true;
}
- else if (parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "var"))
+ else if (parse_var_qualifiers(parser, !!block, &cvq, &noref))
{
- goto ident_var;
+ if (cvq == CV_WRONG)
+ return false;
+ return parse_variable(parser, block, true, cvq, NULL, noref);
}
else if (parser->tok == TOKEN_KEYWORD)
{
- if (!strcmp(parser_tokval(parser), "local") ||
- !strcmp(parser_tokval(parser), "const") ||
- !strcmp(parser_tokval(parser), "var"))
- {
-ident_var:
- if (parser_tokval(parser)[0] == 'c')
- cvq = CV_CONST;
- else if (parser_tokval(parser)[0] == 'v')
- cvq = CV_VAR;
- else
- cvq = CV_NONE;
-
- if (!block) {
- parseerror(parser, "cannot declare a local variable here");
- return false;
- }
- if (!parser_next(parser)) {
- parseerror(parser, "expected variable declaration");
- return false;
- }
- if (!parse_variable(parser, block, true, cvq, NULL))
- return false;
- *out = NULL;
- return true;
- }
- else if (!strcmp(parser_tokval(parser), "__builtin_debug_printtype"))
+ if (!strcmp(parser_tokval(parser), "__builtin_debug_printtype"))
{
char ty[1024];
ast_value *tdef;
}
if (!expr)
continue;
- ast_block_add_expr(block, expr);
+ if (!ast_block_add_expr(block, expr)) {
+ ast_delete(block);
+ block = NULL;
+ goto cleanup;
+ }
}
if (parser->tok != '}') {
return block;
}
-static ast_expression* parse_statement_or_block(parser_t *parser)
+static bool parse_statement_or_block(parser_t *parser, ast_expression **out)
{
- ast_expression *expr = NULL;
- if (parser->tok == '{')
- return (ast_expression*)parse_block(parser);
- if (!parse_statement(parser, NULL, &expr, false))
- return NULL;
- return expr;
+ if (parser->tok == '{') {
+ *out = (ast_expression*)parse_block(parser);
+ return !!*out;
+ }
+ return parse_statement(parser, NULL, out, false);
}
static bool create_vector_members(ast_value *var, ast_member **me)
if (store_think) ast_delete(store_think);
retval = false;
}
- ast_block_add_expr(block, (ast_expression*)store_frame);
- ast_block_add_expr(block, (ast_expression*)store_nextthink);
- ast_block_add_expr(block, (ast_expression*)store_think);
+ if (!ast_block_add_expr(block, (ast_expression*)store_frame) ||
+ !ast_block_add_expr(block, (ast_expression*)store_nextthink) ||
+ !ast_block_add_expr(block, (ast_expression*)store_think))
+ {
+ retval = false;
+ }
}
if (!retval) {
return NULL;
}
- ast_block_add_expr(block, (ast_expression*)st);
+ if (!ast_block_add_expr(block, (ast_expression*)st)) {
+ ast_delete(block);
+ return NULL;
+ }
ret = ast_return_new(ctx, NULL);
if (!ret) {
return NULL;
}
- ast_block_add_expr(block, (ast_expression*)ret);
+ if (!ast_block_add_expr(block, (ast_expression*)ret)) {
+ ast_delete(block);
+ return NULL;
+ }
return (ast_expression*)block;
} else {
return NULL;
}
- ast_block_add_expr(block, (ast_expression*)st);
+ if (!ast_block_add_expr(block, (ast_expression*)st)) {
+ ast_delete(block);
+ return NULL;
+ }
ret = ast_return_new(ctx, NULL);
if (!ret) {
return NULL;
}
- ast_block_add_expr(block, (ast_expression*)ret);
+ if (!ast_block_add_expr(block, (ast_expression*)ret)) {
+ ast_delete(block);
+ return NULL;
+ }
return (ast_expression*)block;
} else {
goto cleanup;
}
- ast_block_add_expr(func->blocks[0], root);
array->setter = fval;
- return true;
+ return ast_block_add_expr(func->blocks[0], root);
cleanup:
if (index) ast_delete(index);
if (value) ast_delete(value);
goto cleanup;
}
- ast_block_add_expr(func->blocks[0], root);
array->setter = fval;
- return true;
+ return ast_block_add_expr(func->blocks[0], root);
cleanup:
if (entity) ast_delete(entity);
if (index) ast_delete(index);
goto cleanup;
}
- ast_block_add_expr(func->blocks[0], root);
array->getter = fval;
- return true;
+ return ast_block_add_expr(func->blocks[0], root);
cleanup:
if (index) ast_delete(index);
if (root) ast_delete(root);
return true;
}
-static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef)
+static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref)
{
ast_value *var;
ast_value *proto;
}
var->cvq = qualifier;
+ /* in a noref section we simply bump the usecount */
+ if (noref || parser->noref)
+ var->uses++;
/* Part 1:
* check for validity: (end_sys_..., multiple-definitions, prototypes, ...)
/* Deal with end_sys_ vars */
was_end = false;
if (!strcmp(var->name, "end_sys_globals")) {
+ var->uses++;
parser->crc_globals = vec_size(parser->globals);
was_end = true;
}
else if (!strcmp(var->name, "end_sys_fields")) {
+ var->uses++;
parser->crc_fields = vec_size(parser->fields);
was_end = true;
}
}
vec_push(parser->functions, func);
- func->builtin = -parser_token(parser)->constval.i;
+ func->builtin = -parser_token(parser)->constval.i-1;
}
if (!parser_next(parser)) {
vec_push(sy.out, syexp(ast_ctx(var), (ast_expression*)var));
vec_push(sy.out, syexp(ast_ctx(cexp), (ast_expression*)cexp));
vec_push(sy.ops, syop(ast_ctx(var), parser->assign_op));
- if (!parser_sy_pop(parser, &sy))
+ if (!parser_sy_apply_operator(parser, &sy))
ast_unref(cexp);
else {
if (vec_size(sy.out) != 1 && vec_size(sy.ops) != 0)
parseerror(parser, "internal error: leaked operands");
- ast_block_add_expr(localblock, (ast_expression*)sy.out[0].out);
+ if (!ast_block_add_expr(localblock, (ast_expression*)sy.out[0].out))
+ break;
}
vec_free(sy.out);
vec_free(sy.ops);
static bool parser_global_statement(parser_t *parser)
{
+ int cvq = CV_WRONG;
+ bool noref = false;
ast_value *istype = NULL;
+
if (parser->tok == TOKEN_IDENT)
istype = parser_find_typedef(parser, parser_tokval(parser), 0);
if (istype || parser->tok == TOKEN_TYPENAME || parser->tok == '.')
{
- return parse_variable(parser, NULL, false, CV_NONE, istype);
+ return parse_variable(parser, NULL, false, CV_NONE, istype, false);
}
- else if (parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "var"))
+ else if (parse_var_qualifiers(parser, false, &cvq, &noref))
{
- if (!strcmp(parser_tokval(parser), "var")) {
- if (!parser_next(parser)) {
- parseerror(parser, "expected variable declaration after 'var'");
- return false;
- }
- return parse_variable(parser, NULL, true, CV_VAR, NULL);
- }
+ if (cvq == CV_WRONG)
+ return false;
+ return parse_variable(parser, NULL, true, cvq, NULL, noref);
}
else if (parser->tok == TOKEN_KEYWORD)
{
- if (!strcmp(parser_tokval(parser), "const")) {
- if (!parser_next(parser)) {
- parseerror(parser, "expected variable declaration after 'const'");
- return false;
- }
- if (parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "var")) {
- (void)!parsewarning(parser, WARN_CONST_VAR, "ignoring `var` after const qualifier");
- if (!parser_next(parser)) {
- parseerror(parser, "expected variable declaration after 'const var'");
- return false;
- }
- }
- return parse_variable(parser, NULL, true, CV_CONST, NULL);
- }
- else if (!strcmp(parser_tokval(parser), "typedef")) {
+ if (!strcmp(parser_tokval(parser), "typedef")) {
if (!parser_next(parser)) {
parseerror(parser, "expected type definition after 'typedef'");
return false;
parseerror(parser, "unrecognized keyword `%s`", parser_tokval(parser));
return false;
}
+ else if (parser->tok == '#')
+ {
+ return parse_pragma(parser);
+ }
else if (parser->tok == '$')
{
if (!parser_next(parser)) {
continue;
asvalue = (ast_value*)(parser->globals[i]);
if (!asvalue->uses && !asvalue->hasvalue && asvalue->expression.vtype != TYPE_FUNCTION) {
- if (strcmp(asvalue->name, "end_sys_globals") &&
- strcmp(asvalue->name, "end_sys_fields"))
- {
- retval = retval && !genwarning(ast_ctx(asvalue), WARN_UNUSED_VARIABLE,
- "unused global: `%s`", asvalue->name);
- }
+ retval = retval && !genwarning(ast_ctx(asvalue), WARN_UNUSED_VARIABLE,
+ "unused global: `%s`", asvalue->name);
}
if (!ast_global_codegen(asvalue, ir, false)) {
con_out("failed to generate global %s\n", asvalue->name);
if (!ast_istype(parser->globals[i], ast_value))
continue;
asvalue = (ast_value*)(parser->globals[i]);
- if (asvalue->setter) {
- if (!ast_global_codegen(asvalue->setter, ir, false) ||
- !ast_function_codegen(asvalue->setter->constval.vfunc, ir) ||
- !ir_function_finalize(asvalue->setter->constval.vfunc->ir_func))
- {
- printf("failed to generate setter for %s\n", asvalue->name);
- ir_builder_delete(ir);
- return false;
- }
- }
- if (asvalue->getter) {
- if (!ast_global_codegen(asvalue->getter, ir, false) ||
- !ast_function_codegen(asvalue->getter->constval.vfunc, ir) ||
- !ir_function_finalize(asvalue->getter->constval.vfunc->ir_func))
- {
- printf("failed to generate getter for %s\n", asvalue->name);
- ir_builder_delete(ir);
- return false;
- }
+ if (!ast_generate_accessors(asvalue, ir)) {
+ ir_builder_delete(ir);
+ return false;
}
}
for (i = 0; i < vec_size(parser->fields); ++i) {
continue;
if (asvalue->expression.vtype != TYPE_ARRAY)
continue;
- if (asvalue->setter) {
- if (!ast_global_codegen(asvalue->setter, ir, false) ||
- !ast_function_codegen(asvalue->setter->constval.vfunc, ir) ||
- !ir_function_finalize(asvalue->setter->constval.vfunc->ir_func))
- {
- printf("failed to generate setter for %s\n", asvalue->name);
- ir_builder_delete(ir);
- return false;
- }
- }
- if (asvalue->getter) {
- if (!ast_global_codegen(asvalue->getter, ir, false) ||
- !ast_function_codegen(asvalue->getter->constval.vfunc, ir) ||
- !ir_function_finalize(asvalue->getter->constval.vfunc->ir_func))
- {
- printf("failed to generate getter for %s\n", asvalue->name);
- ir_builder_delete(ir);
- return false;
- }
+ if (!ast_generate_accessors(asvalue, ir)) {
+ ir_builder_delete(ir);
+ return false;
}
}
for (i = 0; i < vec_size(parser->functions); ++i) {