aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkartofen <kartofen.mail.0@protonmail.com>2025-08-03 23:53:24 +0300
committerkartofen <kartofen.mail.0@protonmail.com>2025-08-03 23:53:24 +0300
commit1c83c514c8108fccfec9764da5e4563b98eb871b (patch)
treeccc6657a0b24900a17cf90cfd0676c8123492566
parent059ee9afcc575572f87f224c93288e2835cd1a52 (diff)
calc implemented in my grammar
-rwxr-xr-xbuild.sh20
-rw-r--r--demos/sample-files/calc.g26
-rw-r--r--demos/sample-files/gram-defs.c71
-rw-r--r--demos/sample-files/gram-skeleton.c48
-rw-r--r--lr-parser.c1
5 files changed, 103 insertions, 63 deletions
diff --git a/build.sh b/build.sh
index e39d4b4..ea1daef 100755
--- a/build.sh
+++ b/build.sh
@@ -4,7 +4,7 @@ set -e
function log
{
- echo "-> $@"
+ >&2 echo "-> $@"
"$@"
}
@@ -70,12 +70,22 @@ shared demos/sample-files/lalr-defs
# shared demos/sample-files/calc-defs
# leak generate-parser "-o bin/calc -t lalr-table bin/calc-defs.so"
# cc demos/sample-files/calc-skeleton "" parser
-# leak parser "13*10+9" # wrong answer
+# leak parser "13*10+9"
# leak parser "-13+20"
# leak parser "1>52?2+3:53"
+# exit 0
-# --- Grammar Definitino example ---
+# --- Grammar Definition example ---
shared demos/sample-files/gram-defs
leak generate-parser "-o bin/gram -t lalr-table bin/gram-defs.so"
-cc demos/sample-files/gram-skeleton "" parser
-leak parser
+cc demos/sample-files/gram-skeleton "" gram-parser
+
+leak gram-parser < demos/sample-files/calc.g > bin/calc-gram.c
+
+shared bin/calc-gram
+leak generate-parser "-o bin/calc -t lalr-table bin/calc-gram.so"
+cc demos/sample-files/calc-skeleton "" calc-parser
+
+leak calc-parser "13*10+9"
+leak calc-parser "-13+20"
+leak calc-parser "1>52?2+3:53"
diff --git a/demos/sample-files/calc.g b/demos/sample-files/calc.g
new file mode 100644
index 0000000..804e072
--- /dev/null
+++ b/demos/sample-files/calc.g
@@ -0,0 +1,26 @@
+-terminal PLUS MINUS TIMES MORE LESS EQUA
+ LPAREN RPAREN QMARK COLON NUM;
+
+-nonterminal EP E.
+
+-left LPAREN;
+-left 5;
+-left TIMES;
+-left MINUS PLUS;
+-left MORE LESS EQUA;
+-left COLON 7;
+-left QMARK.
+
+EP: E { v = A(0); };
+
+E: E PLUS E { v = A(0) + A(2); }
+ | E MINUS E { v = A(0) - A(2); }
+ | E TIMES E { v = A(0) * A(2); }
+ | LPAREN E RPAREN { v = A(1); }
+ | MINUS E { v = - A(1); }
+ | E QMARK E COLON E { v = A(0) ? A(2) : A(4); }
+ | E QMARK E { v = A(0) ? A(2) : 0; }
+ | E MORE E { v = A(0) > A(2); }
+ | E LESS E { v = A(0) < A(2); }
+ | E EQUA E { v = A(0) == A(2); }
+ | NUM { v = A(0); }.
diff --git a/demos/sample-files/gram-defs.c b/demos/sample-files/gram-defs.c
index b93a950..49329bd 100644
--- a/demos/sample-files/gram-defs.c
+++ b/demos/sample-files/gram-defs.c
@@ -21,41 +21,42 @@ IMPLEMENT_FUNCPTR(int, symbol_is_valid, (symbol s)) { return s < SYMBOLS_END; }
#include "parts/grammar.h"
#define PROD(LHS, _, ...) {LHS, (symbol[]){__VA_ARGS__}, sizeof((symbol[]){__VA_ARGS__})/sizeof(symbol)}
-#define GRAMMAR_ACTION_DEF(X) \
- X(PROD(Sp, -->, A, B, C, END_INPUT), "") \
- \
- X(PROD(A, -->, TERMINAL, Idenlist, \
- SEMICOL, NONTERM, Idenlist, DOT), "handle_type(A(1), A(4))") \
- \
- X(PROD(B, -->, Preclist), "handle_prec(A(0));") \
- X(PROD(Preclist, -->, Prec, SEMICOL, Preclist), \
- "v = list_new_head(A(2), A(0));") \
- X(PROD(Preclist, -->, Prec, DOT), "v = A(0);") \
- X(PROD(Prec, -->, LEFT, IorNlist), \
- "v = prec_new(A(1), PRECEDENCE_LEFT_ASSOC);") \
- X(PROD(Prec, -->, RIGHT, IorNlist), \
- "v = prec_new(A(1), PRECEDENCE_RIGHT_ASSOC);") \
- \
- X(PROD(C, -->, Prodlist), "handle_prod(A(0));") \
- X(PROD(Prodlist, -->, Prod, SEMICOL, Prodlist), \
- "v = list_new_head(A(2), A(0));") \
- X(PROD(Prodlist, -->, Prod, DOT), "v = A(0);") \
- X(PROD(Prod, -->, IDEN, COLON, Actionlist), \
- "v = prod_new(A(0), A(2));") \
- X(PROD(Actionlist, -->, Idenlist, ACTION, PIPE, Actionlist), \
- "v = list_new_head(A(3), action_new(A(0), A(1)));") \
- X(PROD(Actionlist, -->, Idenlist, ACTION), \
- "v = action_new(A(0), A(1));") \
- \
- X(PROD(Idenlist, -->, IDEN, Idenlist), \
- "v = list_new_head(A(1), ptr_new(A(0)));") \
- X(PROD(Idenlist, -->, IDEN), "v = ptr_new(A(0));") \
- X(PROD(IorNlist, -->, IDEN, IorNlist), \
- "v = list_new_head(A(1), ptr_new(A(0)));") \
- X(PROD(IorNlist, -->, IDEN), "v = ptr_new(A(0));") \
- X(PROD(IorNlist, -->, NUM, IorNlist), \
- "v = list_new_head(A(1), num_new(A(0)));") \
- X(PROD(IorNlist, -->, NUM), "v = num_new(A(0));") \
+#define GRAMMAR_ACTION_DEF(X) \
+ X(PROD(Sp, -->, A, B, C, END_INPUT), "") \
+ \
+ X(PROD(A, -->, TERMINAL, Idenlist, \
+ SEMICOL, NONTERM, Idenlist, DOT), \
+ "handle_type(A(1), A(4))") \
+ \
+ X(PROD(B, -->, Preclist), "handle_prec(A(0));") \
+ X(PROD(Preclist, -->, Prec, SEMICOL, Preclist), \
+ "v = list_new_head(A(2), A(0));") \
+ X(PROD(Preclist, -->, Prec, DOT), "v = A(0);") \
+ X(PROD(Prec, -->, LEFT, IorNlist), \
+ "v = prec_new(A(1), PRECEDENCE_LEFT_ASSOC);") \
+ X(PROD(Prec, -->, RIGHT, IorNlist), \
+ "v = prec_new(A(1), PRECEDENCE_RIGHT_ASSOC);") \
+ \
+ X(PROD(C, -->, Prodlist), "handle_prod(A(0));") \
+ X(PROD(Prodlist, -->, Prod, SEMICOL, Prodlist), \
+ "v = list_new_head(A(2), A(0));") \
+ X(PROD(Prodlist, -->, Prod, DOT), "v = A(0);") \
+ X(PROD(Prod, -->, IDEN, COLON, Actionlist), \
+ "v = prod_new(A(0), A(2));") \
+ X(PROD(Actionlist, -->, Idenlist, ACTION, PIPE, Actionlist), \
+ "v = list_new_head(A(3), action_new(A(0), A(1)));") \
+ X(PROD(Actionlist, -->, Idenlist, ACTION), \
+ "v = action_new(A(0), A(1));") \
+ \
+ X(PROD(Idenlist, -->, IDEN, Idenlist), \
+ "v = list_new_head(A(1), ptr_new(A(0)));") \
+ X(PROD(Idenlist, -->, IDEN), "v = ptr_new(A(0));") \
+ X(PROD(IorNlist, -->, IDEN, IorNlist), \
+ "v = list_new_head(A(1), ptr_new(A(0)));") \
+ X(PROD(IorNlist, -->, IDEN), "v = ptr_new(A(0));") \
+ X(PROD(IorNlist, -->, NUM, IorNlist), \
+ "v = list_new_head(A(1), num_new(A(0)));") \
+ X(PROD(IorNlist, -->, NUM), "v = num_new(A(0));") \
#define X_GRAMMAR(G, A) G,
#define X_ACTION(G, A) A,
diff --git a/demos/sample-files/gram-skeleton.c b/demos/sample-files/gram-skeleton.c
index a5899ac..7a54548 100644
--- a/demos/sample-files/gram-skeleton.c
+++ b/demos/sample-files/gram-skeleton.c
@@ -4,10 +4,13 @@
#include <stdint.h>
#include <ctype.h>
+#define INPUT_CAP 4096
+#define ARENA_CAP 4096
+
#define ARENA_IMPLEMENTATION
#include "util/arena.h"
-static char buf[2048];
+static char buf[ARENA_CAP];
static struct arena_ctx global_arena;
static void *xalloc(size_t sz) {
void *addr = arena_allocate(&global_arena, sz);
@@ -55,26 +58,26 @@ struct strnptr_entry {
struct list_head *ptr_new(void *ptr)
new_entry(struct ptr_entry, entry, {
entry->data = (intptr_t)ptr;
- });
+ })
struct list_head *num_new(intmax_t num)
new_entry(struct ptr_entry, entry, {
entry->data = (num << 1) | 0x1;
- });
+ })
struct list_head *prec_new(struct list_head *idenlist, enum precedence_flag flag)
new_entry(struct prec_entry, entry, {
entry->ptrlist = idenlist;
entry->flag = flag;
- });
+ })
struct list_head *action_new(struct list_head *idenlist, char *action)
new_entry(struct strnptr_entry, entry, {
entry->str = action;
entry->ptrlist = idenlist;
- });
+ })
struct list_head *prod_new(char *iden, struct list_head *actionlist)
new_entry(struct strnptr_entry, entry, {
entry->str = iden;
entry->ptrlist = actionlist;
- });
+ })
void handle_type(struct list_head *terminals, struct list_head *nonterminals)
{
@@ -87,6 +90,8 @@ void handle_type(struct list_head *terminals, struct list_head *nonterminals)
printf("%s, ", (char *)entry->data);
printf("SYMBOLS_END };\n");
+ printf("size_t total_symbols = %zu;\n", list_len(terminals) + list_len(nonterminals) + 2);
+
printf("char **symbol_to_str = (char *([])){ ");
list_for_each_entry(struct ptr_entry, entry, list, terminals)
printf("\"%s\", ", (char *)entry->data);
@@ -99,6 +104,7 @@ void handle_type(struct list_head *terminals, struct list_head *nonterminals)
(char *)container_of(nonterminals, struct ptr_entry, list)->data);
printf("IMPLEMENT_FUNCPTR(int, symbol_is_input_end, (symbol s)) { return s == END_INPUT; }\n");
printf("IMPLEMENT_FUNCPTR(int, symbol_is_valid, (symbol s)) { return s < SYMBOLS_END; }\n");
+
}
void handle_prec(struct list_head *preclist)
@@ -128,7 +134,11 @@ void handle_prod(struct list_head *prodlist)
printf("#include \"parts/grammar.h\"\n");
printf("struct production *grammar = (struct production[]){\n");
list_for_each_entry(struct strnptr_entry, e1, list, prodlist) {
+ if(productions == 0)
+ list_add(list_get_tail(list_entry(e1->ptrlist, struct strnptr_entry, list)->ptrlist),
+ ptr_new("END_INPUT"));
productions += list_len(e1->ptrlist);
+
list_for_each_entry(struct strnptr_entry, e2, list, e1->ptrlist) {
printf("{%s, (symbol[]){ ", e1->str);
list_for_each_entry(struct ptr_entry, e3, list, e2->ptrlist)
@@ -173,21 +183,7 @@ static char *next_token(char *str);
symbol token_sym(struct token *t) { return t->s; }
intptr_t token_val(struct token *t) { return t->v; }
-static char *input = (char []){
- "-terminal ID EQUAL STAR;"
- "-nonterminal EP E L R."
- ""
- "-left ID;"
- "-right STAR;"
- "-left EQUAL."
- ""
- "EP: E END_INPUT {1};"
- "E : L EQUAL R {2}"
- " | R {3};"
- "L : STAR R {4}"
- " | ID {5};"
- "R : L {6}."
-};
+static char *input;
struct token *toklist_eat()
{
@@ -203,9 +199,15 @@ struct token *toklist_peek() { return &tok; }
int main(void)
{
- global_arena = ARENA_CTX_INIT(buf, sizeof(buf));
+ static char input_buf[INPUT_CAP];
+ if(fread(input_buf, INPUT_CAP, 1, stdin) == INPUT_CAP) {
+ fprintf(stderr, "INPUT_CAP reached\n");
+ return 1;
+ }
- input = next_token(input);
+ global_arena = ARENA_CTX_INIT(buf, ARENA_CAP);
+
+ input = next_token(input_buf);
intptr_t value;
if(lr_parser(&value)) {
diff --git a/lr-parser.c b/lr-parser.c
index 621a9e7..bca8a52 100644
--- a/lr-parser.c
+++ b/lr-parser.c
@@ -60,6 +60,7 @@ int lr_parser(intptr_t *value)
push(a_goto.arg);
break;
case ACTION_ACCEPT:
+ for(size_t i = 0; i < 3; i++) push(0); // todo: better fix for reducing the final production expecting an END_INPUT on the stack
*value = semantic_actions[0](stack_head);
return 0;
case ACTION_NOT_SET: