diff options
author | bd <bdunahu@operationnull.com> | 2025-01-28 14:39:47 -0500 |
---|---|---|
committer | bd <bdunahu@operationnull.com> | 2025-01-28 14:39:47 -0500 |
commit | 9e09767e23a4edb6b31540195bfe885f83e080d7 (patch) | |
tree | 42454c51ea8e0c8cf90b7c9020dedf3a5627cea2 /src/frontend/driver.c | |
parent | c63a873fe7fbf7947e07acfaf2402fe85100deba (diff) |
[Ongoing] Rewrite frontend to use Flex/Bison
This is a merge of another experiment, so the changes are large:
- separated "modules" directory into frontend/backend
- adjusted module names and moved files for this to happen
- removed modules lexer & parser
- removed all the unit tests (most were outdated)
- added Bison, flex, and C development tools to manifest.scm
- added lexer.l, a source file used by the flex utility with a functioning lexing implementation
- added parser.y, a source file used by the bison utility with a functioning parser implementation
- added node.c and node.h, which parser.y uses to construct an AST of a C source file (up to binary ops)
- added driver.c, a Guile-C interface that provides a module to scheme programs
- added a Makefile to make all of this
- added stuff to .gitignore
Diffstat (limited to 'src/frontend/driver.c')
-rw-r--r-- | src/frontend/driver.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/src/frontend/driver.c b/src/frontend/driver.c new file mode 100644 index 0000000..52eb3f4 --- /dev/null +++ b/src/frontend/driver.c @@ -0,0 +1,88 @@ +#include "lexer.h" +#include "parser.h" +#include "node.h" +#include <stdio.h> +#include <libguile.h> + +/** + * @param node a tree of node structs representing a C source file. + * @return a scheme representation of node. + */ +SCM +node_to_scm(Node *node) { + SCM ret = scm_list_1(scm_from_locale_symbol(node_types[node->type])); + + SCM field_value = SCM_BOOL_F; + switch (node->type) { + case FUNC: + field_value = scm_from_locale_string(node->field.name); + break; + case EXPR: + field_value = scm_from_locale_symbol(node_ops[node->field.op]); + break; + case CONST: + field_value = scm_from_int32(node->field.val); + break; + default: + ; + } + + if (scm_is_true(field_value)) + ret = scm_append(scm_list_2(ret, scm_list_1(field_value))); + + SCM child; + for (size_t i = 0; i < node->num_children; ++i) { + child = node_to_scm(node->children[i]); + ret = scm_append(scm_list_2(ret, scm_list_1(child))); + } + + return ret; +} + +/** \brief Parser driver for ull. + * Given F, returns an AST of the program represented as a guile s-exp, or #f on a parse error. + * if DO_PARSE is false, only performs lexing, returning #t on a success. + * @param f a preprocessed C file to parse. + * @param do_parse on false, do not perform the parsing stage. + * @return a SCM list representing the parse tree, or #t if do_parse is #f and lexing is successful, or #f otherwise. + */ +SCM +file_to_ast_wrapper(SCM f, SCM do_parse) +{ + char *file = scm_to_locale_string(f); + Node *root = NULL; + SCM ret = SCM_BOOL_F; + + yyin = fopen(file, "r"); + if (yyin != NULL){ + if (scm_is_true(do_parse)) { + if (yyparse(&root) == 0) { + ret = node_to_scm(root); + free_node(root); + } + } else { + ret = SCM_BOOL_T; + int token; + while ((token = yylex()) != 0) { + if (token == YYerror) + ret = SCM_BOOL_F; + } + } + } + + fclose(yyin); + free(file); + return ret; +} + +void +init_parser_driver() +{ + scm_c_define_gsubr("file->ast", 2, 0, 0, file_to_ast_wrapper); + scm_c_export("file->ast", NULL); +} + +void +scm_init_parser_driver_module() { + scm_c_define_module("frontend driver", init_parser_driver, NULL); +} |