ast_value *imm_float_zero;
ast_value *imm_float_one;
ast_value *imm_vector_zero;
+ ast_value *nil;
size_t crc_globals;
size_t crc_fields;
/* All the labels the function defined...
* Should they be in ast_function instead?
*/
- ast_label **labels;
- ast_goto **gotos;
+ ast_label **labels;
+ ast_goto **gotos;
+ const char **breaks;
+ const char **continues;
/* A list of hashtables for each scope */
ht *variables;
break;
case opid1('*'):
if (exprs[0]->expression.vtype != exprs[1]->expression.vtype &&
- exprs[0]->expression.vtype != TYPE_VECTOR &&
- exprs[0]->expression.vtype != TYPE_FLOAT &&
- exprs[1]->expression.vtype != TYPE_VECTOR &&
- exprs[1]->expression.vtype != TYPE_FLOAT)
+ !(exprs[0]->expression.vtype == TYPE_VECTOR &&
+ exprs[1]->expression.vtype == TYPE_FLOAT) &&
+ !(exprs[1]->expression.vtype == TYPE_VECTOR &&
+ exprs[0]->expression.vtype == TYPE_FLOAT)
+ )
{
parseerror(parser, "invalid types used in expression: cannot multiply types %s and %s",
type_name[exprs[1]->expression.vtype],
ast_type_to_string(exprs[1], ty2, sizeof(ty2));
parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
}
- else if (!ast_compare_type(exprs[0], exprs[1])) {
+ else if (exprs[1]->expression.vtype != TYPE_NIL &&
+ !ast_compare_type(exprs[0], exprs[1]))
+ {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
ast_type_to_string(exprs[1], ty2, sizeof(ty2));
if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) &&
const oper_info *olast = NULL;
size_t o;
for (o = 0; o < operator_count; ++o) {
- if ((!(operators[o].flags & OP_PREFIX) == wantop) &&
+ if (((!(operators[o].flags & OP_PREFIX) == !!wantop)) &&
/* !(operators[o].flags & OP_SUFFIX) && / * remove this */
!strcmp(parser_tokval(parser), operators[o].op))
{
return true;
}
+static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression **out);
static bool parse_while(parser_t *parser, ast_block *block, ast_expression **out)
+{
+ bool rv;
+ char *label = NULL;
+
+ /* skip the 'while' and get the body */
+ if (!parser_next(parser)) {
+ if (OPTS_FLAG(LOOP_LABELS))
+ parseerror(parser, "expected loop label or 'while' condition in parenthesis");
+ else
+ parseerror(parser, "expected 'while' condition in parenthesis");
+ return false;
+ }
+
+ if (parser->tok == ':') {
+ if (!OPTS_FLAG(LOOP_LABELS))
+ parseerror(parser, "labeled loops not activated, try using -floop-labels");
+ if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
+ parseerror(parser, "expected loop label");
+ return false;
+ }
+ label = util_strdup(parser_tokval(parser));
+ if (!parser_next(parser)) {
+ mem_d(label);
+ parseerror(parser, "expected 'while' condition in parenthesis");
+ return false;
+ }
+ }
+
+ if (parser->tok != '(') {
+ parseerror(parser, "expected 'while' condition in parenthesis");
+ return false;
+ }
+
+ vec_push(parser->breaks, label);
+ vec_push(parser->continues, label);
+
+ rv = parse_while_go(parser, block, out);
+ if (label)
+ mem_d(label);
+ if (vec_last(parser->breaks) != label || vec_last(parser->continues) != label) {
+ parseerror(parser, "internal error: label stack corrupted");
+ rv = false;
+ ast_delete(*out);
+ *out = NULL;
+ }
+ else {
+ vec_pop(parser->breaks);
+ vec_pop(parser->continues);
+ }
+ return rv;
+}
+
+static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression **out)
{
ast_loop *aloop;
ast_expression *cond, *ontrue;
(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");
- return false;
- }
/* parse into the expression */
if (!parser_next(parser)) {
parseerror(parser, "expected 'while' condition after opening paren");
return true;
}
+static bool parse_dowhile_go(parser_t *parser, ast_block *block, ast_expression **out);
static bool parse_dowhile(parser_t *parser, ast_block *block, ast_expression **out)
+{
+ bool rv;
+ char *label = NULL;
+
+ /* skip the 'do' and get the body */
+ if (!parser_next(parser)) {
+ if (OPTS_FLAG(LOOP_LABELS))
+ parseerror(parser, "expected loop label or body");
+ else
+ parseerror(parser, "expected loop body");
+ return false;
+ }
+
+ if (parser->tok == ':') {
+ if (!OPTS_FLAG(LOOP_LABELS))
+ parseerror(parser, "labeled loops not activated, try using -floop-labels");
+ if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
+ parseerror(parser, "expected loop label");
+ return false;
+ }
+ label = util_strdup(parser_tokval(parser));
+ if (!parser_next(parser)) {
+ mem_d(label);
+ parseerror(parser, "expected loop body");
+ return false;
+ }
+ }
+
+ vec_push(parser->breaks, label);
+ vec_push(parser->continues, label);
+
+ rv = parse_dowhile_go(parser, block, out);
+ if (label)
+ mem_d(label);
+ if (vec_last(parser->breaks) != label || vec_last(parser->continues) != label) {
+ parseerror(parser, "internal error: label stack corrupted");
+ rv = false;
+ ast_delete(*out);
+ *out = NULL;
+ }
+ else {
+ vec_pop(parser->breaks);
+ vec_pop(parser->continues);
+ }
+ return rv;
+}
+
+static bool parse_dowhile_go(parser_t *parser, ast_block *block, ast_expression **out)
{
ast_loop *aloop;
ast_expression *cond, *ontrue;
(void)block; /* not touching */
- /* skip the 'do' and get the body */
- if (!parser_next(parser)) {
- parseerror(parser, "expected loop body");
- return false;
- }
if (!parse_statement_or_block(parser, &ontrue))
return false;
return true;
}
+static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **out);
static bool parse_for(parser_t *parser, ast_block *block, ast_expression **out)
+{
+ bool rv;
+ char *label = NULL;
+
+ /* skip the 'for' and check for opening paren */
+ if (!parser_next(parser)) {
+ if (OPTS_FLAG(LOOP_LABELS))
+ parseerror(parser, "expected loop label or 'for' expressions in parenthesis");
+ else
+ parseerror(parser, "expected 'for' expressions in parenthesis");
+ return false;
+ }
+
+ if (parser->tok == ':') {
+ if (!OPTS_FLAG(LOOP_LABELS))
+ parseerror(parser, "labeled loops not activated, try using -floop-labels");
+ if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
+ parseerror(parser, "expected loop label");
+ return false;
+ }
+ label = util_strdup(parser_tokval(parser));
+ if (!parser_next(parser)) {
+ mem_d(label);
+ parseerror(parser, "expected 'for' expressions in parenthesis");
+ return false;
+ }
+ }
+
+ if (parser->tok != '(') {
+ parseerror(parser, "expected 'for' expressions in parenthesis");
+ return false;
+ }
+
+ vec_push(parser->breaks, label);
+ vec_push(parser->continues, label);
+
+ rv = parse_for_go(parser, block, out);
+ if (label)
+ mem_d(label);
+ if (vec_last(parser->breaks) != label || vec_last(parser->continues) != label) {
+ parseerror(parser, "internal error: label stack corrupted");
+ rv = false;
+ ast_delete(*out);
+ *out = NULL;
+ }
+ else {
+ vec_pop(parser->breaks);
+ vec_pop(parser->continues);
+ }
+ return rv;
+}
+static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **out)
{
ast_loop *aloop;
ast_expression *initexpr, *cond, *increment, *ontrue;
increment = NULL;
ontrue = NULL;
- /* skip the 'while' and check for opening paren */
- if (!parser_next(parser) || parser->tok != '(') {
- parseerror(parser, "expected 'for' expressions in parenthesis");
- goto onerr;
- }
/* parse into the expression */
if (!parser_next(parser)) {
parseerror(parser, "expected 'for' initializer after opening paren");
static bool parse_break_continue(parser_t *parser, ast_block *block, ast_expression **out, bool is_continue)
{
- lex_ctx ctx = parser_ctx(parser);
+ size_t i;
+ unsigned int levels = 0;
+ lex_ctx ctx = parser_ctx(parser);
+ const char **loops = (is_continue ? parser->continues : parser->breaks);
(void)block; /* not touching */
+ if (!parser_next(parser)) {
+ parseerror(parser, "expected semicolon or loop label");
+ return false;
+ }
- if (!parser_next(parser) || parser->tok != ';') {
+ if (parser->tok == TOKEN_IDENT) {
+ if (!OPTS_FLAG(LOOP_LABELS))
+ parseerror(parser, "labeled loops not activated, try using -floop-labels");
+ i = vec_size(loops);
+ while (i--) {
+ if (loops[i] && !strcmp(loops[i], parser_tokval(parser)))
+ break;
+ if (!i) {
+ parseerror(parser, "no such loop to %s: `%s`",
+ (is_continue ? "continue" : "break out of"),
+ parser_tokval(parser));
+ return false;
+ }
+ ++levels;
+ }
+ if (!parser_next(parser)) {
+ parseerror(parser, "expected semicolon");
+ return false;
+ }
+ }
+
+ if (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);
+ *out = (ast_expression*)ast_breakcont_new(ctx, is_continue, levels);
return true;
}
return true;
}
+static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression **out);
static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **out)
+{
+ bool rv;
+ char *label = NULL;
+
+ /* skip the 'while' and get the body */
+ if (!parser_next(parser)) {
+ if (OPTS_FLAG(LOOP_LABELS))
+ parseerror(parser, "expected loop label or 'switch' operand in parenthesis");
+ else
+ parseerror(parser, "expected 'switch' operand in parenthesis");
+ return false;
+ }
+
+ if (parser->tok == ':') {
+ if (!OPTS_FLAG(LOOP_LABELS))
+ parseerror(parser, "labeled loops not activated, try using -floop-labels");
+ if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
+ parseerror(parser, "expected loop label");
+ return false;
+ }
+ label = util_strdup(parser_tokval(parser));
+ if (!parser_next(parser)) {
+ mem_d(label);
+ parseerror(parser, "expected 'switch' operand in parenthesis");
+ return false;
+ }
+ }
+
+ if (parser->tok != '(') {
+ parseerror(parser, "expected 'switch' operand in parenthesis");
+ return false;
+ }
+
+ vec_push(parser->breaks, label);
+
+ rv = parse_switch_go(parser, block, out);
+ if (label)
+ mem_d(label);
+ if (vec_last(parser->breaks) != label) {
+ parseerror(parser, "internal error: label stack corrupted");
+ rv = false;
+ ast_delete(*out);
+ *out = NULL;
+ }
+ else {
+ vec_pop(parser->breaks);
+ }
+ return rv;
+}
+
+static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression **out)
{
ast_expression *operand;
ast_value *opval;
(void)block; /* not touching */
(void)opval;
- /* 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");
ast_unref(cval);
}
} else {
- bool cvq;
+ int cvq;
shunt sy = { NULL, NULL };
cvq = var->cvq;
var->cvq = CV_NONE;
bool parser_init()
{
+ lex_ctx empty_ctx;
size_t i;
parser = (parser_t*)mem_a(sizeof(parser_t));
vec_push(parser->variables, parser->htglobals = util_htnew(PARSER_HT_SIZE));
vec_push(parser->typedefs, util_htnew(TYPEDEF_HT_SIZE));
vec_push(parser->_blocktypedefs, 0);
+
+ empty_ctx.file = "<internal>";
+ empty_ctx.line = 0;
+ parser->nil = ast_value_new(empty_ctx, "nil", TYPE_NIL);
+ if (OPTS_FLAG(UNTYPED_NIL))
+ util_htset(parser->htglobals, "nil", (void*)parser->nil);
return true;
}
vec_free(parser->labels);
vec_free(parser->gotos);
+ vec_free(parser->breaks);
+ vec_free(parser->continues);
mem_d(parser);
}