commit dfd72482acf73be232193a85f3cef9bd8066ed0d Author: HeshamTB Date: Mon Dec 25 18:18:28 2023 +0300 init: it compiles, but idk what is happening diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e2baad --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ + +a.out + +# File generated by flex and bison +parser.c +scanner.c +token.h + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f05f7a7 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ + +all: flex bison + gcc expr.c parser.c scanner.c main.c + +bison: + bison --defines=token.h --output=parser.c parser.bison + +flex: bison + flex -o scanner.c scanner.flex diff --git a/expr.c b/expr.c new file mode 100644 index 0000000..ae1e470 --- /dev/null +++ b/expr.c @@ -0,0 +1,100 @@ + +#include "expr.h" +#include + +struct decl* decl_create( + char* name, + struct type* type, + struct expr* value, + struct stmt* code, + struct decl* next) +{ + + struct decl* d = malloc(sizeof(*d)); + d->name = name; + d->value = value; + d->code = code; + d->next = next; + return d; +} + +struct stmt* stmt_create( + stmt_t kind, + struct decl* decl, struct expr* init_expr, + struct expr* expr, struct expr* next_expr, + struct stmt* body, struct stmt* else_body, + struct stmt* next) +{ + + struct stmt* s = malloc(sizeof(*s)); + s->decl = decl; + s->expr = expr; + s->next = next; + s->body = body; + s->else_body = else_body; + s->init_expr = init_expr; + s->next_expr = next_expr; + s->kind = kind; + return s; +} + +struct expr* expr_create(expr_t kind, struct expr* left, struct expr* right) +{ + struct expr* e = malloc(sizeof(*e)); + e->kind = kind; + e->left = left; + e->right = right; + return e; +} + +struct expr* expr_create_name(const char* name) +{ + struct expr* e = malloc(sizeof(*e)); + e->kind = EXPR_NAME; + e->name = name; + return e; +} + +struct expr* expr_create_integer_literal(int i) +{ + struct expr* e = malloc(sizeof(*e)); + e->kind = EXPR_INTEGER_LITERAL; + e->integer_value = i; + return e; +} + +struct expr* expr_create_boolean_literal(int b) +{ + struct expr* e = malloc(sizeof(*e)); + e->kind = EXPR_BOOLEAN_LITERAL; + // FIXME: Check if it is 0 or 1? + e->integer_value = b; + return e; +} + + +struct expr* expr_create_char_literal(char c) +{ + struct expr* e = malloc(sizeof(*e)); + e->kind = EXPR_CHAR_LITERAL; + e->integer_value = c; // this limits us to ASCII? + return e; +} + +struct expr* expr_create_string_literal(const char* s) +{ + struct expr* e = malloc(sizeof(*e)); + e->kind = EXPR_STRING_LITERAL; + e->string_literal = s; + return e; +} + +struct type* create_type(type_t kind, struct type* subtybe, struct param_list* param_list) +{ + struct type* t = malloc(sizeof(*t)); + t->kind = kind; + t->subtype = subtybe; + t->params = param_list; + return t; +} + diff --git a/expr.h b/expr.h new file mode 100644 index 0000000..b677589 --- /dev/null +++ b/expr.h @@ -0,0 +1,89 @@ + + +#ifndef PARSER_H +#define PARSER_H + +typedef enum { + STMT_DECL, + STMT_EXPR, + STMT_IF_ELSE, + STMT_FOR, + STMT_PRINT, + STMT_RETURN, + STMT_BLOCK +} stmt_t; + +typedef enum { + EXPR_ADD, + EXPR_SUB, + EXPR_MUL, + EXPR_DIV, + EXPR_GT, + EXPR_LT, + EXPR_EQ, + EXPR_NOT, + EXPR_NAME, + EXPR_INTEGER_LITERAL, + EXPR_STRING_LITERAL, + EXPR_BOOLEAN_LITERAL, + EXPR_CHAR_LITERAL, + EXPR_CALL, + EXPR_ARG, + EXPR_SUBSCRIPT +} expr_t; + +typedef enum { + TYPE_VOID, + TYPE_BOOLEAN, + TYPE_CHARACTER, + TYPE_INTEGER, + TYPE_STRING, + TYPE_ARRAY, + TYPE_FUNCTION +} type_t; + +struct type { + type_t kind; + struct type* subtype; + struct param_list* params; +}; + +struct param_list { + char* name; + struct type* type; + struct param_list* next; +}; + +struct expr { + expr_t kind; + struct expr* left; + struct expr* right; + + const char* name; + int integer_value; + const char* string_literal; +}; + +struct stmt { + stmt_t kind; + struct decl* decl; + struct expr* init_expr; + struct expr* expr; + struct expr* next_expr; + struct stmt* body; + struct stmt* else_body; + struct stmt* next; +}; + +struct decl { + char* name; + struct type* type; + struct expr* value; + struct stmt* code; + struct decl* next; +}; + +struct expr* expr_create(expr_t kind, struct expr* left, struct expr* right); + + +#endif // PARSER_H diff --git a/main.c b/main.c new file mode 100644 index 0000000..b395388 --- /dev/null +++ b/main.c @@ -0,0 +1,35 @@ + +#include + +#include "token.h" + +/* Flex */ +// extern FILE *yyin; +// extern int yylex(); +// extern char* yytext; + +/* Bison */ +extern int yyparse(); + +int main() +{ + if (yyparse()) { + printf("Parse successful!\n"); + } else { + printf("Parse failed!\n"); + } + + // yyin = fopen("program.c", "r"); + // if (!yyin) { + // printf("Could not open source file!\n"); + // return 1; + // } + + // while (1) { + // enum yytokentype t = yylex(); + // if (t == YYEOF) break; + // printf("token: %d text: %s\n", t, yytext); + // } +} + + diff --git a/parser.bison b/parser.bison new file mode 100644 index 0000000..e0c7b56 --- /dev/null +++ b/parser.bison @@ -0,0 +1,105 @@ +%{ + +#include +#include +#include "expr.h" +#include "token.h" + +struct decl* parser_result = 0; + +extern int yylex(); +extern char* yytext; + + +%} + +%token TOKEN_INT +%token TOKEN_PLUS +%token TOKEN_MINUS +%token TOKEN_MUL +%token TOKEN_DIV +%token TOKEN_LPAREN +%token TOKEN_RPAREN +%token TOKEN_RBRACE +%token TOKEN_LBRACE +%token TOKEN_IF +%token TOKEN_SEMI +%token TOKEN_ERROR +%token TOKEN_COLON +%token TOKEN_ASSIGN +%token TOKEN_VOID +%token TOKEN_WHILE +%token TOKEN_IDENT +%token TOKEN_NUMBER + +%union { + + struct decl* decl; + struct stmt* stmt; + struct expr* expr; + struct type* type; + + char* name; +} + +%type program decl_list decl +%type stmt_list stmt +%type expr factor term +%type type +%type name + +%% + +program : decl_list { parser_result = $1; } + ; + +decl : name TOKEN_COLON type TOKEN_SEMI + { $$ = decl_create($1,$3,0,0,0); } + | name TOKEN_COLON type TOKEN_ASSIGN expr TOKEN_SEMI + { $$ = decl_create($1,$3,$5,0,0); } + ; + +decl_list : decl decl_list { $$ = $1; $1->next = $2; } + | { $$ = 0; } + ; + +stmt : TOKEN_IF TOKEN_LPAREN expr TOKEN_RPAREN stmt + { $$ = stmt_create(STMT_IF_ELSE,0,0,$3,0,$5,0,0); } + | TOKEN_LBRACE stmt_list TOKEN_RBRACE + { $$ = stmt_create(STMT_BLOCK,0,0,0,0,$2,0,0); } + ; + +stmt_list : stmt stmt_list { $$ = $1; $1->next $2; } + | { $$ = 0; } + ; + +expr : expr TOKEN_PLUS term { $$ = expr_create(EXPR_ADD,$1,$3); } + | expr TOKEN_MINUS term { $$ = expr_create(EXPR_SUB,$1,$3); } + | term { $$ = $1; } + ; + +term : term TOKEN_MUL factor { $$ = expr_create(EXPR_MUL,$1,$3); } + | term TOKEN_DIV factor { $$ = expr_create(EXPR_DIV,$1,$3); } + | factor { $$ = $1; } + ; + +factor : TOKEN_MINUS factor + { $$ = expr_create(EXPR_SUB, expr_create_integer_literal(0), $2); } + | TOKEN_LPAREN expr TOKEN_RPAREN { $$ = $2; } + | TOKEN_INT { $$ = expr_create_integer_literal(atoi(yytext)); } + ; + +type : TOKEN_INT { $$ = create_type(TYPE_INTEGER,0,0); } + | TOKEN_VOID { $$ = create_type(TYPE_VOID,0,0); } + ; + +name : TOKEN_IDENT { $$ = yytext; } + ; + +%% + +int yyerror(char* s) +{ + printf("parse error: %s\n", s); + return 1; +} diff --git a/scanner.flex b/scanner.flex new file mode 100644 index 0000000..a57ef6d --- /dev/null +++ b/scanner.flex @@ -0,0 +1,30 @@ +%{ + +#include "token.h" + +%} + +DIGIT [0-9] +LETTER [a-zA-Z] + +%% +(" "|\t|\n) /* skip whitespce */ +\+ { return TOKEN_PLUS; } +\- { return TOKEN_MINUS; } +\* { return TOKEN_MUL; } +\/ { return TOKEN_DIV; } +if { return TOKEN_IF; } +\( { return TOKEN_LPAREN; } +\) { return TOKEN_RPAREN; } +\{ { return TOKEN_LBRACE; } +\} { return TOKEN_RBRACE; } +void { return TOKEN_VOID; } +int { return TOKEN_INT; } +while { return TOKEN_WHILE; } +{LETTER}+ { return TOKEN_IDENT; } +{DIGIT}+ { return TOKEN_NUMBER; } +. { return TOKEN_ERROR; } + +%% +int yywrap() { return 1; } +