]> git.mdlowis.com Git - proto/sclpl.git/commitdiff
Reworked codegenerator to generate to file or standard output
authorMichael D. Lowis <mike@mdlowis.com>
Wed, 22 Oct 2014 02:20:55 +0000 (22:20 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Wed, 22 Oct 2014 02:20:55 +0000 (22:20 -0400)
source/sclpl/codegen.c
source/sclpl/main.c

index 14ac3322fad7444e7701a07f006afdc3a3ca6597..31d286530e803fd475679e6282d6a20ae7c64c8a 100644 (file)
@@ -79,185 +79,187 @@ static size_t get_fn_id(vec_t* funcs, tree_t* fn) {
 
 /*****************************************************************************/
 
-static void print_indent(int depth) {
+static void print_indent(FILE* file, int depth) {
     for(int i = 0; i < (4 * depth); i++)
-        printf("%c", ' ');
+        fprintf(file, "%c", ' ');
 }
 
-static void print_char(char ch) {
+static void print_char(FILE* file, char ch) {
     switch (ch) {
-        case '\r': printf("__char('\\r')");    break;
-        case '\n': printf("__char('\\n')");    break;
-        case '\t': printf("__char('\\t')");    break;
-        case '\v': printf("__char('\\v')");    break;
-        default:   printf("__char('%c')", ch); break;
+        case '\r': fprintf(file, "__char('\\r')");    break;
+        case '\n': fprintf(file, "__char('\\n')");    break;
+        case '\t': fprintf(file, "__char('\\t')");    break;
+        case '\v': fprintf(file, "__char('\\v')");    break;
+        default:   fprintf(file, "__char('%c')", ch); break;
     }
 }
 
-static void print_string(const char* str) {
-    printf("__string(\"");
+static void print_string(FILE* file, const char* str) {
+    fprintf(file, "__string(\"");
     while('\0' != str[0])
     {
         switch (str[0]) {
-            case '\r': printf("\\r");        break;
-            case '\n': printf("\\n");        break;
-            case '\t': printf("\\t");        break;
-            case '\v': printf("\\v");        break;
-            default:   printf("%c", str[0]); break;
+            case '\r': fprintf(file, "\\r");        break;
+            case '\n': fprintf(file, "\\n");        break;
+            case '\t': fprintf(file, "\\t");        break;
+            case '\v': fprintf(file, "\\v");        break;
+            default:   fprintf(file, "%c", str[0]); break;
         }
         str++;
     }
-    printf("\")");
+    fprintf(file, "\")");
 }
 
 /*****************************************************************************/
 
-static void emit_header(void) {
-    puts("#include <sclpl.h>\n");
+static void emit_header(FILE* file) {
+    fputs("#include <sclpl.h>\n\n", file);
 }
 
-static void emit_fn_signature(char* name, tree_t* fnval) {
-    printf("_Value %s(", name);
+static void emit_fn_signature(FILE* file, char* name, tree_t* fnval) {
+    fprintf(file, "_Value %s(", name);
     vec_t* params = get_child(fnval, 1)->ptr.vec;
     for (size_t i = 0; i < vec_size(params); i++) {
-        printf("_Value %s", (char*)get_val((tree_t*)vec_at(params,i)));
+        fprintf(file, "_Value %s", (char*)get_val((tree_t*)vec_at(params,i)));
         if (i+1 < vec_size(params))
-            printf(", ");
+            fprintf(file, ", ");
     }
-    printf(")");
+    fprintf(file, ")");
 }
 
-static void emit_def_placeholders(vec_t* prgrm) {
+static void emit_def_placeholders(FILE* file, vec_t* prgrm) {
     for (size_t idx = 0; idx < vec_size(prgrm); idx++) {
         tree_t* p_tree = (tree_t*)vec_at(prgrm, idx);
         if (is_formtype(p_tree, "def")) {
-            printf("_Value %s;\n", (char*)get_child_val(p_tree,1));
+            fprintf(file, "_Value %s;\n", (char*)get_child_val(p_tree,1));
         }
     }
-    puts("");
+    fputs("\n", file);
 }
 
-static void emit_expression(vec_t* fnlst, tree_t* p_tree, int depth) {
+static void emit_expression(FILE* file, vec_t* fnlst, tree_t* p_tree, int depth) {
     if (p_tree->tag == ATOM) {
         lex_tok_t* tok = p_tree->ptr.tok;
         switch (tok->type) {
-            case T_STRING: print_string(((char*)tok->value));                        break;
-            case T_CHAR:   print_char(((char)(int)tok->value));                      break;
-            case T_INT:    printf("__int(%ld)",   *((long int*)tok->value));         break;
-            case T_FLOAT:  printf("__float(%f)",  *((double*)tok->value));           break;
-            case T_BOOL:   printf("__bool(%s)",   ((int)tok->value)?"true":"false"); break;
-            case T_VAR:    printf("%s",           ((char*)tok->value));              break;
-            default:                                                                 break;
+            case T_STRING: print_string(file, ((char*)tok->value));                         break;
+            case T_CHAR:   print_char(file, ((char)(int)tok->value));                       break;
+            case T_INT:    fprintf(file, "__int(%ld)",   *((long int*)tok->value));         break;
+            case T_FLOAT:  fprintf(file, "__float(%f)",  *((double*)tok->value));           break;
+            case T_BOOL:   fprintf(file, "__bool(%s)",   ((int)tok->value)?"true":"false"); break;
+            case T_VAR:    fprintf(file, "%s",           ((char*)tok->value));              break;
+            default:                                                                        break;
         }
     } else if (is_formtype(p_tree, "if")) {
-        printf("IF (");
-        emit_expression(fnlst, get_child(p_tree, 1), depth);
-        printf(")\n");
-        print_indent(depth+1);
-        emit_expression(fnlst, get_child(p_tree, 2), depth+1);
-        printf("\n");
-        print_indent(depth);
-        printf("ELSE\n");
-        print_indent(depth+1);
+        fprintf(file, "IF (");
+        emit_expression(file, fnlst, get_child(p_tree, 1), depth);
+        fprintf(file, ")\n");
+        print_indent(file, depth+1);
+        emit_expression(file, fnlst, get_child(p_tree, 2), depth+1);
+        fprintf(file, "\n");
+        print_indent(file, depth);
+        fprintf(file, "ELSE\n");
+        print_indent(file, depth+1);
         if (vec_size(p_tree->ptr.vec) > 3) {
-            emit_expression(fnlst, get_child(p_tree, 4), depth+1);
+            emit_expression(file, fnlst, get_child(p_tree, 4), depth+1);
         } else {
-            printf("NIL");
+            fprintf(file, "__nil");
         }
 
     } else if (is_formtype(p_tree, "fn")) {
-        printf("__func(&fn%d)", (int)get_fn_id(fnlst, p_tree));
+        fprintf(file, "__func(&fn%d)", (int)get_fn_id(fnlst, p_tree));
     } else {
         vec_t* vec   = p_tree->ptr.vec;
         int nargs = vec_size(vec)-1;
         /* Determine the calling convention based on number of args */
         if (0 == nargs)
-            printf("__call0(%s", (char*)get_val(vec_at(vec,0)));
+            fprintf(file, "__call0(%s", (char*)get_val(vec_at(vec,0)));
         else if (nargs < 16)
-            printf("__calln(%s, %d, ", (char*)get_val(vec_at(vec,0)), (int)nargs);
+            fprintf(file, "__calln(%s, %d, ", (char*)get_val(vec_at(vec,0)), (int)nargs);
         else
-            printf("__calln(%s, n, ", (char*)get_val(vec_at(vec,0)));
+            fprintf(file, "__calln(%s, n, ", (char*)get_val(vec_at(vec,0)));
         /* Print out the arguments */
         for (size_t idx = 1; idx < vec_size(vec); idx++) {
-            emit_expression(fnlst, (tree_t*)vec_at(vec,idx), depth);
+            emit_expression(file, fnlst, (tree_t*)vec_at(vec,idx), depth);
             if (idx+1 < vec_size(vec))
-                printf(", ");
+                fprintf(file, ", ");
         }
-        printf(")");
+        fprintf(file, ")");
     }
 }
 
-static void emit_fn_declarations(vec_t* fnlst) {
+static void emit_fn_declarations(FILE* file, vec_t* fnlst) {
     char name[64];
     for (size_t idx = 0; idx < vec_size(fnlst); idx++) {
         sprintf(name,"fn%d", (int)idx);
-        printf("static ");
-        emit_fn_signature(name, (tree_t*)vec_at(fnlst,idx));
-        puts(";");
+        fprintf(file, "static ");
+        emit_fn_signature(file, name, (tree_t*)vec_at(fnlst,idx));
+        fputs(";\n", file);
     }
-    puts("");
+    fputs("\n", file);
 }
 
-static void emit_fn_definitions(vec_t* fnlst) {
+static void emit_fn_definitions(FILE* file, vec_t* fnlst) {
     char name[64];
     for (size_t idx = 0; idx < vec_size(fnlst); idx++) {
         tree_t* func = (tree_t*)vec_at(fnlst,idx);
         sprintf(name,"fn%d", (int)idx);
-        printf("static ");
-        emit_fn_signature(name, func);
-        puts(" {");
+        fprintf(file, "static ");
+        emit_fn_signature(file, name, func);
+        fputs(" {\n", file);
 
         vec_t* body = (vec_t*)func->ptr.vec;
         for (size_t i = 2; i < vec_size(body); i++) {
-            printf("    ");
+            fprintf(file, "    ");
             if (i+1 == vec_size(body))
-                printf("return ");
-            emit_expression(fnlst, (tree_t*)vec_at(body,i), 1);
-            printf(";\n");
+                fprintf(file, "return ");
+            emit_expression(file, fnlst, (tree_t*)vec_at(body,i), 1);
+            fprintf(file, ";\n");
         }
-        puts("}\n");
+        fputs("}\n", file);
     }
+    fputs("\n", file);
 }
 
-static void emit_toplevel(vec_t* fnlst, vec_t* prgrm) {
-    puts("void toplevel(void) {");
+static void emit_toplevel(FILE* file, vec_t* fnlst, vec_t* prgrm) {
+    fputs("void toplevel(void) {\n", file);
     for (size_t idx = 0; idx < vec_size(prgrm); idx++) {
         tree_t* p_tree = (tree_t*)vec_at(prgrm, idx);
         if (is_formtype(p_tree, "require")) {
-            printf("    extern void %s_toplevel(void);\n", (char*)get_child_val(p_tree,1));
-            printf("    %s_toplevel();\n", (char*)get_child_val(p_tree,1));
+            fprintf(file, "    extern void %s_toplevel(void);\n", (char*)get_child_val(p_tree,1));
+            fprintf(file, "    %s_toplevel();\n", (char*)get_child_val(p_tree,1));
         } else if (is_formtype(p_tree, "def")) {
-            printf("    %s = ", (char*)get_child_val(p_tree,1));
-            emit_expression(fnlst, get_child(p_tree, 2), 0);
-            printf(";\n");
+            fprintf(file, "    %s = ", (char*)get_child_val(p_tree,1));
+            emit_expression(file, fnlst, get_child(p_tree, 2), 0);
+            fprintf(file, ";\n");
         } else {
-            printf("    (void)(");
-            emit_expression(fnlst, p_tree, 1);
-            printf(");\n");
+            fprintf(file, "    (void)(");
+            emit_expression(file, fnlst, p_tree, 1);
+            fprintf(file, ");\n");
         }
     }
-    puts("}");
+    fputs("}\n", file);
 }
 
-static void emit_footer(void) {
-    puts(
+static void emit_footer(FILE* file) {
+    fputs(
         "\nint main(int argc, char** argv) {"
         "\n    (void)argc;"
         "\n    (void)argv;"
         "\n    toplevel();"
         "\n    return 0;"
-        "\n}"
+        "\n}\n",
+        file
     );
 }
 
 void codegen_csource(FILE* file, vec_t* program) {
     (void)file;
-    emit_header();
-    emit_def_placeholders(program);
+    emit_header(file);
+    emit_def_placeholders(file, program);
     vec_t* funcs = find_fn_literals(program);
-    emit_fn_declarations(funcs);
-    emit_fn_definitions(funcs);
-    emit_toplevel(funcs, program);
+    emit_fn_declarations(file, funcs);
+    emit_fn_definitions(file, funcs);
+    emit_toplevel(file, funcs, program);
     mem_release(funcs);
-    emit_footer();
+    emit_footer(file);
 }
index 6ebb8f5e34dfd76b8fe695c7f621c81effe8f829..0b92afa5ba5b82bb0da367c2283609058be3e784 100644 (file)
@@ -2,6 +2,8 @@
 #include <stdlib.h>
 #include <stddef.h>
 #include "opts.h"
+#include "str.h"
+#include "list.h"
 #include "grammar.h"
 #include "parser.h"
 #include "lexer.h"
@@ -99,6 +101,92 @@ tree_t* convert_to_ast(tree_t* p_tree) {
     return p_newtree;
 }
 
+/* Options Helpers
+ *****************************************************************************/
+bool file_exists(const char* name) {
+    bool  ret  = false;
+    FILE* file = fopen(name,"r");
+    if (NULL != file) {
+        fclose(file);
+        ret = true;
+    }
+    return ret;
+}
+
+list_t* input_files(void) {
+    list_t* infiles = list_new();
+    const char** files = opts_arguments();
+    while (NULL != files[0]) {
+        if (!file_exists(files[0])) {
+            mem_release(infiles);
+            fprintf(stderr, "Error: no such file or directory: %s\n", files[0]);
+            exit(1);
+        }
+        list_push_front(infiles, str_new(files[0]));
+        files++;
+    }
+    mem_release(list_pop_front(infiles));
+    return infiles;
+}
+
+/* Utility Functions
+ *****************************************************************************/
+typedef enum {
+    CSOURCE,
+    OBJECT,
+    PROGRAM,
+    STATICLIB,
+    SHAREDLIB
+} file_type_t;
+
+str_t* get_filename(file_type_t ftype, str_t* infile) {
+    str_t* ext_ind = str_new(".");
+    size_t index   = str_rfind(infile, ext_ind);
+    str_t* rawname = str_substr(infile, 0, str_size(infile)-index);
+    str_t* ext;
+    switch (ftype) {
+        case CSOURCE:   ext = str_new(".c");   break;
+        case OBJECT:    ext = str_new(".o");   break;
+        case PROGRAM:   ext = str_new("");     break;
+        case STATICLIB: ext = str_new(".a");   break;
+        case SHAREDLIB: ext = str_new(".lib"); break;
+    }
+    str_t* fname = str_concat(rawname, ext);
+    mem_release(ext_ind);
+    mem_release(rawname);
+    mem_release(ext);
+    return fname;
+}
+
+int translate(str_t* in, str_t* out) {
+    int ret = 0;
+    FILE* input  = (NULL == in)  ? stdin  : fopen(str_cstr(in), "r");
+    FILE* output = (NULL == out) ? stdout : fopen(str_cstr(out), "w");
+
+    parser_t* p_parser = parser_new(NULL, input);
+    vec_t* p_vec = vec_new(0);
+    while(!parser_eof(p_parser)) {
+        tree_t* p_tree = grammar_toplevel(p_parser);
+        if (NULL != p_tree) {
+            tree_t* p_ast = convert_to_ast(p_tree);
+            mem_release(p_tree);
+            vec_push_back(p_vec, p_ast);
+        } else {
+            parser_resume(p_parser);
+            ret = 1;
+        }
+    }
+    if (0 == ret)
+        codegen_csource(output, p_vec);
+    mem_release(p_vec);
+    mem_release(p_parser);
+
+    fclose(input);
+    fclose(output);
+    mem_release(out);
+    return ret;
+}
+
 /* Driver Modes
  *****************************************************************************/
 static int emit_tokens(void) {
@@ -133,23 +221,19 @@ static int emit_tree(void) {
 
 static int emit_csource(void) {
     int ret = 0;
-    parser_t* p_parser = parser_new(NULL, stdin);
-    vec_t* p_vec = vec_new(0);
-    while(!parser_eof(p_parser)) {
-        tree_t* p_tree = grammar_toplevel(p_parser);
-        if (NULL != p_tree) {
-            tree_t* p_ast = convert_to_ast(p_tree);
-            mem_release(p_tree);
-            vec_push_back(p_vec, p_ast);
-        } else {
-            parser_resume(p_parser);
-            ret = 1;
+    list_t* files = input_files();
+    size_t  size  = list_size(files);
+    if (0 == size) {
+        translate(NULL, NULL);
+    } else {
+        list_node_t* node = NULL;
+        while (NULL != (node = list_pop_front(files))) {
+            str_t* fname = (str_t*)node->contents;
+            ret = translate(fname, get_filename(CSOURCE, fname));
+            mem_release(node);
         }
     }
-    if (0 == ret)
-        codegen_csource(stdout, p_vec);
-    mem_release(p_vec);
-    mem_release(p_parser);
+    mem_release(files);
     return ret;
 }
 
@@ -194,6 +278,8 @@ static int emit_program(void) {
 int main(int argc, char **argv) {
     opts_parse( Options_Config, argc, argv );
 
+    mem_release(input_files());
+
     if (!opts_is_set(NULL,"mode")) {
         print_usage();
     } else if(opts_equal(NULL, "mode", "repl")) {