#include "parser.h" #include "expr.h" #include "token.h" #include Expr* Expression(void); Expr* Equality(void); Expr* Comparison(void); Expr* Term(void); Expr* Factor(void); Expr* Unary(void); Expr* Primary(void); int Match(int, ...); int Check(TokenType); int ParserAtEnd(void); Token* ParserPeek(void); Token* Previous(void); Token* AdvanceParser(void); void SynchronizeParser(void); const TokenList* ListOfTokens; int Current = 0; Expr* GenerateExpressionTree(const TokenList* list) { ListOfTokens = list; return Expression(); } //Simply expands the equality rule Expr* Expression() { return Equality(); } 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; } printf("Bad expression\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))) { AdvanceParser(); return 1; } } 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); }