diff options
| author | hachem <im@hachem.wtf> | 2026-09-19 11:17:14 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-09-19 11:17:14 +0200 |
| commit | 768bbdd137f5b205e4282bd79572681aef4514e3 (patch) | |
| tree | c249765cd8607a34443e05709ea54441bf0dfd3e | |
| parent | 08b8cbbccd8c8d7dab75746ee9d134f67455de91 (diff) | |
feat: add bison grammar for emit, decltype and difference
| -rw-r--r-- | Makefile | 17 | ||||
| -rw-r--r-- | lexer.h | 12 | ||||
| -rw-r--r-- | main.c | 45 | ||||
| -rw-r--r-- | sfinae.l | 14 | ||||
| -rw-r--r-- | sfinae.y | 64 |
5 files changed, 95 insertions, 57 deletions
@@ -1,8 +1,9 @@ CC = cc LEX = flex -CFLAGS = -std=c17 -Wall -Wextra -Werror -Wpedantic -O2 +YACC = bison +CFLAGS = -std=c17 -Wall -Wextra -Werror -Wpedantic -O2 -Ibin SOURCES = ast.c ast.h lexer.h main.c -OBJECTS = bin/lexer.o bin/ast.o bin/main.o +OBJECTS = bin/lexer.o bin/parser.o bin/ast.o bin/main.o SANITIZE = -g -O0 -fsanitize=address,undefined .PHONY: all debug check format lint clean @@ -18,13 +19,19 @@ sfinae: $(OBJECTS) bin/lexer.c: sfinae.l | bin $(LEX) -o bin/lexer.c sfinae.l -bin/lexer.o: bin/lexer.c lexer.h +bin/lexer.o: bin/lexer.c bin/parser.h ast.h lexer.h $(CC) -std=c17 -w -I. -c -o $@ bin/lexer.c +bin/parser.c bin/parser.h: sfinae.y | bin + $(YACC) -d -o bin/parser.c sfinae.y + +bin/parser.o: bin/parser.c + $(CC) -std=c17 -w -I. -c -o $@ bin/parser.c + bin/%.o: %.c | bin $(CC) $(CFLAGS) -c -o $@ $< -bin/main.o: lexer.h +bin/main.o: ast.h lexer.h bin/ast.o: ast.h lexer.h debug: CFLAGS += $(SANITIZE) @@ -40,7 +47,7 @@ format: clang-format -i $(SOURCES) lint: - clang-tidy ast.c main.c -- -std=c17 + clang-tidy ast.c main.c -- -std=c17 -Ibin clean: rm -rf bin sfinae @@ -3,20 +3,8 @@ #include <stdbool.h> #include <stdio.h> -enum Token -{ - TOK_END = 0, - TOK_COLONCOLON = 256, - TOK_EMIT, - TOK_COMMIT, - TOK_DECLTYPE, - TOK_DIFFERENCE, - TOK_CHAR -}; - extern FILE* yyin; // input extern int yylineno; // current line int yylex(void); // scanner bool lexer_failed(void); -char lexer_character(void); @@ -1,37 +1,20 @@ -#include "lexer.h" - #include <stdio.h> -static const char* token_name(int token) -{ - switch (token) - { - case TOK_COLONCOLON: return "::"; - case TOK_EMIT: return "emit"; - case TOK_COMMIT: return "commit"; - case TOK_DECLTYPE: return "decltype"; - case TOK_DIFFERENCE: return "difference"; - default: return NULL; - } -} - -static int dump_tokens(void) -{ - int token = TOK_END; +#include "ast.h" +#include "lexer.h" - while ((token = yylex()) != TOK_END) - { - const char* name = token_name(token); +extern struct Node* program_root; +int yyparse(void); - if (token == TOK_CHAR) - (void)printf("'%c'\n", lexer_character()); - else if (name != NULL) - (void)printf("%s\n", name); - else - (void)printf("%c\n", (char)token); - } +static int parse_program(void) +{ + int status = yyparse(); + if (status != 0 || lexer_failed()) + status = 1; - return lexer_failed() ? 1 : 0; + node_free(program_root); + program_root = NULL; + return status; } int main(int argc, char** argv) @@ -45,11 +28,11 @@ int main(int argc, char** argv) yyin = fopen(argv[1], "r"); if (yyin == NULL) { - (void)fprintf(stderr, "cannot open %s, is it even real\n", argv[1]); + (void)fprintf(stderr, "cannot open %s\n", argv[1]); return 1; } - int status = dump_tokens(); + int status = parse_program(); (void)fclose(yyin); return status; } @@ -2,12 +2,13 @@ %{ #include "lexer.h" +#include "ast.h" +#include "parser.h" #include <stdbool.h> #include <stdio.h> static bool failed = false; -static char character = '\0'; static char unescape(char escaped) { @@ -24,7 +25,7 @@ static int fail(const char* message) { (void)fprintf(stderr, "line %d: %s\n", yylineno, message); failed = true; - return TOK_END; + return 0; } %} @@ -36,8 +37,8 @@ static int fail(const char* message) "decltype" return TOK_DECLTYPE; "difference" return TOK_DIFFERENCE; [<>(),;] return yytext[0]; -'\\.' character = unescape(yytext[2]); return TOK_CHAR; -'.' character = yytext[1]; return TOK_CHAR; +'\\.' yylval.character = unescape(yytext[2]); return TOK_CHAR; +'.' yylval.character = yytext[1]; return TOK_CHAR; "//"[^\n]* /* a comment */ [ \t\r\n]+ /* blanks */ [0-9]+ return fail("numeric literals are for the weak, subtract two characters"); @@ -50,8 +51,3 @@ bool lexer_failed(void) { return failed; } - -char lexer_character(void) -{ - return character; -} diff --git a/sfinae.y b/sfinae.y new file mode 100644 index 0000000..2e91b23 --- /dev/null +++ b/sfinae.y @@ -0,0 +1,64 @@ +%{ +#include "ast.h" +#include "lexer.h" + +#include <stdio.h> + +struct Node* program_root = NULL; + +void yyerror(const char* message); +%} + +%union +{ + char character; + struct Node* node; +} + +%token TOK_COLONCOLON +%token TOK_EMIT +%token TOK_COMMIT +%token TOK_DECLTYPE +%token TOK_DIFFERENCE +%token <character> TOK_CHAR + +%type <node> statements statement type value + +%% + +program + : statements + { program_root = $1; } + ; + +statements + : /* nothing */ + { $$ = NULL; } + | statements statement ';' + { $$ = node_append($1, $2); } + ; + +statement + : TOK_COLONCOLON TOK_EMIT '<' type '>' TOK_COLONCOLON TOK_COMMIT + { $$ = node_unary(STMT_EMIT, $4); } + ; + +type + : TOK_COLONCOLON TOK_DECLTYPE '(' value ')' + { $$ = node_unary(TYPE_DECLTYPE, $4); } + ; + +value + : TOK_COLONCOLON TOK_DIFFERENCE '<' TOK_CHAR ',' TOK_CHAR '>' + { $$ = node_binary(VALUE_DIFFERENCE, node_char($4), node_char($6)); } + ; + +%% + +void yyerror(const char* message) +{ + if (!lexer_failed()) + { + (void)fprintf(stderr, "line %d: %s, did you forget to commit\n", yylineno, message); + } +} |
