summaryrefslogtreecommitdiff
path: root/src/frontend/driver.c
diff options
context:
space:
mode:
authorbd <bdunahu@operationnull.com>2025-01-28 14:39:47 -0500
committerbd <bdunahu@operationnull.com>2025-01-28 14:39:47 -0500
commit9e09767e23a4edb6b31540195bfe885f83e080d7 (patch)
tree42454c51ea8e0c8cf90b7c9020dedf3a5627cea2 /src/frontend/driver.c
parentc63a873fe7fbf7947e07acfaf2402fe85100deba (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.c88
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);
+}