hachem.wtf
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-19 11:17:14 +0200
committerhachem <im@hachem.wtf>2026-09-19 11:17:14 +0200
commit768bbdd137f5b205e4282bd79572681aef4514e3 (patch)
treec249765cd8607a34443e05709ea54441bf0dfd3e
parent08b8cbbccd8c8d7dab75746ee9d134f67455de91 (diff)
feat: add bison grammar for emit, decltype and difference
-rw-r--r--Makefile17
-rw-r--r--lexer.h12
-rw-r--r--main.c45
-rw-r--r--sfinae.l14
-rw-r--r--sfinae.y64
5 files changed, 95 insertions, 57 deletions
diff --git a/Makefile b/Makefile
index a30b93c..c107cb3 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/lexer.h b/lexer.h
index 4e09ace..93d854a 100644
--- a/lexer.h
+++ b/lexer.h
@@ -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);
diff --git a/main.c b/main.c
index 634e6d0..2d358d8 100644
--- a/main.c
+++ b/main.c
@@ -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;
}
diff --git a/sfinae.l b/sfinae.l
index f969a98..5c67f3c 100644
--- a/sfinae.l
+++ b/sfinae.l
@@ -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);
+ }
+}