aboutsummaryrefslogtreecommitdiff
path: root/lr-parser.c
diff options
context:
space:
mode:
authorkartofen <kartofen.mail.0@protonmail.com>2025-09-13 15:24:28 +0300
committerkartofen <kartofen.mail.0@protonmail.com>2025-09-13 15:24:28 +0300
commitdb1b9c8dcb0d115217a33c2fe8e0760d49143e11 (patch)
treec93743adff3d78ea066c14879b7d2bfeb3ce42fb /lr-parser.c
parent46e786db9d1b48b8fbc3502e36f093b755f3e09f (diff)
ast nearly build and proper errors
Diffstat (limited to 'lr-parser.c')
-rw-r--r--lr-parser.c117
1 files changed, 76 insertions, 41 deletions
diff --git a/lr-parser.c b/lr-parser.c
index 336c222..a909f7f 100644
--- a/lr-parser.c
+++ b/lr-parser.c
@@ -12,84 +12,118 @@
#include "parts/table.h"
#include "parts/toklist.h"
// and
-typedef intptr_t (*semantic_action_fn)(intmax_t *stack_head);
+typedef stack_item (*semantic_action_fn)(stack_item *item_head);
extern semantic_action_fn *semantic_actions;
-typedef intmax_t stack_item;
-
#define STACK_CAP 128
-static stack_item stack_bottom[STACK_CAP];
-static stack_item *stack_head = stack_bottom;
+static stack_item item_bottom[STACK_CAP];
+static stack_item *item_head = item_bottom;
+
+static int state_bottom[STACK_CAP];
+static int *state_head = state_bottom;
static void print_stack()
{
fprintf(stderr, "STACK: { ");
- for(stack_item *s = stack_bottom+1; s <= stack_head; s += 3)
+ for(int *s = state_bottom+1; s <= state_head; s += 2)
fprintf(stderr, "%s ", symbol_to_str[*(symbol *)s]);
fprintf(stderr, "}\n\n");
}
-int lr_parser(intptr_t *value)
+struct lr_errinfo {
+ enum lr_errtype { LR_ERR_STACKCAP_EXCEEDED, LR_ERR_UNEXPECTED_SYMBOL, LR_ERR_NO_GOTO_ENTRY } type;
+ union {
+ size_t stack_cap;
+ struct { symbol sym; size_t state; } idx;
+ };
+};
+
+struct lr_errinfo *lr_parser(void *value)
{
-#define push(item) do { \
- if(++stack_head - stack_bottom < STACK_CAP ) *stack_head = item; \
- else { fprintf(stderr, "ERROR: STACK_CAP exceeded\n"); print_stack(); return 1; } \
+ static struct lr_errinfo errinfo;
+
+#define push(stack_head, stack_bottom, item) do { \
+ if(++stack_head - stack_bottom < STACK_CAP ) *stack_head = item; \
+ else { errinfo = (struct lr_errinfo){.type = LR_ERR_STACKCAP_EXCEEDED, .stack_cap = STACK_CAP }; return &errinfo; } \
} while(0)
-#define pop() (--stack_head)
+#define pop(stack_head) (--stack_head)
+
+#define spush(item) push(state_head, state_bottom, item)
+#define spop() pop(state_head)
+#define ipush(item) push(item_head, item_bottom, item)
+#define ipop() pop(item_head)
+
#define eat() toklist_eat()
#define peek() toklist_peek()
while(1) {
- struct action a = table[(size_t)*stack_head][token_sym(peek())];
+ struct action a = table[(size_t)*state_head][token_sym(peek())];
switch(a.type) {
case ACTION_SHIFT:;
struct token *t = eat();
- push(token_sym(t));
- push(token_val(t));
- push(a.arg);
+ ipush(*(stack_item*)token_val(t));
+ spush(token_sym(t));
+ spush(a.arg);
#ifdef _LR_PARSER_DEBUG
fprintf(stderr, "SHIFT %s\n", symbol_to_str[token_sym(t)]);
print_stack();
#endif
break;
case ACTION_REDUCE:
- intptr_t semantic_value = semantic_actions[a.arg](stack_head);
- for(size_t i = 0; i < 3*grammar[a.arg].nRHS; i++) pop();
+ stack_item semantic_value = semantic_actions[a.arg](item_head);
+ for(size_t i = 0; i < grammar[a.arg].nRHS; i++) {
+ ipop(); spop(); spop();
+ }
symbol lhs = grammar[a.arg].LHS;
- struct action a_goto = table[(size_t)*stack_head][lhs];
+ struct action a_goto = table[(size_t)*state_head][lhs];
if(a_goto.type != ACTION_GOTO) {
- fprintf(stderr,
- "ERROR: Expected goto action for token '%d' at state %zu\n",
- lhs, (size_t)*stack_head);
- return 1;
+ errinfo = (struct lr_errinfo){.type = LR_ERR_NO_GOTO_ENTRY, .idx = {lhs, (size_t)*state_head}};
+ return &errinfo;
}
- push(lhs);
- push(semantic_value);
- push(a_goto.arg);
+ ipush(semantic_value);
+ spush(lhs);
+ spush(a_goto.arg);
#ifdef _LR_PARSER_DEBUG
fprintf(stderr, "READUCE %s\n", symbol_to_str[lhs]);
+ print_stack();
#endif
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;
+ ipush((stack_item){0});
+ spush(0); spush(0);
+ // todo: better fix for reducing the final production expecting an END_INPUT on the stack
+ *(stack_item *)value = semantic_actions[0](item_head);
+ return NULL;
case ACTION_NOT_SET:
default:
- fprintf(stderr,
- "ERROR: Unexpected symbol '%s' at state %zu\n",
- symbol_to_str[token_sym(peek())], (size_t)*stack_head);
- // Expected ...
- print_stack();
- return 1;
+ errinfo = (struct lr_errinfo){.type = LR_ERR_UNEXPECTED_SYMBOL, .idx = {token_sym(peek()), (size_t)*state_head}};
+ return &errinfo;
}
}
+}
+
+char *lr_err_str(struct lr_errinfo *errinfo)
+{
+ // TODO: check if strbuf cap is exceeded
+ static char strbuf[128];
+
+ switch(errinfo->type) {
+ case LR_ERR_STACKCAP_EXCEEDED:
+ snprintf(strbuf, sizeof(strbuf), "LR parser stack capacity of %zu has been exceeded", errinfo->stack_cap);
+ break;
+ case LR_ERR_UNEXPECTED_SYMBOL:
+ snprintf(strbuf, sizeof(strbuf), "Unexpected symbol '%s' at state '%zu'", symbol_to_str[errinfo->idx.sym], errinfo->idx.state);
+ break;
+ case LR_ERR_NO_GOTO_ENTRY:
+ snprintf(strbuf, sizeof(strbuf), "No GOTO state for symbol '%s' at state '%zu'", symbol_to_str[errinfo->idx.sym], errinfo->idx.state);
+ break;
+ }
- return 1;
+ return strbuf;
}
#ifdef _LR_PARSER_STANDALONE
@@ -107,6 +141,7 @@ enum symbol {
SYMBOLS_END,
};
+char **symbol_to_str = (char*[]){"+", "-", "(", ")", "0", "1", "IN_END", "EP", "E", "T", "N", "S_END"};
size_t total_symbols = SYMBOLS_END;
IMPLEMENT_FUNCPTR(int, symbol_is_valid, (symbol s)) { return s < SYMBOLS_END; }
@@ -152,7 +187,7 @@ size_t table_states = 13;
// implement toklist.h
struct token {
symbol s;
- int v;
+ intmax_t v;
};
static struct token toklist[] = {{N0, 0}, {PLUS, 0}, {N1, 0}, {END_INPUT, 0}};
@@ -167,18 +202,18 @@ struct token *toklist_eat()
}
struct token *toklist_peek() { return toklist + tok; }
-symbol token_sym(struct token *t) { return t->s; }
-int token_val(struct token *t) { return t->v; }
+symbol token_sym(struct token *t) { return t->s; }
+intptr_t token_val(struct token *t) { return (intptr_t)&t->v; }
-intptr_t none(intmax_t *stack_head) {(void)stack_head; return 0;}
+intmax_t none(intmax_t *stack_head) {(void)stack_head; return 0;}
semantic_action_fn *semantic_actions = (semantic_action_fn[]){none, none, none, none, none, none, none, none};
int main(void)
{
- intptr_t value;
+ intmax_t value;
if(lr_parser(&value)) return 1;
- printf("%jd\n", value);
+ printf("%ld\n", value);
return 0;
}