Skip to content

Instantly share code, notes, and snippets.

@keleshev
Last active September 27, 2024 08:13
Show Gist options
  • Save keleshev/cdd6d3d46437284b2a0c2fc42cf90e0f to your computer and use it in GitHub Desktop.
Save keleshev/cdd6d3d46437284b2a0c2fc42cf90e0f to your computer and use it in GitHub Desktop.
%{
#include <stdio.h>
#include "parser.h"
%}
%%
[ \r\n\t]* { continue; /* Skip blanks. */ }
[0-9]+ { sscanf(yytext, "%d", &yylval->value);
return TOKEN_NUMBER; }
"*" { return TOKEN_STAR; }
"+" { return TOKEN_PLUS; }
"(" { return TOKEN_LPAREN; }
")" { return TOKEN_RPAREN; }
. { continue; /* Ignore unexpected characters. */}
#include <stdio.h>
#include "parser.h"
#include "lexer.h"
int yyparse(yyscan_t scanner);
int compile(const char *source) {
yyscan_t scanner;
YY_BUFFER_STATE state;
if (yylex_init(&scanner)) {
return 1; /* could not initialize */
}
state = yy_scan_string(source, scanner);
if (yyparse(scanner)) {
return 2; /* error parsing */
}
yy_delete_buffer(state, scanner);
yylex_destroy(scanner);
return 0;
}
int main(void) {
char test[] = "4 + 2*10 + 3*(5 + 1)";
int code = compile(test);
return code;
}
FILES = lexer.c parser.c main.c
main: $(FILES)
$(CC) $(CFLAGS) $(FILES) -o main
lexer.c lexer.h: lexer.l
flex --outfile=lexer.c --header-file=lexer.h --nodefault \
--reentrant --bison-bridge --nounistd --noyywrap --never-interactive --warn Lexer.l
parser.c parser.h: parser.y lexer.c
bison --output=parser.c --defines=parser.h parser.y
clean:
rm -f *.o *~ lexer.c lexer.h parser.c parser.h main
%{
#include "parser.h"
#include "lexer.h"
#define emit printf
void yyerror(yyscan_t scanner, const char *msg) {
fprintf(stderr, "Error: %s\n", msg);
}
%}
%pure-parser
%lex-param { void* scanner }
%parse-param { void* scanner }
%union {
int value;
}
%token TOKEN_LPAREN "("
%token TOKEN_RPAREN ")"
%token TOKEN_PLUS "+"
%token TOKEN_STAR "*"
%token <value> TOKEN_NUMBER "number"
%type <void> input
%left "+"
%left "*"
%%
input:
{ emit(".global main\n");
emit("main:\n"); }
expr { emit(" pop %%rax\n");
emit(" ret\n"); }
expr:
"number" { emit(" push $%d\n", $1); }
| expr "+" expr { emit(" pop %%rax\n");
emit(" pop %%rbx\n");
emit(" add %%rbx, %%rax\n");
emit(" push %%rax\n"); }
| expr "*" expr { emit(" pop %%rax\n");
emit(" pop %%rbx\n");
emit(" mul %%rbx\n");
emit(" push %%rax\n"); }
| "(" expr ")" { /* No action. */ }
.global main
main:
push $4
push $2
push $10
pop %rax
pop %rbx
mul %rbx
push %rax
pop %rax
pop %rbx
add %rbx, %rax
push %rax
push $3
push $5
push $1
pop %rax
pop %rbx
add %rbx, %rax
push %rax
pop %rax
pop %rbx
mul %rbx
push %rax
pop %rax
pop %rbx
add %rbx, %rax
push %rax
pop %rax
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment