arithy / packcc

A parser generator for C
Other
347 stars 28 forks source link

raising error from action? #65

Closed stef closed 2 years ago

stef commented 2 years ago

It is unclear to me if it is possible to raise an error from the action. In your example calculator it would make sense for example for division by zero or (int_min / -1).

thank you for this awesome project!

arithy commented 2 years ago

Sorry for the late reply.

An error state should be introduced as a part of the value type, which is specified using %value. I show an example below. Only zero-division error is implemented here.

%prefix "calc"

%value "calc_result_t"

%header {
typedef struct calc_result_tag {
    int value;
    int error; /* 0: no error, 1 error. */
} calc_result_t;
}

%source {
#include <stdio.h>
#include <stdlib.h>

static calc_result_t calc_result_new(int value, int error) {
    calc_result_t r;
    r.value = value;
    r.error = error;
    return r;
}
}

statement <- _ e:expression _ EOL { if (e.error) printf("arithmetic error\n"); else printf("answer=%d\n", e); }
           / ( !EOL . )* EOL      { printf("syntax error\n"); }

expression <- e:term { $$ = e; }

term <- l:term _ '+' _ r:factor { $$ = calc_result_new(l.value + r.value, l.error | r.error); }
      / l:term _ '-' _ r:factor { $$ = calc_result_new(l.value - r.value, l.error | r.error); }
      / e:factor                { $$ = e; }

factor <- l:factor _ '*' _ r:unary { $$ = calc_result_new(l.value * r.value, l.error | r.error); }
        / l:factor _ '/' _ r:unary { $$ = (r.value != 0) ? calc_result_new(l.value / r.value, l.error | r.error) : calc_result_new(0, 1); }
        / e:unary                  { $$ = e; }

unary <- '+' _ e:unary { $$ = e; }
       / '-' _ e:unary { $$ = calc_result_new(-e.value, e.error); }
       / e:primary     { $$ = e; }

primary <- < [0-9]+ >               { $$ = calc_result_new(atoi($1), 0); }
         / '(' _ e:expression _ ')' { $$ = e; }

_      <- [ \t]*
EOL    <- '\n' / '\r\n' / '\r' / ';'

%%
int main() {
    calc_context_t *ctx = calc_create(NULL);
    while (calc_parse(ctx, NULL));
    calc_destroy(ctx);
    return 0;
}
stef commented 2 years ago

thank you very much, that answers my question and is a great example. thank you so much for taking the time to enlighten me! you can close this issue.