]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.c
Starting to add error messages for when using array types in expressions
[xonotic/gmqcc.git] / parser.c
index 0616b711b7fb97137a7d5fa9d6db5dc6e3517022..1b2b691f67f595309cd31ef7a9a0308ca6fa06e2 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -387,6 +387,9 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy)
     size_t i, assignop;
     qcint  generated_op = 0;
 
+    char ty1[1024];
+    char ty2[1024];
+
     if (!sy->ops_count) {
         parseerror(parser, "internal error: missing operator");
         return false;
@@ -759,8 +762,6 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy)
                 else
                     assignop = type_storep_instr[exprs[0]->expression.vtype];
                 if (!ast_compare_type(field->expression.next, exprs[1])) {
-                    char ty1[1024];
-                    char ty2[1024];
                     ast_type_to_string(field->expression.next, ty1, sizeof(ty1));
                     ast_type_to_string(exprs[1], ty2, sizeof(ty2));
                     if (opts_standard == COMPILER_QCC &&
@@ -785,11 +786,16 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy)
                 {
                     assignop = type_store_instr[TYPE_VECTOR];
                 }
-                else
+                else {
                     assignop = type_store_instr[exprs[0]->expression.vtype];
-                if (!ast_compare_type(exprs[0], exprs[1])) {
-                    char ty1[1024];
-                    char ty2[1024];
+                }
+
+                if (assignop == AINSTR_END) {
+                    ast_type_to_string(exprs[0], ty1, sizeof(ty1));
+                    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])) {
                     ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                     ast_type_to_string(exprs[1], ty2, sizeof(ty2));
                     if (opts_standard == COMPILER_QCC &&
@@ -1148,6 +1154,10 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
             parseerror(parser, "internal error: '(' should be classified as operator");
             goto onerr;
         }
+        else if (parser->tok == '[') {
+            parseerror(parser, "internal error: '[' should be classified as operator");
+            goto onerr;
+        }
         else if (parser->tok == ')') {
             if (wantop) {
                 DEBUGSHUNTDO(printf("do[op] )\n"));
@@ -2262,6 +2272,60 @@ on_error:
     return NULL;
 }
 
+static ast_value *parse_arraysize(parser_t *parser, ast_value *var)
+{
+    ast_expression *cexp;
+    ast_value      *cval, *tmp;
+    lex_ctx ctx;
+
+    ctx = parser_ctx(parser);
+
+    if (!parser_next(parser)) {
+        ast_delete(var);
+        parseerror(parser, "expected array-size");
+        return NULL;
+    }
+
+    cexp = parse_expression_leave(parser, true);
+
+    if (!cexp || !ast_istype(cexp, ast_value)) {
+        if (cexp)
+            ast_unref(cexp);
+        ast_delete(var);
+        parseerror(parser, "expected array-size as constant positive integer");
+        return NULL;
+    }
+    cval = (ast_value*)cexp;
+
+    tmp = ast_value_new(ctx, "<type[]>", TYPE_ARRAY);
+    tmp->expression.next = (ast_expression*)var;
+    var = tmp;
+
+    if (cval->expression.vtype == TYPE_INTEGER)
+        tmp->expression.count = cval->constval.vint;
+    else if (cval->expression.vtype == TYPE_FLOAT)
+        tmp->expression.count = cval->constval.vfloat;
+    else {
+        ast_unref(cexp);
+        ast_delete(var);
+        parseerror(parser, "array-size must be a positive integer constant");
+        return NULL;
+    }
+    ast_unref(cexp);
+
+    if (parser->tok != ']') {
+        ast_delete(var);
+        parseerror(parser, "expected ']' after array-size");
+        return NULL;
+    }
+    if (!parser_next(parser)) {
+        ast_delete(var);
+        parseerror(parser, "error after parsing array size");
+        return NULL;
+    }
+    return var;
+}
+
 /* Parse a complete typename.
  * for single-variables (ie. function parameters or typedefs) storebase should be NULL
  * but when parsing variables separated by comma
@@ -2348,42 +2412,9 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase)
 
     /* now this may be an array */
     if (parser->tok == '[') {
-        ast_expression *cexp = parse_expression_leave(parser, true);
-        ast_value      *cval;
-        if (!cexp || !ast_istype(cexp, ast_value)) {
-            if (cexp) ast_delete(cexp);
-            ast_delete(var);
-            parseerror(parser, "expected array-size as constant positive integer");
-            return NULL;
-        }
-        cval = (ast_value*)cexp;
-
-        tmp = ast_value_new(ctx, "<type[]>", TYPE_ARRAY);
-        tmp->expression.next = (ast_expression*)var;
-        var = tmp;
-
-        if (cval->expression.vtype == TYPE_INTEGER)
-            tmp->expression.count = cval->constval.vint;
-        else if (cval->expression.vtype == TYPE_FLOAT)
-            tmp->expression.count = cval->constval.vfloat;
-        else {
-            ast_delete(cexp);
-            ast_delete(var);
-            parseerror(parser, "array-size must be a positive integer constant");
-            return NULL;
-        }
-        ast_delete(cexp);
-
-        if (parser->tok != ']') {
-            ast_delete(var);
-            parseerror(parser, "expected ']' after array-size");
-            return NULL;
-        }
-        if (!parser_next(parser)) {
-            ast_delete(var);
-            parseerror(parser, "error after parsing array size");
+        var = parse_arraysize(parser, var);
+        if (!var)
             return NULL;
-        }
     }
 
     /* This is the point where we can turn it into a field */
@@ -2434,6 +2465,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
     bool      isparam   = false;
     bool      isvector  = false;
     bool      cleanvar  = true;
+    bool      wasarray  = false;
 
     varentry_t varent, ve[3];
 
@@ -2450,8 +2482,32 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
 
     while (true) {
         proto = NULL;
+        wasarray = false;
 
         /* Part 0: finish the type */
+        if (parser->tok == '(') {
+            if (opts_standard == COMPILER_QCC)
+                parseerror(parser, "C-style function syntax is not allowed in -std=qcc");
+            var = parse_parameter_list(parser, var);
+            if (!var) {
+                retval = false;
+                goto cleanup;
+            }
+        }
+        /* we only allow 1-dimensional arrays */
+        if (parser->tok == '[') {
+            wasarray = true;
+            var = parse_arraysize(parser, var);
+            if (!var) {
+                retval = false;
+                goto cleanup;
+            }
+        }
+        if (parser->tok == '(' && wasarray) {
+            parseerror(parser, "functions cannot return arrays");
+            /* we'll still parse the type completely for now */
+        }
+        /* for functions returning functions */
         while (parser->tok == '(') {
             if (opts_standard == COMPILER_QCC)
                 parseerror(parser, "C-style function syntax is not allowed in -std=qcc");