]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.c
Proto for parsing a function body
[xonotic/gmqcc.git] / parser.c
index 80347dfedf566ce5ba47fdcf6b0a85661bab0705..c0a1fbb806c7994d8702810752ba7453e9f2093b 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -9,9 +9,13 @@ typedef struct {
     int      tok;
 
     MEM_VECTOR_MAKE(ast_value*, globals);
+    MEM_VECTOR_MAKE(ast_function*, functions);
+
+    ast_function *function;
 } parser_t;
 
 MEM_VEC_FUNCTIONS(parser_t, ast_value*, globals)
+MEM_VEC_FUNCTIONS(parser_t, ast_function*, functions)
 
 void parseerror(parser_t *parser, const char *fmt, ...)
 {
@@ -60,15 +64,90 @@ ast_value* parser_find_global(parser_t *parser, const char *name)
     return NULL;
 }
 
+typedef struct {
+    MEM_VECTOR_MAKE(ast_value*, p);
+} paramlist_t;
+MEM_VEC_FUNCTIONS(paramlist_t, ast_value*, p)
+
+ast_value *parser_parse_type(parser_t *parser, bool *isfunc)
+{
+    paramlist_t params;
+    ast_value *var;
+    lex_ctx   ctx = parser_ctx(parser);
+    int vtype = parser_token(parser)->constval.t;
+
+    MEM_VECTOR_INIT(&params, p);
+
+    *isfunc = false;
+
+    if (!parser_next(parser))
+        return NULL;
+
+    if (parser->tok == '(') {
+        *isfunc = true;
+        while (true) {
+            ast_value *param;
+            bool dummy;
+
+            if (!parser_next(parser)) {
+                MEM_VECTOR_CLEAR(&params, p);
+                return NULL;
+            }
+
+            if (parser->tok == ')')
+                break;
+
+            param = parser_parse_type(parser, &dummy);
+            (void)dummy;
+
+            if (!param) {
+                MEM_VECTOR_CLEAR(&params, p);
+                return NULL;
+            }
+
+            if (!paramlist_t_p_add(&params, param)) {
+                MEM_VECTOR_CLEAR(&params, p);
+                parseerror(parser, "Out of memory while parsing typename");
+                return NULL;
+            }
+
+            if (parser->tok == ',')
+                continue;
+            if (parser->tok == ')')
+                break;
+            MEM_VECTOR_CLEAR(&params, p);
+            parseerror(parser, "Unexpected token");
+            return NULL;
+        }
+        if (!parser_next(parser)) {
+            MEM_VECTOR_CLEAR(&params, p);
+            return NULL;
+        }
+    }
+
+    var = ast_value_new(ctx, "<unnamed>", vtype);
+    if (!var) {
+        MEM_VECTOR_CLEAR(&params, p);
+        return NULL;
+    }
+    MEM_VECTOR_MOVE(&params, p, var, params);
+    return var;
+}
+
+bool parser_parse_body(parser_t *parser)
+{
+    return false;
+}
+
 bool parser_do(parser_t *parser)
 {
     if (parser->tok == TOKEN_TYPENAME)
     {
-        ast_value *var;
-        int       vtype = parser->lex->tok->constval.t;
-
-        /* Declaring a variable */
-        if (!parser_next(parser))
+        bool isfunc = false;
+        ast_function *func = NULL;
+        lex_ctx ctx = parser_ctx(parser);
+        ast_value *var = parser_parse_type(parser, &isfunc);
+        if (!var)
             return false;
 
         if (parser->tok != TOKEN_IDENT) {
@@ -76,32 +155,110 @@ bool parser_do(parser_t *parser)
             return false;
         }
 
-        var = parser_find_global(parser, parser_tokval(parser));
-
-        if (var) {
+        if (parser_find_global(parser, parser_tokval(parser))) {
+            ast_value_delete(var);
             parseerror(parser, "global already exists: %s\n", parser_tokval(parser));
             return false;
         }
 
-        var = ast_value_new(parser_ctx(parser), parser_tokval(parser), vtype);
-        if (!parser_t_globals_add(parser, var))
+        if (!ast_value_set_name(var, parser_tokval(parser))) {
+            parseerror(parser, "failed to set variable name\n");
+            ast_value_delete(var);
             return false;
+        }
 
-        /* Constant assignment */
-        if (!parser_next(parser))
+        if (isfunc) {
+            /* a function was defined */
+            ast_value *fval;
+
+            /* turn var into a value of TYPE_FUNCTION, with the old var
+             * as return type
+             */
+            fval = ast_value_new(ctx, var->name, TYPE_FUNCTION);
+            func = ast_function_new(ctx, var->name, fval);
+            if (!fval || !func) {
+                ast_value_delete(var);
+                if (fval) ast_value_delete(fval);
+                if (func) ast_function_delete(func);
+                return false;
+            }
+
+            fval->expression.next = (ast_expression*)var;
+            MEM_VECTOR_MOVE(var, params, fval, 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;
+            }
+
+            var = fval;
+        }
+
+        if (!parser_t_globals_add(parser, var) ||
+            !parser_next(parser))
+        {
+            ast_value_delete(var);
             return false;
+        }
 
-        if (parser->tok == ';')
-            return parser_next(parser);
+        if (parser->tok == ';') {
+            if (!parser_next(parser))
+                return parser->tok == TOKEN_EOF;
+            return true;
+        }
 
         if (parser->tok != '=') {
             parseerror(parser, "expected '=' or ';'");
             return false;
         }
 
-        /* '=' found, assign... */
-        parseerror(parser, "TODO, const assignment");
-        return false;
+        if (!parser_next(parser))
+            return false;
+
+        if (parser->tok == '#') {
+            if (!isfunc || !func) {
+                parseerror(parser, "unexpected builtin number, '%s' is not a function", var->name);
+                return false;
+            }
+            if (!parser_next(parser)) {
+                parseerror(parser, "expected builtin number");
+                return false;
+            }
+            if (parser->tok != TOKEN_INTCONST) {
+                parseerror(parser, "builtin number must be an integer constant");
+                return false;
+            }
+            if (parser_token(parser)->constval.i <= 0) {
+                parseerror(parser, "builtin number must be positive integer greater than zero");
+                return false;
+            }
+
+            func->builtin = -parser_token(parser)->constval.i;
+        } else if (parser->tok == '{') {
+            /* function body */
+            bool ret;
+            ast_function *old = parser->function;
+            parser->function = func;
+            ret = parser_parse_body(parser);
+            parser->function = old;
+            return ret;
+        } else {
+            parseerror(parser, "TODO, const assignment");
+        }
+
+        if (!parser_next(parser))
+            return false;
+
+        if (parser->tok != ';') {
+            parseerror(parser, "expected semicolon");
+            return false;
+        }
+
+        (void)parser_next(parser);
+
+        return true;
     }
     else if (parser->tok == TOKEN_KEYWORD)
     {
@@ -125,11 +282,14 @@ bool parser_compile(const char *filename)
 {
     size_t i;
     parser_t *parser;
+    ir_builder *ir;
 
     parser = (parser_t*)mem_a(sizeof(parser_t));
     if (!parser)
         return false;
 
+    memset(&parser, 0, sizeof(parser));
+
     MEM_VECTOR_INIT(parser, globals);
     parser->lex = lex_open(filename);
 
@@ -147,8 +307,9 @@ bool parser_compile(const char *filename)
         {
             if (!parser_do(parser)) {
                 if (parser->tok == TOKEN_EOF)
-                    break;
-                printf("parse error\n");
+                    parseerror(parser, "unexpected eof");
+                else
+                    parseerror(parser, "parse error\n");
                 lex_close(parser->lex);
                 mem_d(parser);
                 return false;
@@ -157,6 +318,30 @@ bool parser_compile(const char *filename)
     }
 
     lex_close(parser->lex);
+
+    ir = ir_builder_new("gmqcc_out");
+    if (!ir) {
+        printf("failed to allocate builder\n");
+        goto cleanup;
+    }
+
+    for (i = 0; i < parser->globals_count; ++i) {
+        if (!ast_global_codegen(parser->globals[i], ir)) {
+            printf("failed to generate global %s\n", parser->globals[i]->name);
+        }
+    }
+    for (i = 0; i < parser->functions_count; ++i) {
+        if (!ast_function_codegen(parser->functions[i], ir)) {
+            printf("failed to generate function %s\n", parser->functions[i]->name);
+        }
+        if (!ir_function_finalize(parser->functions[i]->ir_func)) {
+            printf("failed to finalize function %s\n", parser->functions[i]->name);
+        }
+    }
+
+    ir_builder_dump(ir, printf);
+
+cleanup:
     for (i = 0; i < parser->globals_count; ++i) {
         ast_value_delete(parser->globals[i]);
     }