From 160bd09d2ce00a4d605870ecae322bbb2dc5602d Mon Sep 17 00:00:00 2001 From: Samuel Huang Date: Mon, 6 Nov 2023 12:11:28 -0500 Subject: [PATCH] Introduce printer * Create test cases for printer * Add printer test in runtest.sh * Add --print option * Add rules for printer and other improvements * Create printer.c * Define semantic values in lex.yy.l * Modify parse() to support parsing consecutive files * Modify parse() to return AST root * Add actions after reduction in grammar.y * Add param_list_create() and param_list_print() * Add expr_create() and expr_print() * Add type_create() and type_print() * Add stmt_create() and stmt_print() * Add decl_create() and decl_print() * Pass file pointers to decode(), scan(), and parse() * Modify parse() to take file pointer * Modify scan() to take file pointer * Modify decode() to take file pointer * Move definition of MAX_STRING_LEN * Add grammar.output to .gitignore --- .gitignore | 1 + Makefile | 36 ++++- bminor.c | 23 ++- decl.c | 58 ++++++++ decl.h | 25 ++-- encoder.c | 25 +--- encoder.h | 7 +- expr.c | 293 +++++++++++++++++++++++++++++++++++++ expr.h | 82 ++++++++--- grammar.y | 172 ++++++++++++++-------- lex.yy.l | 6 + param_list.c | 24 +++ param_list.h | 18 +-- parser.c | 20 +-- parser.h | 2 +- printer.c | 122 +++++++++++++++ printer.h | 4 + runtest.sh | 22 +++ scanner.c | 15 +- scanner.h | 2 +- stmt.c | 148 +++++++++++++++++++ stmt.h | 36 +++-- test/printer/good00.bminor | 12 ++ test/printer/good01.bminor | 17 +++ test/printer/good02.bminor | 20 +++ test/printer/good03.bminor | 5 + test/printer/good04.bminor | 11 ++ test/printer/good05.bminor | 4 + test/printer/good06.bminor | 18 +++ test/printer/good07.bminor | 8 + test/printer/good08.bminor | 7 + test/printer/good09.bminor | 11 ++ test/printer/good10.bminor | 11 ++ type.c | 83 +++++++++++ type.h | 23 ++- 35 files changed, 1193 insertions(+), 178 deletions(-) create mode 100644 decl.c create mode 100644 expr.c create mode 100644 param_list.c create mode 100644 printer.c create mode 100644 printer.h create mode 100644 stmt.c create mode 100644 test/printer/good00.bminor create mode 100644 test/printer/good01.bminor create mode 100644 test/printer/good02.bminor create mode 100644 test/printer/good03.bminor create mode 100644 test/printer/good04.bminor create mode 100644 test/printer/good05.bminor create mode 100644 test/printer/good06.bminor create mode 100644 test/printer/good07.bminor create mode 100644 test/printer/good08.bminor create mode 100644 test/printer/good09.bminor create mode 100644 test/printer/good10.bminor create mode 100644 type.c diff --git a/.gitignore b/.gitignore index 16a1068..155d5ff 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,6 @@ bminor lex.yy.c token.h grammar.tab.c +grammar.output test/**/*.out \ No newline at end of file diff --git a/Makefile b/Makefile index c2b6a29..8994218 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,10 @@ -bminor: bminor.c encoder.o scanner.o lex.yy.o parser.o grammar.tab.o +bminor: bminor.c encoder.o scanner.o lex.yy.o parser.o grammar.tab.o printer.o decl.o stmt.o expr.o type.o param_list.o gcc $^ -o $@ -encoder.o: encoder.c - gcc -c $^ -o $@ +encoder.o: encoder.c encoder.h + gcc -c $< -o $@ +# Scanner lex.yy.c: lex.yy.l flex $^ @@ -13,16 +14,36 @@ lex.yy.o: lex.yy.c scanner.o: scanner.c token.h gcc -c $< -o $@ +# Parser parser.o: parser.c gcc -c $^ -o $@ grammar.tab.c token.h: grammar.y lex.yy.c - bison --defines=token.h $< - #bison -v --defines=token.h $< + #bison --defines=token.h $< + bison -v --defines=token.h $< grammar.tab.o: grammar.tab.c gcc -c $^ -o $@ +# Printer +printer.o: printer.c + gcc -c $^ -o $@ + +decl.o: decl.c + gcc -c $^ -o $@ + +stmt.o: stmt.c + gcc -c $^ -o $@ + +expr.o: expr.c + gcc -c $^ -o $@ + +type.o: type.c + gcc -c $^ -o $@ + +param_list.o: param_list.c + gcc -c $^ -o $@ + # Tests test-encoder: ./runtest.sh encoder @@ -33,9 +54,12 @@ test-scanner: test-parser: ./runtest.sh parser +test-printer: + ./runtest.sh printer + clean: rm -f lex.yy.c rm -f token.h grammar.tab.c grammar.output rm -f *.o rm -f ./test/*/*.bminor.out - rm -f bminor \ No newline at end of file + rm -f bminor diff --git a/bminor.c b/bminor.c index dc82e0b..3d801b7 100644 --- a/bminor.c +++ b/bminor.c @@ -5,6 +5,7 @@ #include "encoder.h" #include "scanner.h" #include "parser.h" +#include "printer.h" void usage(int exit_code) { @@ -14,8 +15,8 @@ void usage(int exit_code) int main(int argc, char* argv[]) { + // Parse command line arguments char* option, * filename; - switch (argc) { case 1: @@ -36,27 +37,41 @@ int main(int argc, char* argv[]) break; } + // Open input file + FILE* fp = fopen(filename, "r"); + if (fp == NULL) + { + fprintf(stderr, "Failed to open file %s\n", filename); + return EXIT_FAILURE; + } + + // Perform the requested operation if (strcmp(option, "--encode") == 0) { - if (decode(filename) == 0) + if (decode(fp) == 0) return EXIT_SUCCESS; } else if (strcmp(option, "--scan") == 0) { - if (scan(filename) == 0) + if (scan(fp) == 0) return EXIT_SUCCESS; } else if (strcmp(option, "--parse") == 0) { - if (parse(filename) == 0) + if (parse(fp) != NULL) return EXIT_SUCCESS; } + else if (strcmp(option, "--print") == 0) + { + return print_and_compare(filename, fp); + } else { fprintf(stderr, "Unknown option '%s'\n", option); usage(EXIT_FAILURE); } + //Error message fprintf(stderr, "Failed to %s file %s\n", option + 2, filename); return EXIT_FAILURE; } diff --git a/decl.c b/decl.c new file mode 100644 index 0000000..e8f9c86 --- /dev/null +++ b/decl.c @@ -0,0 +1,58 @@ +#include +#include +#include "decl.h" +#include "type.h" + +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->type = type; + d->value = value; + d->code = code; + d->next = next; + return d; +} + +void decl_print(struct decl* d, int indent) +{ + if (!d) return; + int i; + + for (i = 0; i < indent; i++) + printf("\t"); + printf("%s: ", d->name); + type_print(d->type); + + if (d->value) + { + printf(" = "); + if (d->value->kind == EXPR_LIST) + { + printf("{"); + expr_print(d->value); + printf("}"); + } + else + { + expr_print(d->value); + } + } + + if (d->code) + { + printf(" = {\n"); + stmt_print(d->code, indent + 1); + for (i = 0; i < indent; i++) + printf("\t"); + printf("}"); + } + else + { + // Functions don't end with semicolon + printf(";"); + } + + printf("\n"); + decl_print(d->next, indent); +} \ No newline at end of file diff --git a/decl.h b/decl.h index ee776d1..b7b5f0b 100755 --- a/decl.h +++ b/decl.h @@ -1,24 +1,21 @@ - #ifndef DECL_H #define DECL_H -#include "type.h" #include "stmt.h" #include "expr.h" -#include +#include "symbol.h" -struct decl { - char *name; - struct type *type; - struct expr *value; - struct stmt *code; - struct symbol *symbol; - struct decl *next; +struct decl +{ + char* name; + struct type* type; + struct expr* value; + struct stmt* code; + struct symbol* symbol; + struct decl* next; }; -struct decl * decl_create( char *name, struct type *type, struct expr *value, struct stmt *code, struct decl *next ); -void decl_print( struct decl *d, int indent ); +struct decl* decl_create(char* name, struct type* type, struct expr* value, struct stmt* code, struct decl* next); +void decl_print(struct decl* d, int indent); #endif - - diff --git a/encoder.c b/encoder.c index 06f90f5..12d8df3 100644 --- a/encoder.c +++ b/encoder.c @@ -1,8 +1,7 @@ #include #include #include - -#define MAX_STRING_LEN 255 +#include "encoder.h" int is_hex(char c) { @@ -199,25 +198,18 @@ int string_encode(const char* s, char* es) return 0; } -int decode(const char* filename) +int decode(FILE* fp) { - FILE* file = fopen(filename, "r"); - if (file == NULL) - { - printf("Could not open file %s\n", filename); - return 1; - } - // Find the size of the file - fseek(file, 0, SEEK_END); - long file_size = ftell(file); + fseek(fp, 0, SEEK_END); + long file_size = ftell(fp); if (file_size > (MAX_STRING_LEN * 5 + 2) * sizeof(char)) { fprintf(stderr, "Invalid string: too long\n"); - fclose(file); + fclose(fp); return 1; } - rewind(file); + rewind(fp); // Allocate memory for the file content // Reserve space for \0 @@ -225,14 +217,13 @@ int decode(const char* filename) if (file_content == NULL) { perror("Could not allocate memory"); - fclose(file); + fclose(fp); return 1; } // Read the file content into the allocated memory - size_t chars_read = fread(file_content, sizeof(char), file_size, file); + size_t chars_read = fread(file_content, sizeof(char), file_size, fp); file_content[chars_read] = '\0'; - fclose(file); char s[MAX_STRING_LEN + 1] = { 0 }; diff --git a/encoder.h b/encoder.h index 83906e8..2fd4fc3 100644 --- a/encoder.h +++ b/encoder.h @@ -1,7 +1,12 @@ +#ifndef ENCODER_H +#define ENCODER_H + #define MAX_STRING_LEN 255 int string_decode(const char* es, char* s); int string_encode(const char* s, char* es); -int decode(const char* filename); +int decode(FILE *fp); + +#endif \ No newline at end of file diff --git a/expr.c b/expr.c new file mode 100644 index 0000000..378d504 --- /dev/null +++ b/expr.c @@ -0,0 +1,293 @@ +#include +#include +#include "encoder.h" +#include "expr.h" + +/* Creating binary nodes by default */ + +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; +} + +/* Creating unary operation nodes */ + +struct expr* expr_create_unary(expr_t kind, struct expr* operand) +{ + return expr_create(kind, operand, NULL); +} + +/* Creating leaf nodes */ + +struct expr* expr_create_leaf(expr_t kind) +{ + return expr_create(kind, NULL, NULL); +} + +struct expr* expr_create_name(const char* n) +{ + struct expr* e = expr_create_leaf(EXPR_NAME); + e->name = n; + return e; +} + +struct expr* expr_create_integer_literal(int i) +{ + struct expr* e = expr_create_leaf(EXPR_INTEGER_LITERAL); + e->integer_literal = i; + return e; +} + +struct expr* expr_create_float_literal(float f) +{ + struct expr* e = expr_create_leaf(EXPR_INTEGER_LITERAL); + e->float_literal = f; + return e; +} + +struct expr* expr_create_boolean_literal(int b) +{ + struct expr* e = expr_create_leaf(EXPR_BOOLEAN_LITERAL); + e->integer_literal = b; // Reuse the integer_literal field + return e; +} + +struct expr* expr_create_char_literal(char c) +{ + struct expr* e = expr_create_leaf(EXPR_CHAR_LITERAL); + e->char_literal = c; + return e; +} + +struct expr* expr_create_string_literal(const char* str) +{ + struct expr* e = expr_create_leaf(EXPR_STRING_LITERAL); + e->string_literal = str; + return e; +} + +/* Printing the expression nodes */ + +int get_precedence(const struct expr* e) +{ + switch (e->kind) + { + case EXPR_ASSIGN: + return 1; + case EXPR_OR: + return 2; + case EXPR_AND: + return 3; + case EXPR_LT: + case EXPR_LEQ: + case EXPR_GT: + case EXPR_GEQ: + case EXPR_EQ: + case EXPR_NEQ: + return 4; + case EXPR_ADD: + case EXPR_SUB: + return 5; + case EXPR_MUL: + case EXPR_DIV: + case EXPR_MOD: + return 6; + case EXPR_EXP: + return 7; + case EXPR_NEG: + case EXPR_NOT: + return 8; + case EXPR_INCREMENT: + case EXPR_DECREMENT: + return 9; + default: + return 10; + } +} + +void expr_print_binary(const struct expr* e) +{ + char operator[3] = "\0\0"; + switch (e->kind) + { + /* Arithmetic operators */ + case EXPR_ADD: + operator[0] = '+'; + break; + case EXPR_SUB: + operator[0] = '-'; + break; + case EXPR_MUL: + operator[0] = '*'; + break; + case EXPR_DIV: + operator[0] = '/'; + break; + case EXPR_MOD: + operator[0] = '%'; + break; + case EXPR_EXP: + operator[0] = '^'; + break; + + /* Comparison and logical operators */ + case EXPR_EQ: + operator[0] = operator[1] = '='; + break; + case EXPR_NEQ: + operator[0] = '!'; + operator[1] = '='; + break; + case EXPR_LT: + operator[0] = '<'; + break; + case EXPR_LEQ: + operator[0] = '<'; + operator[1] = '='; + break; + case EXPR_GT: + operator[0] = '>'; + break; + case EXPR_GEQ: + operator[0] = '>'; + operator[1] = '='; + break; + case EXPR_AND: + operator[0] = operator[1] = '&'; + break; + case EXPR_OR: + operator[0] = operator[1] = '|'; + break; + + /* Assignment operator */ + case EXPR_ASSIGN: + operator[0] = '='; + break; + + default: + /* Non-trivial cases handled by expr_print() */ + break; + } + + if (get_precedence(e) > get_precedence(e->left)) + { + printf("("); + expr_print(e->left); + printf(")"); + } + else + expr_print(e->left); + + printf(" %s ", operator); + + if (get_precedence(e) > get_precedence(e->right)) + { + printf("("); + expr_print(e->right); + printf(")"); + } + else + expr_print(e->right); +} + +void expr_print_leaf(const struct expr* e) +{ + char* es; + switch (e->kind) + { + case EXPR_NAME: + printf("%s", e->name); + break; + case EXPR_INTEGER_LITERAL: + printf("%d", e->integer_literal); + break; + case EXPR_FLOAT_LITERAL: + printf("%f", e->float_literal); + break; + case EXPR_BOOLEAN_LITERAL: + printf("%s", e->integer_literal ? "true" : "false"); + break; + case EXPR_CHAR_LITERAL: + printf("'%c'", e->char_literal); + break; + case EXPR_STRING_LITERAL: + es = malloc(MAX_STRING_LEN * sizeof(char) + 1); + string_encode(e->string_literal, es); + printf("%s", es); + break; + + default: + /* Non-literals handled in expr_print() */ + break; + } +} + +void expr_print_list(const struct expr* e) +{ + expr_print(e->left); + if (e->right != NULL) + { + printf(", "); + expr_print_list(e->right); + } +} + +void expr_print(const struct expr* e) +{ + switch (e->kind) + { + /* Leaf nodes */ + case EXPR_NAME: + case EXPR_INTEGER_LITERAL: + case EXPR_FLOAT_LITERAL: + case EXPR_BOOLEAN_LITERAL: + case EXPR_CHAR_LITERAL: + case EXPR_STRING_LITERAL: + expr_print_leaf(e); + break; + + /* Other non-trivial operators */ + case EXPR_NEG: + printf("-"); + expr_print(e->left); + break; + case EXPR_NOT: + printf("!"); + expr_print(e->left); + break; + case EXPR_INCREMENT: + expr_print(e->left); + printf("++"); + break; + case EXPR_DECREMENT: + expr_print(e->left); + printf("--"); + break; + case EXPR_CALL: + expr_print(e->left); + printf("("); + expr_print_list(e->right); + printf(")"); + break; + case EXPR_INDEX: + expr_print(e->left); + printf("["); + expr_print(e->right); + printf("]"); + break; + + /* Other nodes */ + case EXPR_LIST: + expr_print_list(e); + break; + + default: + /* Trivial binary operators */ + expr_print_binary(e); + break; + } +} diff --git a/expr.h b/expr.h index 65fdd87..e0afaf6 100755 --- a/expr.h +++ b/expr.h @@ -3,35 +3,77 @@ #include "symbol.h" -typedef enum { +typedef enum +{ + /* Arithmetic operator nodes */ EXPR_ADD, EXPR_SUB, EXPR_MUL, - EXPR_DIV - /* many more kinds of exprs to add here */ + EXPR_DIV, + EXPR_MOD, + EXPR_EXP, + + /* Comparison and logic operator nodes */ + EXPR_GT, + EXPR_GEQ, + EXPR_LT, + EXPR_LEQ, + EXPR_EQ, + EXPR_NEQ, + EXPR_AND, + EXPR_OR, + + /* Other binary operator nodes */ + EXPR_CALL, + EXPR_INDEX, + EXPR_ASSIGN, + + /* Unary operator nodes */ + EXPR_NEG, + EXPR_NOT, + EXPR_INCREMENT, + EXPR_DECREMENT, + + /* Leaf nodes */ + EXPR_INTEGER_LITERAL, + EXPR_FLOAT_LITERAL, + EXPR_BOOLEAN_LITERAL, + EXPR_CHAR_LITERAL, + EXPR_STRING_LITERAL, + EXPR_NAME, + + /* Special nodes */ + EXPR_LIST } expr_t; -struct expr { - /* used by all kinds of exprs */ +struct expr +{ + /* Used by all kinds of expressions */ expr_t kind; - struct expr *left; - struct expr *right; - - /* used by various leaf exprs */ - const char *name; - int literal_value; - const char * string_literal; - struct symbol *symbol; + struct expr* left; + struct expr* right; + + /* Used by various leaf expressions */ + struct symbol* symbol; + const char* name; + int integer_literal; // Used by INTEGER and BOOLEAN + float float_literal; + char char_literal; + const char* string_literal; }; -struct expr * expr_create( expr_t kind, struct expr *left, struct expr *right ); +struct expr* expr_create(expr_t kind, struct expr* left, struct expr* right); +struct expr* expr_create_unary(expr_t kind, struct expr* operand); -struct expr * expr_create_name( const char *n ); -struct expr * expr_create_integer_literal( int c ); -struct expr * expr_create_boolean_literal( int c ); -struct expr * expr_create_char_literal( char c ); -struct expr * expr_create_string_literal( const char *str ); +/* Creating leaf nodes */ +struct expr* expr_create_name(const char* n); +struct expr* expr_create_integer_literal(int i); +struct expr* expr_create_float_literal(float f); +struct expr* expr_create_boolean_literal(int b); +struct expr* expr_create_char_literal(char c); +struct expr* expr_create_string_literal(const char* str); -void expr_print( struct expr *e ); +/* Printing the expressions */ +void expr_print(const struct expr* e); #endif diff --git a/grammar.y b/grammar.y index db3edd2..54bac93 100644 --- a/grammar.y +++ b/grammar.y @@ -1,5 +1,6 @@ %{ #include +#include "stmt.h" #define YYDEBUG 1 extern int yylex(); @@ -9,6 +10,8 @@ extern char *yytext; void yyerror(const char *s) { fprintf(stderr, "Error: %s at line %d near '%s'\n", s, yylineno, yytext); } + +struct decl *root = NULL; %} /* Keywords */ @@ -17,7 +20,6 @@ void yyerror(const char *s) { %token TOKEN_BOOLEAN %token TOKEN_CHAR %token TOKEN_ELSE -%token TOKEN_FALSE %token TOKEN_FLOAT %token TOKEN_FOR %token TOKEN_FUNCTION @@ -26,7 +28,6 @@ void yyerror(const char *s) { %token TOKEN_PRINT %token TOKEN_RETURN %token TOKEN_STRING -%token TOKEN_TRUE %token TOKEN_VOID %token TOKEN_WHILE @@ -62,47 +63,80 @@ void yyerror(const char *s) { %token TOKEN_COMMA /* Identifiers and Literals */ -%token TOKEN_ID -%token TOKEN_INT_LITERAL -%token TOKEN_FLOAT_LITERAL -%token TOKEN_CHAR_LITERAL -%token TOKEN_STRING_LITERAL +%token TOKEN_ID +%token TOKEN_INT_LITERAL +%token TOKEN_FLOAT_LITERAL +%token TOKEN_CHAR_LITERAL +%token TOKEN_STRING_LITERAL +%token TOKEN_TRUE +%token TOKEN_FALSE /* Error */ %token TOKEN_EOF %token TOKEN_ERROR +/* Types expected in AST */ +%union { + struct decl *decl; + struct stmt *stmt; + struct expr *expr; + struct param_list *param_list; + struct type *type; + + char c; + int i; + float f; + char* s; +}; + +%type prog decl_list decl decl_init +%type opt_expr_list expr_list opt_expr expr + expr1 expr2 expr3 expr4 expr5 expr6 expr7 expr8 expr9 + group lval factor index +%type opt_stmt_list stmt_list stmt closed_stmt open_stmt + if_cond if_stmt_closed if_stmt_open + for_header for_stmt_open for_stmt_closed + simple_stmt print_stmt return_stmt block_stmt +%type type_simple type_array type_array_sized type_func +%type opt_param_list param_list param + %% -prog : decl_list TOKEN_EOF +prog : decl_list TOKEN_EOF { $$ = $1; root = $$; YYACCEPT; } ; /* Declarations */ -decl_list : /* epsilon */ - | decl_list decl +decl_list : /* epsilon */ { $$ = NULL; } + | decl decl_list { $$ = $1; $$->next = $2; } ; decl : TOKEN_ID TOKEN_COLON type_simple TOKEN_SEMICOLON + { $$ = decl_create($1, $3, NULL, NULL, NULL); } | TOKEN_ID TOKEN_COLON type_array_sized TOKEN_SEMICOLON + { $$ = decl_create($1, $3, NULL, NULL, NULL); } | TOKEN_ID TOKEN_COLON type_func TOKEN_SEMICOLON + { $$ = decl_create($1, $3, NULL, NULL, NULL); } | decl_init ; decl_init : TOKEN_ID TOKEN_COLON type_simple TOKEN_ASSIGN expr TOKEN_SEMICOLON + { $$ = decl_create($1, $3, $5, NULL, NULL); } | TOKEN_ID TOKEN_COLON type_array_sized TOKEN_ASSIGN TOKEN_LBRACE opt_expr_list TOKEN_RBRACE TOKEN_SEMICOLON + { $$ = decl_create($1, $3, $6, NULL, NULL); } | TOKEN_ID TOKEN_COLON type_func TOKEN_ASSIGN TOKEN_LBRACE opt_stmt_list TOKEN_RBRACE + { $$ = decl_create($1, $3, NULL, $6, NULL); } ; /* Statements */ -opt_stmt_list : /* epsilon */ +opt_stmt_list : /* epsilon */ { $$ = NULL; } | stmt_list ; stmt_list : stmt - | stmt_list stmt + | stmt stmt_list { $$ = $1; $$->next = $2; } ; stmt : open_stmt @@ -119,160 +153,178 @@ open_stmt : if_stmt_open ; if_cond : TOKEN_IF TOKEN_LPAREN opt_expr TOKEN_RPAREN + { $$ = stmt_create_empty(STMT_IF_ELSE); $$->expr = $3; } ; if_stmt_closed : if_cond closed_stmt TOKEN_ELSE closed_stmt + { $$ = $1; $$->body = $2; $$->else_body = $4; } ; if_stmt_open : if_cond stmt + { $$ = $1; $$->body = $2; } | if_cond closed_stmt TOKEN_ELSE if_stmt_open + { $$ = $1; $$->body = $2; $$->else_body = $4;} ; for_header : TOKEN_FOR TOKEN_LPAREN opt_expr TOKEN_SEMICOLON opt_expr TOKEN_SEMICOLON opt_expr TOKEN_RPAREN + { $$ = stmt_create(STMT_FOR, NULL, $3, $5, $7, NULL, NULL, NULL); } -for_stmt_open : for_header open_stmt +for_stmt_open : for_header open_stmt { $$ = $1; $$->body = $2; } ; -for_stmt_closed : for_header closed_stmt +for_stmt_closed : for_header closed_stmt { $$ = $1; $$->body = $2; } ; /* Simple statements are not recursive */ simple_stmt : print_stmt | return_stmt | block_stmt - | decl - | expr TOKEN_SEMICOLON + | decl { $$ = stmt_create_empty(STMT_DECL), $$->decl = $1; } + | expr TOKEN_SEMICOLON { $$ = stmt_create_empty(STMT_EXPR), $$->expr = $1; } ; print_stmt : TOKEN_PRINT opt_expr_list TOKEN_SEMICOLON + { $$ = stmt_create_empty(STMT_PRINT); $$->expr = $2; } ; return_stmt : TOKEN_RETURN opt_expr TOKEN_SEMICOLON + { $$ = stmt_create_empty(STMT_RETURN); $$->expr = $2; } ; block_stmt : TOKEN_LBRACE stmt_list TOKEN_RBRACE + { $$ = stmt_create_empty(STMT_BLOCK); $$->body = $2; } ; /* Expressions */ -opt_expr_list : /* epsilon */ +opt_expr_list : /* epsilon */ { $$ = NULL; } | expr_list ; expr_list : expr - | expr_list TOKEN_COMMA expr + { $$ = expr_create(EXPR_LIST, $1, NULL); } + | expr TOKEN_COMMA expr_list + { $$ = expr_create(EXPR_LIST, $1, $3); } ; -opt_expr : /* epsilon */ +opt_expr : /* epsilon */ { $$ = NULL; } | expr ; expr : expr1 ; -expr1 : lval TOKEN_ASSIGN expr1 +expr1 : lval TOKEN_ASSIGN expr1 { expr_create(EXPR_ASSIGN, $1, $3); } | expr2 ; -lval : TOKEN_ID - | TOKEN_ID index +lval : TOKEN_ID { $$ = expr_create_name($1); } + | TOKEN_ID index { $$ = expr_create(EXPR_INDEX, expr_create_name($1), $2); } ; -expr2 : expr2 TOKEN_LOGICAL_OR expr3 +expr2 : expr2 TOKEN_LOGICAL_OR expr3 { $$ = expr_create(EXPR_OR, $1, $3); } | expr3 ; -expr3 : expr3 TOKEN_LOGICAL_AND expr4 +expr3 : expr3 TOKEN_LOGICAL_AND expr4 { $$ = expr_create(EXPR_AND, $1, $3); } | expr4 ; -expr4 : expr4 TOKEN_EQUAL expr5 - | expr4 TOKEN_NOT_EQUAL expr5 - | expr4 TOKEN_LESS expr5 - | expr4 TOKEN_LESS_OR_EQUAL expr5 - | expr4 TOKEN_GREATER expr5 - | expr4 TOKEN_GREATER_OR_EQUAL expr5 +expr4 : expr4 TOKEN_EQUAL expr5 { $$ = expr_create(EXPR_EQ, $1, $3); } + | expr4 TOKEN_NOT_EQUAL expr5 { $$ = expr_create(EXPR_NEQ, $1, $3); } + | expr4 TOKEN_LESS expr5 { $$ = expr_create(EXPR_LT, $1, $3); } + | expr4 TOKEN_LESS_OR_EQUAL expr5 { $$ = expr_create(EXPR_LEQ, $1, $3); } + | expr4 TOKEN_GREATER expr5 { $$ = expr_create(EXPR_GT, $1, $3); } + | expr4 TOKEN_GREATER_OR_EQUAL expr5 { $$ = expr_create(EXPR_GEQ, $1, $3); } | expr5 ; -expr5 : expr5 TOKEN_ADD expr6 - | expr5 TOKEN_MINUS expr6 +expr5 : expr5 TOKEN_ADD expr6 { $$ = expr_create(EXPR_ADD, $1, $3); } + | expr5 TOKEN_MINUS expr6 { $$ = expr_create(EXPR_SUB, $1, $3); } | expr6 ; -expr6 : expr6 TOKEN_MULTIPLY expr7 - | expr6 TOKEN_DIVIDE expr7 - | expr6 TOKEN_MODULO expr7 +expr6 : expr6 TOKEN_MULTIPLY expr7 { $$ = expr_create(EXPR_MUL, $1, $3); } + | expr6 TOKEN_DIVIDE expr7 { $$ = expr_create(EXPR_DIV, $1, $3); } + | expr6 TOKEN_MODULO expr7 { $$ = expr_create(EXPR_MOD, $1, $3); } | expr7 ; -expr7 : expr7 TOKEN_EXPONENT expr8 +expr7 : expr7 TOKEN_EXPONENT expr8 { $$ = expr_create(EXPR_EXP, $1, $3); } | expr8 ; -expr8 : TOKEN_MINUS expr8 - | TOKEN_LOGICAL_NOT expr8 +expr8 : TOKEN_MINUS expr8 { $$ = expr_create_unary(EXPR_NEG, $2); } + | TOKEN_LOGICAL_NOT expr8 { $$ = expr_create_unary(EXPR_NOT, $2); } | expr9 ; -expr9 : expr9 TOKEN_INCREMENT - | expr9 TOKEN_DECREMENT +expr9 : expr9 TOKEN_INCREMENT { $$ = expr_create_unary(EXPR_INCREMENT, $1); } + | expr9 TOKEN_DECREMENT { $$ = expr_create_unary(EXPR_DECREMENT, $1); } | group ; -group : TOKEN_LPAREN expr TOKEN_RPAREN +group : TOKEN_LPAREN expr TOKEN_RPAREN { $$ = $2; } | TOKEN_ID TOKEN_LPAREN opt_expr_list TOKEN_RPAREN + { $$ = expr_create(EXPR_CALL, expr_create_name($1), $3); } | TOKEN_ID index + { $$ = expr_create(EXPR_INDEX, expr_create_name($1), $2); } | factor ; -index : TOKEN_LBRACKET expr TOKEN_RBRACKET +index : TOKEN_LBRACKET expr TOKEN_RBRACKET { $$ = $2; } ; -factor : TOKEN_ID - | TOKEN_INT_LITERAL - | TOKEN_FLOAT_LITERAL - | TOKEN_CHAR_LITERAL - | TOKEN_STRING_LITERAL - | TOKEN_TRUE - | TOKEN_FALSE +factor : TOKEN_ID { $$ = expr_create_name($1); } + | TOKEN_INT_LITERAL { $$ = expr_create_integer_literal($1); } + | TOKEN_FLOAT_LITERAL { $$ = expr_create_float_literal($1); } + | TOKEN_CHAR_LITERAL { $$ = expr_create_char_literal($1); } + | TOKEN_STRING_LITERAL { $$ = expr_create_string_literal($1); } + | TOKEN_TRUE { $$ = expr_create_boolean_literal(1); } + | TOKEN_FALSE { $$ = expr_create_boolean_literal(0); } ; /* Types */ -type_simple : TOKEN_INTEGER - | TOKEN_FLOAT - | TOKEN_BOOLEAN - | TOKEN_CHAR - | TOKEN_STRING - | TOKEN_VOID +type_simple : TOKEN_INTEGER { $$ = type_create(TYPE_INTEGER); } + | TOKEN_FLOAT { $$ = type_create(TYPE_FLOAT); } + | TOKEN_BOOLEAN { $$ = type_create(TYPE_BOOLEAN); } + | TOKEN_CHAR { $$ = type_create(TYPE_CHAR); } + | TOKEN_STRING { $$ = type_create(TYPE_STRING); } + | TOKEN_VOID { $$ = type_create(TYPE_VOID); } ; type_array : TOKEN_ARRAY TOKEN_LBRACKET TOKEN_RBRACKET type_simple + { $$ = type_create_array($4, NULL); } | TOKEN_ARRAY TOKEN_LBRACKET TOKEN_RBRACKET type_array + { $$ = type_create_array($4, NULL); } ; type_array_sized : TOKEN_ARRAY index type_simple + { $$ = type_create_array($3, $2); } | TOKEN_ARRAY index type_array_sized + { $$ = type_create_array($3, $2); } ; type_func : TOKEN_FUNCTION type_simple TOKEN_LPAREN opt_param_list TOKEN_RPAREN + { $$ = type_create_func($2, $4); } | TOKEN_FUNCTION type_array_sized TOKEN_LPAREN opt_param_list TOKEN_RPAREN + { $$ = type_create_func($2, $4); } ; -opt_param_list : /* epsilon */ +opt_param_list : /* epsilon */ { $$ = NULL; } | param_list ; param_list : param - | param_list TOKEN_COMMA param + | param_list TOKEN_COMMA param { $$ = $1; $1->next = $3; } ; -param : TOKEN_ID TOKEN_COLON type_simple - | TOKEN_ID TOKEN_COLON type_array - | TOKEN_ID TOKEN_COLON type_array_sized +param : TOKEN_ID TOKEN_COLON type_simple { $$ = param_list_create($1, $3, NULL); } + | TOKEN_ID TOKEN_COLON type_array { $$ = param_list_create($1, $3, NULL); } + | TOKEN_ID TOKEN_COLON type_array_sized { $$ = param_list_create($1, $3, NULL); } ; %% diff --git a/lex.yy.l b/lex.yy.l index 055a7a3..7faa2ff 100644 --- a/lex.yy.l +++ b/lex.yy.l @@ -44,23 +44,27 @@ while { printf("WHILE\n"); return TOKEN_WHILE; } [a-zA-Z_][a-zA-Z0-9_]* { printf("IDENTIFIER: %s\n", yytext); + yylval.s = strdup(yytext); return TOKEN_ID; } [1-9][0-9]*|0 { printf("INTEGER_LITERAL: %s\n", yytext); + yylval.i = atoi(yytext); return TOKEN_INT_LITERAL; } [0-9]*\.[0-9]+ { /* Float without decimal point */ printf("TOKEN_FLOAT_LITERAL: %s\n", yytext); + yylval.f = atof(yytext); return TOKEN_FLOAT_LITERAL; } [0-9]*(\.[0-9]+)?[eE][+-]?[1-9]+[0-9]* { /* Float with scientific notation */ printf("TOKEN_FLOAT_LITERAL: %s\n", yytext); + yylval.f = atof(yytext); return TOKEN_FLOAT_LITERAL; } @@ -80,6 +84,7 @@ while { printf("WHILE\n"); return TOKEN_WHILE; } printf("encoded: %s\n", es); es[strlen(es) - 1] = '\0'; printf("CHAR_LITERAL: %s\n", es + 1); + yylval.c = s[0]; return TOKEN_CHAR_LITERAL; } else { printf("ERROR: Invalid character literal: %s\n", yytext); @@ -127,6 +132,7 @@ while { printf("WHILE\n"); return TOKEN_WHILE; } char es[strlen(yytext) + 1]; string_encode((const char*) s, es); printf("STRING_LITERAL: %s\n", es); + yylval.s = strdup(s); return TOKEN_STRING_LITERAL; } else { printf("ERROR: Invalid string literal: %s\n", yytext); diff --git a/param_list.c b/param_list.c new file mode 100644 index 0000000..274429b --- /dev/null +++ b/param_list.c @@ -0,0 +1,24 @@ +#include +#include +#include "param_list.h" + +struct param_list* param_list_create(char* name, struct type* type, struct param_list* next) +{ + struct param_list* p = malloc(sizeof(*p)); + p->name = name; + p->type = type; + p->next = next; + return p; +} + +void param_list_print(struct param_list* p) +{ + if (!p) return; + printf("%s: ", p->name); + type_print(p->type); + if (p->next) + { + printf(", "); + param_list_print(p->next); + } +} \ No newline at end of file diff --git a/param_list.h b/param_list.h index 22083ad..67f8ffb 100755 --- a/param_list.h +++ b/param_list.h @@ -1,20 +1,16 @@ - #ifndef PARAM_LIST_H #define PARAM_LIST_H #include "type.h" -#include - -struct expr; -struct param_list { - char *name; - struct type *type; - struct symbol *symbol; - struct param_list *next; +struct param_list +{ + char* name; + struct type* type; + struct param_list* next; }; -struct param_list * param_list_create( char *name, struct type *type, struct param_list *next ); -void param_list_print( struct param_list *a ); +struct param_list* param_list_create(char* name, struct type* type, struct param_list* next); +void param_list_print(struct param_list* a); #endif diff --git a/parser.c b/parser.c index 715ea85..d3389be 100644 --- a/parser.c +++ b/parser.c @@ -1,19 +1,15 @@ #include +#include "parser.h" extern int yyparse(); -extern FILE* yyin; +extern void yyrestart(FILE*); extern int yydebug; +extern struct decl* root; -int parse(const char* filename) +struct decl* parse(FILE* fp) { yydebug = 0; - yyin = fopen(filename, "r"); - if (!yyin) - { - fprintf(stderr, "Could not open file %s\n", filename); - return 1; - } - int result = yyparse(); - fclose(yyin); - return result; -} \ No newline at end of file + yyrestart(fp); + yyparse(); + return root; +} diff --git a/parser.h b/parser.h index e5b30b9..6c9945b 100644 --- a/parser.h +++ b/parser.h @@ -1 +1 @@ -int parse(char* filename); \ No newline at end of file +struct decl* parse(FILE* fp); diff --git a/printer.c b/printer.c new file mode 100644 index 0000000..215d83f --- /dev/null +++ b/printer.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include "printer.h" +#include "parser.h" + +void print(struct decl* d) +{ + decl_print(d, 0); +} + +int fprint(struct decl* d, FILE* fp) +{ + int fd = fileno(fp); + int saved_stdout = dup(STDOUT_FILENO); + if (dup2(fd, STDOUT_FILENO) == -1) + { + fprintf(stderr, "Failed to redirect stdout to file\n"); + return 1; + } + print(d); + dup2(saved_stdout, STDOUT_FILENO); + close(saved_stdout); + return 0; +} + +int print_and_compare(char* filename, FILE* fp) +{ + // FIXME: "syntax error at line 1 near ''" when printing the second file + // TODO: Suppress output from scanner and printer + // Parse the input file + struct decl* d1 = parse(fp); + if (d1 == NULL) + { + printf("Failed to parse file %s before printing\n", filename); + return EXIT_FAILURE; + } + printf("\n======== Printing started ========\n\n"); + print(d1); + + // Construct filenames + char* ext_out = ".out"; + char* ext_tmp = ".tmp"; + char* output = malloc(strlen(filename) + strlen(ext_out) + 1); + char* temp = malloc(strlen(filename) + strlen(ext_tmp) + 1); + if (output == NULL || temp == NULL) + { + fprintf(stderr, "Failed to allocate memory for output filename\n"); + return EXIT_FAILURE; + } + strcpy(output, filename); + strcat(output, ext_out); + strcpy(temp, filename); + strcat(temp, ext_tmp); + + // Open output file for printing + FILE* fp_out = fopen(output, "w+"); + if (fp_out == NULL) + { + fprintf(stderr, "Failed to open file %s for printing\n", output); + return EXIT_FAILURE; + } + + // Print the AST to the output file + if (fprint(d1, fp_out)) + { + fprintf(stderr, "Failed to print file %s\n", filename); + fclose(fp_out); + return EXIT_FAILURE; + } + else + { + printf("Successfully printed to file %s\n", output); + } + + // Parse the output file + struct decl* d2 = parse(fp_out); + fclose(fp_out); + if (d2 == NULL) + { + fprintf(stderr, "Failed to parse file %s after printing\n", output); + return EXIT_FAILURE; + } + + // Open temp file for printing + FILE* fp_tmp = fopen(temp, "w"); + if (fp_tmp == NULL) + { + fprintf(stderr, "Failed to open file %s for printing\n", temp); + return EXIT_FAILURE; + } + + // Print the AST to the temp file + if (fprint(d2, fp_tmp)) + { + fprintf(stderr, "Failed to print to file %s\n", temp); + return EXIT_FAILURE; + } + else + { + printf("Successfully printed to file %s\n", temp); + } + + // Compare the output and temp files + char* command = malloc(strlen(output) + strlen(temp) + 7); + sprintf(command, "diff %s %s", output, temp); + int ret = system(command); + switch (ret) + { + case -1: + fprintf(stderr, "Failed to execute diff command\n"); + return EXIT_FAILURE; + case 0: + printf("Successfully printed and verified\n"); + remove(temp); + return EXIT_SUCCESS; + default: + fprintf(stderr, "Successfully printed but failed to verify\n"); + return EXIT_FAILURE; + } +} diff --git a/printer.h b/printer.h new file mode 100644 index 0000000..49aa7a0 --- /dev/null +++ b/printer.h @@ -0,0 +1,4 @@ +#include "decl.h" + +void print(struct decl* d); +int print_and_compare(char* filename, FILE* fp); diff --git a/runtest.sh b/runtest.sh index 0d4bcbf..b41acc2 100755 --- a/runtest.sh +++ b/runtest.sh @@ -9,6 +9,17 @@ fi module="$1" +printer_test () { + for testfile in ./test/printer/good*.bminor; do + if bminor --print "$testfile" 2>/dev/null; then + echo "$testfile success (as expected)" + else + echo "$testfile failure (INCORRECT)" + fi + done + exit 0 +} + case $module in "encoder") command="encode" @@ -19,6 +30,9 @@ case $module in "parser") command="parse" ;; + "printer") + printer_test + ;; *) echo "Unknown module: $module" exit 1 @@ -33,6 +47,14 @@ for testfile in ./test/"$module"/good*.bminor; do fi done +for testfile in ./test/"$module"/good*.bminor; do + if bminor --"$command" "$testfile" > "$testfile.out"; then + echo "$testfile success (as expected)" + else + echo "$testfile failure (INCORRECT)" + fi +done + for testfile in ./test/"$module"/bad*.bminor; do if bminor --"$command" "$testfile" > "$testfile.out"; then echo "$testfile success (INCORRECT)" diff --git a/scanner.c b/scanner.c index 951a806..faa3e74 100644 --- a/scanner.c +++ b/scanner.c @@ -5,25 +5,16 @@ extern FILE* yyin; extern int yylex(); extern char* yytext; -int scan(const char* filename) +int scan(FILE* fp) { - yyin = fopen(filename, "r"); - if (yyin == NULL) - { - printf("Could not open file %s\n", filename); - return 1; - } - + yyin = fp; int token = 1; // Initialize to a non-zero value while (token != TOKEN_EOF) { // Handle the tokens - if (token == TOKEN_ERROR) { + if (token == TOKEN_ERROR) return 1; - } token = yylex(); } - - fclose(yyin); return 0; } \ No newline at end of file diff --git a/scanner.h b/scanner.h index 1220748..257ae87 100644 --- a/scanner.h +++ b/scanner.h @@ -1 +1 @@ -int scan(const char* filename); \ No newline at end of file +int scan(FILE *fp); \ No newline at end of file diff --git a/stmt.c b/stmt.c new file mode 100644 index 0000000..682aff2 --- /dev/null +++ b/stmt.c @@ -0,0 +1,148 @@ +#include +#include +#include "stmt.h" + +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->kind = kind; + s->decl = decl; + s->init_expr = init_expr; + s->expr = expr; + s->next_expr = next_expr; + s->body = body; + s->else_body = else_body; + s->next = next; + return s; +} + +struct stmt* stmt_create_empty(stmt_t kind) +{ + return stmt_create( + kind, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + ); +} + +/* Print a statement */ + +void stmt_print_indent(int indent) +{ + for (int i = 0; i < indent; i++) + printf("\t"); +} + +void stmt_print_if_else(const struct stmt* s, int indent) +{ + stmt_print_indent(indent); + printf("if ("); + expr_print(s->expr); + printf(")\n"); + + if (s->body) + { + if (s->body->kind == STMT_BLOCK) + stmt_print(s->body, indent); + else + stmt_print(s->body, indent + 1); + } + + if (s->else_body) + { + stmt_print_indent(indent); + printf("else\n"); + if (s->else_body->kind == STMT_BLOCK) + stmt_print(s->else_body, indent); + else + stmt_print(s->else_body, indent + 1); + } +} + +void stmt_print_for(const struct stmt* s, int indent) +{ + stmt_print_indent(indent); + printf("for ("); + if (s->init_expr) + { + expr_print(s->init_expr); + printf("; "); + } + else printf(";"); + if (s->next_expr) + { + expr_print(s->expr); + printf("; "); + } + else printf(";"); + if (s->next_expr) + expr_print(s->next_expr); + printf(")\n"); + + if (s->body->kind == STMT_BLOCK) + stmt_print(s->body, indent); + else + stmt_print(s->body, indent + 1); +} + +void stmt_print(const struct stmt* s, int indent) +{ + switch (s->kind) + { + case STMT_DECL: + decl_print(s->decl, indent); + printf(";\n"); + break; + case STMT_EXPR: + stmt_print_indent(indent); + expr_print(s->expr); + printf(";\n"); + break; + case STMT_IF_ELSE: + stmt_print_if_else(s, indent); + break; + case STMT_FOR: + stmt_print_for(s, indent); + break; + case STMT_PRINT: + stmt_print_indent(indent); + printf("print "); + expr_print(s->expr); + printf(";\n"); + break; + case STMT_RETURN: + stmt_print_indent(indent); + printf("return"); + if (s->expr) + { + printf(" "); + expr_print(s->expr); + } + printf(";\n"); + break; + case STMT_BLOCK: + stmt_print_indent(indent); + printf("{\n"); + stmt_print(s->body, indent + 1); + stmt_print_indent(indent); + printf("}\n"); + break; + } + + if (s->next) + stmt_print(s->next, indent); +} diff --git a/stmt.h b/stmt.h index c89610a..dcb89a1 100755 --- a/stmt.h +++ b/stmt.h @@ -1,10 +1,10 @@ - #ifndef STMT_H #define STMT_H #include "decl.h" -typedef enum { +typedef enum +{ STMT_DECL, STMT_EXPR, STMT_IF_ELSE, @@ -14,19 +14,31 @@ typedef enum { STMT_BLOCK } stmt_t; -struct stmt { +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* decl; + struct expr* init_expr; + struct expr* expr; + struct expr* next_expr; + struct stmt* body; + struct stmt* else_body; + struct stmt* next; }; -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 ); -void stmt_print( struct stmt *s, int indent ); +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* stmt_create_empty(stmt_t kind); +void stmt_print(const struct stmt* s, int indent); #endif diff --git a/test/printer/good00.bminor b/test/printer/good00.bminor new file mode 100644 index 0000000..034c43a --- /dev/null +++ b/test/printer/good00.bminor @@ -0,0 +1,12 @@ +/* Variable declarations */ +a: integer; +z: integer = a; +b: integer = 123; +c: float = 45.67; +d: boolean = false; +e: char = 'q'; +f: string = "hello bminor\n"; +g: array [x] integer; +h: array [2] boolean = {true, false}; +i: array [2] array [x] boolean; +j: array [2] integer = {x + y, 1 / 3}; diff --git a/test/printer/good01.bminor b/test/printer/good01.bminor new file mode 100644 index 0000000..872e0e3 --- /dev/null +++ b/test/printer/good01.bminor @@ -0,0 +1,17 @@ +/* Function declarations */ +main : function integer (args: string) = { + print "hello", "world"; + return 0; +} + +x: integer = 2; + +main : function array [x] integer (args: string) = { + print "hello", "world"; + return 0; +} + +main : function integer (args: string, ints: array [] integer) = { + print "hello", "world"; + return 0; +} \ No newline at end of file diff --git a/test/printer/good02.bminor b/test/printer/good02.bminor new file mode 100644 index 0000000..a898ccb --- /dev/null +++ b/test/printer/good02.bminor @@ -0,0 +1,20 @@ +/* Complex for loops */ +main : function integer (args: array [] string) = { + str: string = "Hello World"; + i: integer = 0; + for (i = 0; i < 10; i++) { + print str; + } + + for (;;) { + print str; + } + + for (;;) { + print str; + for (;;) { + print str; + } + } + return 0; +} \ No newline at end of file diff --git a/test/printer/good03.bminor b/test/printer/good03.bminor new file mode 100644 index 0000000..c436763 --- /dev/null +++ b/test/printer/good03.bminor @@ -0,0 +1,5 @@ +/* Simple for loop */ +main : function void () = { + for (;;) + print "Hello"; +} \ No newline at end of file diff --git a/test/printer/good04.bminor b/test/printer/good04.bminor new file mode 100644 index 0000000..3af4913 --- /dev/null +++ b/test/printer/good04.bminor @@ -0,0 +1,11 @@ +/* If conditions */ +main : function void () = { + if (true) { + print "Hello"; + } else { + print "World"; + } + + if ( x + y <= 0 ) + print "Hello"; +} \ No newline at end of file diff --git a/test/printer/good05.bminor b/test/printer/good05.bminor new file mode 100644 index 0000000..6c2712a --- /dev/null +++ b/test/printer/good05.bminor @@ -0,0 +1,4 @@ +/* Expressions with parentheses */ +x: integer = x + y * 2; +x: integer = (x + y) * 2; +x: integer = (1 + 2 * (x + y)) * 2; diff --git a/test/printer/good06.bminor b/test/printer/good06.bminor new file mode 100644 index 0000000..12e23d4 --- /dev/null +++ b/test/printer/good06.bminor @@ -0,0 +1,18 @@ +/* Nested if conditions */ +main : function void () = { + if (true) { + print "Hello"; + } else { + print "World"; + } + + if ( x + y <= 0 ) + if (x) + print "x"; + + if ( x + y <= 0 ) + if (x) + print "x"; + else + print "y"; +} diff --git a/test/printer/good07.bminor b/test/printer/good07.bminor new file mode 100644 index 0000000..d32c057 --- /dev/null +++ b/test/printer/good07.bminor @@ -0,0 +1,8 @@ +/* Mixed precedence */ +x: integer = x + y * 2; +x: integer = (x + y) * 2; +x: integer = (1 + 2 * (x + y)) * 2; +x: integer = ( f(1, 2) + x[0] ) ^ 1 * 2 / 2; +x: integer = a || b && c; +x: integer = a && b || c; +x: integer = a && (b || c); diff --git a/test/printer/good08.bminor b/test/printer/good08.bminor new file mode 100644 index 0000000..5580ead --- /dev/null +++ b/test/printer/good08.bminor @@ -0,0 +1,7 @@ +/* Unary precedence */ +x: integer = x++; +x: integer = (x++)--; +x: integer = -x + 1; +x: integer = (-x + 1)--; +x: integer = !(!x); +x: integer = (x + y) * -1; diff --git a/test/printer/good09.bminor b/test/printer/good09.bminor new file mode 100644 index 0000000..6de97e9 --- /dev/null +++ b/test/printer/good09.bminor @@ -0,0 +1,11 @@ +/* If condition in loops */ +main : function void () = { + for (;;) { + if (true) + x++; + else { + x--; + return; + } + } +} diff --git a/test/printer/good10.bminor b/test/printer/good10.bminor new file mode 100644 index 0000000..6de97e9 --- /dev/null +++ b/test/printer/good10.bminor @@ -0,0 +1,11 @@ +/* If condition in loops */ +main : function void () = { + for (;;) { + if (true) + x++; + else { + x--; + return; + } + } +} diff --git a/type.c b/type.c new file mode 100644 index 0000000..e1d6d89 --- /dev/null +++ b/type.c @@ -0,0 +1,83 @@ +#include +#include +#include "type.h" + +/* Creating the types */ + +struct type* type_create(type_t kind) +{ + struct type* t = malloc(sizeof(*t)); + t->kind = kind; + return t; +} + +struct type* type_create_array(struct type* subtype, struct expr* size) +{ + struct type* t = type_create(TYPE_ARRAY); + t->subtype = subtype; + t->size = size; + return t; +} + +struct type* type_create_func(struct type* rtype, struct param_list* params) +{ + struct type* t = type_create(TYPE_FUNCTION); + t->subtype = rtype; + t->params = params; + return t; +} + +/* Printing the types */ + +void type_print_primitive(struct type* t) +{ + switch (t->kind) + { + case TYPE_INTEGER: + printf("integer"); + break; + case TYPE_FLOAT: + printf("float"); + break; + case TYPE_CHAR: + printf("char"); + break; + case TYPE_VOID: + printf("void"); + break; + case TYPE_BOOLEAN: + printf("boolean"); + break; + case TYPE_STRING: + printf("string"); + break; + default: + /* Compound types handled in type_print() */ + break; + } +} + +void type_print(struct type* t) +{ + switch (t->kind) + { + case TYPE_ARRAY: + printf("array ["); + if (t->size != NULL) + expr_print(t->size); + printf("] "); + type_print(t->subtype); + break; + case TYPE_FUNCTION: + printf("function "); + type_print(t->subtype); + printf(" ("); + param_list_print(t->params); + printf(")"); + break; + default: + /* Primitive types */ + type_print_primitive(t); + break; + } +} \ No newline at end of file diff --git a/type.h b/type.h index aa0604d..4df3a05 100755 --- a/type.h +++ b/type.h @@ -2,24 +2,33 @@ #define TYPE_H #include "param_list.h" +#include "expr.h" -typedef enum { +typedef enum +{ TYPE_VOID, TYPE_BOOLEAN, - TYPE_CHARACTER, + TYPE_CHAR, TYPE_INTEGER, + TYPE_FLOAT, TYPE_STRING, TYPE_ARRAY, TYPE_FUNCTION, } type_t; -struct type { +struct type +{ type_t kind; - struct param_list *params; - struct type *subtype; + struct type* subtype; + struct expr* size; + struct param_list* params; }; -struct type * type_create( type_t kind, struct type *subtype, struct param_list *params ); -void type_print( struct type *t ); +/* Creating types */ +struct type* type_create(type_t kind); +struct type* type_create_array(struct type* subtype, struct expr* size); +struct type* type_create_func(struct type* rtype, struct param_list* params); + +void type_print(struct type* t); #endif