#include "parser.h" #include "expr.h" #include "statement.h" #include "token.h" #include #include #include Expr* Expression(void); Expr* Equality(void); Expr* Comparison(void); Expr* Term(void); Expr* Factor(void); Expr* Unary(void); Expr* Primary(void); Stmt* Statement(void); Stmt* PrintStatement(void); Stmt* ExpressionStatement(void); StatementList* CreateStatementList(void); int AddStatementToList(Stmt*, StatementList*); int Match(int, ...); int Check(TokenType); int ParserAtEnd(void); Token* ParserPeek(void); Token* Previous(void); Token* AdvanceParser(void); void SynchronizeParser(void); void FreeExpressionTree(Expr*); const TokenList* ListOfTokens; int Current = 0; StatementList* Parse(const TokenList* list) { ListOfTokens = list; StatementList* statements = CreateStatementList(); Stmt* statement = NULL; if (!statements) return NULL; while(!ParserAtEnd()) { statement = Statement(); if (!statement) { fprintf(stderr, "[Warn] No statement generated\n"); continue; } AddStatementToList(statement, statements); } return statements; } //Simply expands the equality rule Expr* Expression() { return Equality(); } Stmt* Statement(void) { if (Match(1, PRINT)) return PrintStatement(); return ExpressionStatement(); } Stmt* PrintStatement(void) { Expr* value = Expression(); if (!Match(1, Semicolon)) { fprintf(stderr, "Expected ';' after value\n"); return NULL; } AdvanceParser(); return CreateStatement(value, STMT_Print); } Stmt* ExpressionStatement(void) { Expr* expr = Expression(); if (!Match(1, Semicolon)) { fprintf(stderr, "Expected ';' after expression\n"); return NULL; } AdvanceParser(); return CreateStatement(expr, STMT_Expression); } Stmt* ExpressionStatement(void); Expr* Equality() { Expr* expr = Comparison(); while(Match(2, Bang_Equal, Equal_Equal)) { Token* operator = Previous(); Expr* right = Comparison(); Expr* temp = calloc(1, sizeof(Expr)); temp->type = BINARY; temp->expression.Binary.left = expr; temp->expression.Binary.op = operator; temp->expression.Binary.right = right; expr = temp; } return expr; } Expr* Comparison() { Expr* expr = Term(); while(Match(4, Greater, Greater_Equal, Less, Less_Equal)) { Token* operator = Previous(); Expr* right = Term(); Expr* temp = calloc(1, sizeof(Expr)); temp->type = BINARY; temp->expression.Binary.left = expr; temp->expression.Binary.op = operator; temp->expression.Binary.right = right; expr = temp; } return expr; } Expr* Term() { Expr* expr = Factor(); while(Match(2, Minus, Plus)) { Token* operator = Previous(); Expr* right = Factor(); Expr* temp = calloc(1, sizeof(Expr)); temp->type = BINARY; temp->expression.Binary.left = expr; temp->expression.Binary.op = operator; temp->expression.Binary.right = right; expr = temp; } return expr; } Expr* Factor() { Expr* expr = Unary(); while(Match(2, Slash, Star)) { Token* operator = Previous(); Expr* right = Unary(); Expr* temp = calloc(1, sizeof(Expr)); temp->type = BINARY; temp->expression.Binary.left = expr; temp->expression.Binary.op = operator; temp->expression.Binary.right = right; expr = temp; } return expr; } Expr* Unary() { if (Match(2, Bang, Minus)) { Token* operator = Previous(); Expr* right = Unary(); Expr* expr = calloc(1, sizeof(Expr)); expr->type = UNARY; expr->expression.Unary.op = operator; expr->expression.Unary.right = right; return expr; } return Primary(); } Expr* Primary() { Expr* expr = calloc(1, sizeof(Expr)); expr->type = LITERAL; if (Match(3, FALSE, TRUE, NIL)) { expr->expression.Literal = ParserPeek(); return expr; } if (Match(2, Number, String)) { expr->expression.Literal = Previous(); return expr; } free(expr); if (Match(1, LParen)) { expr = Expression(); if (!Check(RParen)) { free(expr); printf("Unbalanced\n"); //Todo: something or another... return NULL; } //Consume(RParen, "Expect ')' after expression."); Expr* temp = calloc(1, sizeof(Expr)); temp->type = GROUPING; temp->expression.Grouping.expression = expr; return temp; } fprintf(stderr, "Bad expression, this should be unreachable.\n"); return NULL; } int Match(int count, ...) { va_list list; va_start(list, count); for(int i = 0; i < count; i++) { if(Check(va_arg(list, TokenType))) { va_end(list); AdvanceParser(); return 1; } } va_end(list); return 0; } int Check(TokenType type) { if (ParserAtEnd()) return 0; return ParserPeek()->type == type; } int ParserAtEnd() { return ParserPeek()->type == EndOF; } Token* ParserPeek() { return ListOfTokens->tokens[Current]; } Token* Previous() { return ListOfTokens->tokens[Current - 1]; } Token* AdvanceParser() { if (!ParserAtEnd()) Current++; return Previous(); } //In the Java implementation this get's called in catch blocks. //Obviously that's not going to fly in C, so I need some way to //"unwind" the stack. Maybe synchronizing (setting the Current variable) //will be enough, and simply return NULLs up the call stack. //Naive but might work in the future for this. void SynchronizeParser(void) { AdvanceParser(); //Discard tokens until we find a statement boundary, or at least something that looks like one. while(!ParserAtEnd()) { if (Previous()->type == Semicolon) return; switch(ParserPeek()->type) { case CLASS: case FOR: case FUN: case IF: case PRINT: case RETURN: case VAR: case WHILE: return; default: break; } AdvanceParser(); } } void PrintExpressionTree(const Expr* tree) { if (!tree) return; if (tree->type == BINARY) { printf("("); PrintExpressionTree(tree->expression.Binary.left); PrintExpressionTree(tree->expression.Binary.right); printf("%s", tree->expression.Binary.op->lexeme); printf(")"); } else if (tree->type == UNARY) { printf("("); printf("%s", tree->expression.Unary.op->lexeme); PrintExpressionTree(tree->expression.Unary.right); printf(")"); } else if (tree->type == GROUPING) { PrintExpressionTree(tree->expression.Grouping.expression); } else if (tree->type == LITERAL) printf("%s", tree->expression.Literal->lexeme); } void FreeExpressionTree(Expr* tree) { if (!tree) return; if (tree->type == BINARY) { FreeExpressionTree(tree->expression.Binary.left); FreeExpressionTree(tree->expression.Binary.right); } else if (tree->type == UNARY) { FreeExpressionTree(tree->expression.Unary.right); } free(tree); } void FreeStatementList(StatementList* list) { if (!list) return; for(int i = 0; i < list->size; i++) { FreeExpressionTree(list->content[i]->expression); free(list->content[i]); } free(list); } StatementList* CreateStatementList(void) { StatementList* list = calloc(1, sizeof(StatementList)); if (!list) { fprintf(stderr, "Failed to calloc StatementList. %s\n", strerror(errno)); return NULL; } list->content = calloc(STATEMENTLIST_DEFAULT_SIZE, sizeof(Stmt)); if (!list->content) { fprintf(stderr, "Failed to calloc StatementList contents. %s\n", strerror(errno)); free(list); return NULL; } list->capacity = STATEMENTLIST_DEFAULT_SIZE; return list; } int AddStatementToList(Stmt* statement, StatementList* list) { if (!statement || !list) return 0; if (list->size == list->capacity) { void* new_ptr = realloc(list->content, sizeof(Stmt) * list->capacity * 2); if (!new_ptr) { fprintf(stderr, "Failed to realloc StatmentList to size %d. %s\n", list->capacity * 2, strerror(errno)); return 0; } list->content = new_ptr; list->capacity *= 2; } list->content[list->size] = statement; list->size++; return 1; }