Skip to content

Instantly share code, notes, and snippets.

@Chubek
Last active September 24, 2023 17:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Chubek/d7e5eb46c956d15754c7e93d397aeec4 to your computer and use it in GitHub Desktop.
Save Chubek/d7e5eb46c956d15754c7e93d397aeec4 to your computer and use it in GitHub Desktop.
leg(1) grammar for simple numerical expressions

eval.leg.y contains leg(1) grammar for simple numerical expressions --- excluding identifiers. Just numbers. It supports floats, and the 4 radices of integer commonly in use. Although that there won't be any parsing errors when floats are passed to non-compliant operators, your C runtime will definitely glitch out so be mindful.

But it also bootstraps the YY_INPUT through stdin by making a temporary file and using freopen(3) to reopen stdin within that buffer --- after of course having dumped the input and the sentinel (;) into it. Perhaps this part can be redone. I will update it later in the future to fix this issue.

To use this grammar (after installing leg(1) which comes bundled with peg(1), from here --- mind you that most Debian package managers have it, try sudo apt-get install peg first):

wget -qO- https://gist.githubusercontent.com/Chubek/d7e5eb46c956d15754c7e93d397aeec4/raw/1a549e45b3996e7c57a896c356b2eae0a3843dea/eval.leg.y | leg -o _eval.yy.c

You may use it like this:

#include "_eval.yy.c"
#include <stdio.h>
#include <string.h>

int main (int argc, int8_t **argv)
{
	write_to_parser(argv[1]);
	while (yyparse());
	printf("%ld", (long)yyfinal);
	close_redir();
}

To run a quick test using tcc(1):

cat _test.c |  tcc -run - 1+1

It is not fully tested. It may run into left recursion --- IT MAY. But PEG grammars are usually less prone to left recursion than their EBNF counterparts (when the EBNF gets shoddily translated into LL(1) anyways, quite honestly, use cases of LL(1) are small).

My Discord is .chubak. My email is chubakbidpaa@gmail.com. Thank you.

%{
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
static int64_t yyfinal;
%}
Expr = LPAREN? (i:Logical* | . ) RPAREN? EOI { yyfinal = i; }
Logical = l:Bitwise
( - '&&' - r:Bitwise { l = l && r; }
| - '||' - r:Bitwise { l = l || r; }
)* { $$ = l; }
Bitwise = l:Equalal
( - '&' - r:Equalal { l &= r; }
| - '|' - r:Equalal { l |= r; }
| - '^' - r:Equalal { l ^= r; }
)* { $$ = l; }
Equalal = l:Relal
( - '==' - r:Relal { l = l == r; }
| - '!=' - r:Relal { l = l != r; }
)* { $$ = l; }
Relal = l:Shiftive
( -'<' - r:Shiftive { l = l < r; }
| - '>' - r:Shiftive { l = l > r; }
| - '>=' - r:Shiftive { l = l >= r; }
| - '<=' - r:Shiftive { l = l <= r; }
)* { $$ = l; }
Shiftive = l:Additive
( - '>>' - r:Additive { l >>= r; }
| - '<<' - r:Additive { l <<= r; }
)* { $$ = l; }
Additive = l:Multive
( - '+' - r:Multive { l += r; }
| - '-' - r:Multive { l -= r; }
)* { $$ = l; }
Multive = l:Unary
( - '*' - r:Unary { l *= r; }
| - '/' - r:Unary { l /= r; }
)* { $$ = l; }
Unary = i:Value { $$ = i; }
| '++' i:Value { $$ = i + 1; }
| '--' i:Value { $$ = i - 1; }
| '-' i:Value { $$ = -1 * i; }
| '!' i:Value { $$ = i & 0; }
| '~' i:Value { $$ = i ^ i; }
Value = - i:INT - { $$ = i; }
| - f:FLT - { $$ = f; }
| LPAREN res:Expr RPAREN { $$ = res; }
FLT = - < ("-"|"+")?[0-9]*("."|"e"|"E")[0-9]+ > - { $$ = strtold(yytext, NULL);; }
INT = - < ("-"|"+")?[1-9][0-9]* > - { $$ = strtoll(yytext, NULL, 10); }
| - < ("0x"|"0X")[a-fA-F0-9]+ > - { $$ = strtoll(yytext, NULL, 16); }
| - < ("0o"|"0O")[0-7]+ > - { $$ = strtoll(yytext, NULL, 8); }
| - < ("0b"|"0B")[0-1]+ > - { $$ = strtoll(yytext, NULL, 2); }
RPAREN = - ')' -
LPAREN = - '(' -
- = [ \t]*
EOI = ";"
%%
FILE *redir;
char *tmp = "XXXXaa";
static inline void
write_to_parser(const int8_t *yystr)
{
mkstemp(tmp); redir = fopen(tmp, "w");
fputs(yystr, redir); fputc(';', redir);
fclose(redir); redir = freopen(tmp, "r", stdin);
}
static inline void
close_redir(void)
{
fclose(redir); unlink(tmp);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment