From 099bc5bf35b3f33edf1e12afe73e37e052718b32 Mon Sep 17 00:00:00 2001 From: "Erwann Lagouche (AirOne01)" <21955960+AirOne01@users.noreply.github.com> Date: Mon, 9 Mar 2026 01:46:33 +0100 Subject: [PATCH 1/3] feat: b --- flake.nix | 4 ++++ pcc/b/.gitignore | 4 ++++ pcc/b/Makefile | 24 +++++++++++++++++++++ pcc/b/lexer.l | 36 +++++++++++++++++++++++++++++++ pcc/b/parser.y | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ pcc/b/test1.b | 4 ++++ pcc/b/test2.b | 11 ++++++++++ 7 files changed, 138 insertions(+) create mode 100644 pcc/b/.gitignore create mode 100644 pcc/b/Makefile create mode 100644 pcc/b/lexer.l create mode 100644 pcc/b/parser.y create mode 100644 pcc/b/test1.b create mode 100644 pcc/b/test2.b diff --git a/flake.nix b/flake.nix index 5f546d87..499d2abe 100644 --- a/flake.nix +++ b/flake.nix @@ -68,6 +68,10 @@ # ASM nasm + # Compiler compilers + bison # yacc + flex # lex + # Rust pkg-config rustc diff --git a/pcc/b/.gitignore b/pcc/b/.gitignore new file mode 100644 index 00000000..5d2a1e85 --- /dev/null +++ b/pcc/b/.gitignore @@ -0,0 +1,4 @@ +B +*.h +*.c + diff --git a/pcc/b/Makefile b/pcc/b/Makefile new file mode 100644 index 00000000..f821f207 --- /dev/null +++ b/pcc/b/Makefile @@ -0,0 +1,24 @@ +NAME = B +CC = gcc +CFLAGS = -Wall -Wextra -Werror + +all: $(NAME) + +$(NAME): y.tab.c lex.yy.c + $(CC) $(CFLAGS) -o $(NAME) y.tab.c lex.yy.c + +y.tab.c y.tab.h: parser.y + yacc -d parser.y + +lex.yy.c: lexer.l y.tab.h + lex lexer.l + +clean: + rm -f lex.yy.c y.tab.c y.tab.h + +fclean: clean + rm -f $(NAME) + +re: fclean all + +.PHONY: all clean fclean re diff --git a/pcc/b/lexer.l b/pcc/b/lexer.l new file mode 100644 index 00000000..23dd60b0 --- /dev/null +++ b/pcc/b/lexer.l @@ -0,0 +1,36 @@ +%{ +#include "y.tab.h" // tokens generated by yacc +#include + +// The below 'option' call voids some unused functions +// Older versions of lex might not recognize this line +%} + +%option nounput noinput + +%% + +[a-zA-Z_][a-zA-Z0-9_]* { + yylval.str = strdup(yytext); // dupe + return IDENTIFIER; + } + +[0-9]+ { + yylval.num = atoi(yytext); + return NUMBER; + } + +[ \t\n]+ { /* ignore whitespaces */ } + +"=" { return EQUALS; } +";" { return SEMICOLON; } +"(" { return '('; } +")" { return ')'; } +"{" { return '{'; } +"}" { return '}'; } + +%% + +int yywrap() { + return 1; +} diff --git a/pcc/b/parser.y b/pcc/b/parser.y new file mode 100644 index 00000000..96777adc --- /dev/null +++ b/pcc/b/parser.y @@ -0,0 +1,55 @@ +%{ +#include +int yylex(void); +void yyerror(const char *s); +%} + +%union { + int num; + char *str; +} + +%token IDENTIFIER +%token NUMBER +%token EQUALS SEMICOLON + +%% + +program: + | program statement + | program function_definition + ; + +statements_list: + | statements_list statement + ; + +statement: + IDENTIFIER EQUALS NUMBER SEMICOLON { + printf("\tmov eax, %d\n", $3); + printf("\tmov [ebp-4], eax ; store val\n"); + } + ; + +function_definition: + IDENTIFIER '(' ')' '{' { + printf("%s:\n", $1); + printf("\t.long %s + 4\n", $1); + printf("\tenter 0, 0\n"); + } + statements_list + '}' { + printf("\tleave\n"); + printf("\tret\n"); + } + ; + +%% + +void yyerror(const char *s) { + fprintf(stderr, "Error: %s\n", s); +} + +int main(void) { + return yyparse(); +} diff --git a/pcc/b/test1.b b/pcc/b/test1.b new file mode 100644 index 00000000..06c4f471 --- /dev/null +++ b/pcc/b/test1.b @@ -0,0 +1,4 @@ +main() { + i = 0; +} + diff --git a/pcc/b/test2.b b/pcc/b/test2.b new file mode 100644 index 00000000..a555e8b8 --- /dev/null +++ b/pcc/b/test2.b @@ -0,0 +1,11 @@ +main() { + extrn putchar, char; + auto i, s; + i = 0; + s = "hello, world\n"; + while (char(s, i)) { + putchar(char(s, i)); + i++; + } +} + From d7a3f404948285eeeb1e0fc65c642d163f1e13b1 Mon Sep 17 00:00:00 2001 From: "Erwann Lagouche (AirOne01)" <21955960+AirOne01@users.noreply.github.com> Date: Mon, 9 Mar 2026 02:05:48 +0100 Subject: [PATCH 2/3] feat(b): memory management --- pcc/b/lexer.l | 4 +++ pcc/b/parser.y | 89 ++++++++++++++++++++++++++++++++++++++++++++-- pcc/b/test2.b | 11 ++---- pcc/b/test_final.b | 11 ++++++ 4 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 pcc/b/test_final.b diff --git a/pcc/b/lexer.l b/pcc/b/lexer.l index 23dd60b0..f9e04709 100644 --- a/pcc/b/lexer.l +++ b/pcc/b/lexer.l @@ -10,6 +10,9 @@ %% +"auto" { return AUTO; } +"extrn" { return EXTERN; } + [a-zA-Z_][a-zA-Z0-9_]* { yylval.str = strdup(yytext); // dupe return IDENTIFIER; @@ -24,6 +27,7 @@ "=" { return EQUALS; } ";" { return SEMICOLON; } +"," { return ','; } "(" { return '('; } ")" { return ')'; } "{" { return '{'; } diff --git a/pcc/b/parser.y b/pcc/b/parser.y index 96777adc..58002202 100644 --- a/pcc/b/parser.y +++ b/pcc/b/parser.y @@ -1,7 +1,63 @@ %{ #include +#include +#include +#include + int yylex(void); void yyerror(const char *s); + +typedef enum { + TYPE_AUTO, + TYPE_EXTERN +} SymbolType; + +typedef struct { + char *name; + SymbolType type; + int offset; // ebp +} Symbol; + +void *sym_table = NULL; +int current_local_offset = -4; + +// required by tsearch +int compare_symbols(const void *pa, const void *pb) { + return strcmp(((const Symbol *)pa)->name, ((const Symbol *)pb)->name); +} + +void add_symbol(char *name, SymbolType type) { + Symbol *sym = malloc(sizeof(Symbol)); + sym->name = strdup(name); + sym->type = type; + + if (type == TYPE_AUTO) { + sym->offset = current_local_offset; + // shift down 4 for next var + current_local_offset -= 4; + } else { + // extern symbols don't use edp offset + sym->offset = 0; + } + + // insertion + Symbol **found = tsearch(sym, &sym_table, compare_symbols); + if (*found != sym) { + // var was already in the tree + free(sym->name); + free(sym); + } +} + +Symbol *get_symbol(char *name) { + Symbol dummy; + dummy.name = name; + Symbol **found = tfind(&dummy, &sym_table, compare_symbols); + if (found) { + return *found; + } + return NULL; +} %} %union { @@ -11,7 +67,7 @@ void yyerror(const char *s); %token IDENTIFIER %token NUMBER -%token EQUALS SEMICOLON +%token EQUALS SEMICOLON AUTO EXTERN %% @@ -20,14 +76,38 @@ program: | program function_definition ; +declarations: + | declarations declaration + ; + +declaration: + AUTO auto_list SEMICOLON + | EXTERN extrn_list SEMICOLON + ; + +auto_list: + IDENTIFIER { add_symbol($1, TYPE_AUTO); } + | auto_list ',' IDENTIFIER { add_symbol($3, TYPE_AUTO); } + ; + +extrn_list: + IDENTIFIER { add_symbol($1, TYPE_EXTERN); } + | extrn_list ',' IDENTIFIER { add_symbol($3, TYPE_EXTERN); } + ; + statements_list: | statements_list statement ; statement: IDENTIFIER EQUALS NUMBER SEMICOLON { - printf("\tmov eax, %d\n", $3); - printf("\tmov [ebp-4], eax ; store val\n"); + Symbol *sym = get_symbol($1); + + if (sym && sym->type == TYPE_AUTO) { + printf("\tmov eax, %d\n", $3); + printf("\tmov [ebp%d], eax ; store val in %s\n", sym->offset, $1); + } else + fprintf(stderr, "Error: Unknown or non-auto variable '%s'\n", $1); } ; @@ -36,7 +116,10 @@ function_definition: printf("%s:\n", $1); printf("\t.long %s + 4\n", $1); printf("\tenter 0, 0\n"); + // reset offset tracker for new func + current_local_offset = -4; } + declarations statements_list '}' { printf("\tleave\n"); diff --git a/pcc/b/test2.b b/pcc/b/test2.b index a555e8b8..907083a2 100644 --- a/pcc/b/test2.b +++ b/pcc/b/test2.b @@ -1,11 +1,6 @@ main() { - extrn putchar, char; - auto i, s; + auto i, s, x; i = 0; - s = "hello, world\n"; - while (char(s, i)) { - putchar(char(s, i)); - i++; - } + s = 42; + x = 100; } - diff --git a/pcc/b/test_final.b b/pcc/b/test_final.b new file mode 100644 index 00000000..a555e8b8 --- /dev/null +++ b/pcc/b/test_final.b @@ -0,0 +1,11 @@ +main() { + extrn putchar, char; + auto i, s; + i = 0; + s = "hello, world\n"; + while (char(s, i)) { + putchar(char(s, i)); + i++; + } +} + From 5a5441f09d8ab946ebbf53efac27d608d560c2a8 Mon Sep 17 00:00:00 2001 From: "Erwann Lagouche (AirOne01)" <21955960+AirOne01@users.noreply.github.com> Date: Mon, 9 Mar 2026 02:07:28 +0100 Subject: [PATCH 3/3] chore: release-please stuff --- .release-please-manifest.json | 1 + milestone-5/cpp09/version.txt | 1 + pcc/b/version.txt | 1 + pcc/libasm/version.txt | 1 + piscine-c/c00/version.txt | 1 + release-please-config.json | 4 ++++ 6 files changed, 9 insertions(+) create mode 100644 milestone-5/cpp09/version.txt create mode 100644 pcc/b/version.txt create mode 100644 pcc/libasm/version.txt create mode 100644 piscine-c/c00/version.txt diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 379a1dde..7a7ac47e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -34,6 +34,7 @@ "milestone-5/cpp08": "1.1.0", "milestone-5/cpp09": "1.0.1", "milestone-5/inception": "1.0.0", + "pcc/b": "0.0.0", "pcc/libasm": "1.0.0", "rushes/hotrace": "2.1.0", "rushes/libunit": "1.0.0", diff --git a/milestone-5/cpp09/version.txt b/milestone-5/cpp09/version.txt new file mode 100644 index 00000000..77d6f4ca --- /dev/null +++ b/milestone-5/cpp09/version.txt @@ -0,0 +1 @@ +0.0.0 diff --git a/pcc/b/version.txt b/pcc/b/version.txt new file mode 100644 index 00000000..77d6f4ca --- /dev/null +++ b/pcc/b/version.txt @@ -0,0 +1 @@ +0.0.0 diff --git a/pcc/libasm/version.txt b/pcc/libasm/version.txt new file mode 100644 index 00000000..77d6f4ca --- /dev/null +++ b/pcc/libasm/version.txt @@ -0,0 +1 @@ +0.0.0 diff --git a/piscine-c/c00/version.txt b/piscine-c/c00/version.txt new file mode 100644 index 00000000..77d6f4ca --- /dev/null +++ b/piscine-c/c00/version.txt @@ -0,0 +1 @@ +0.0.0 diff --git a/release-please-config.json b/release-please-config.json index 549214f7..e50ad7b4 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -141,6 +141,10 @@ "release-type": "simple", "package-name": "inception" }, + "pcc/b": { + "release-type": "simple", + "package-name": "b" + }, "pcc/libasm": { "release-type": "simple", "package-name": "libasm"