#include "../includes/parser.h" #include #include #include typedef enum { NoOptions = 0, ForwardParser = 1, RemoveExpected = 2 } ExpectOptions; List* TokensList; int CurrentToken = 0; void PrintSymbols(void); void RemoveCurrentToken(void); void HandleAssemblerDirective(void); void HandleOpcode(void); void AdvanceParser(void); void IgnoreParserLine(void); Token* PeekToken(void); int ParserAtEnd(void); IRState MachineState; void ExpectPuncuation(TokenPunctuation punctuation, ExpectOptions options); void ExpectRegister(void); Symbol* ExpectIdentifier(int resolved, ExpectOptions options); void ExpectCharacterClass(Symbol* symbol); void ExpectLineEndOrFileEnd(ExpectOptions options); int HeapSize = 0; int PC = 0; IRState* ParseTokens(List* tokens) { if (!tokens) return NULL; TokensList = tokens; MachineState.SymbolsTable = CreateSymbolTable(); MachineState.Instructions = CreateList(); while(!ParserAtEnd()) { Token* t = PeekToken(); if (!t || t->EndOfFile) break; switch(t->Class) { case DirectiveClass: HandleAssemblerDirective(); break; case MnemonicClass: HandleOpcode(); break; case LabelClass: { Symbol* symbol; int found = TryGetSymbol(t->Lemexe, MachineState.SymbolsTable, &symbol); if (found && symbol->Resolved) { fprintf(stderr, "[Error] Line %d: Redefinition of symbol '%s'\n", t->LineNumber, t->Lemexe); exit(1); } if (!found) AddSymbolToTable(t->Lemexe, HeapSize, 1, MachineState.SymbolsTable); else symbol->Resolved = 1; RemoveCurrentToken(); //label ExpectLineEndOrFileEnd(RemoveExpected); } break; default: fprintf(stderr, "[Warning] Line %d: Syntax error, expected start of expression, got '%c' [%d].\n", t->LineNumber, t->Value.Punctuation, t->Class); exit(1); //IgnoreParserLine(); break; } } PrintSymbols(); return &MachineState; } void HandleAssemblerDirective() { Token* directive = PeekToken(); switch(directive->Value.Directive){ case DB: { RemoveCurrentToken(); Symbol* symbol = ExpectIdentifier(1, RemoveExpected); if (PeekToken()->Class == CharacterClass) { ExpectCharacterClass(symbol); } else if (PeekToken()->Class == NumberClass) { symbol->Length = 2; RemoveCurrentToken(); //Clear the number token. ExpectLineEndOrFileEnd(RemoveExpected); } else if (PeekToken()->Class == IdentifierClass) { symbol = ExpectIdentifier(0, RemoveExpected); ExpectLineEndOrFileEnd(RemoveExpected); } HeapSize += symbol->Length; } break; default: fprintf(stderr, "Synatx error on line %d, %s.\n", directive->LineNumber, directive->Lemexe); exit(1); } } void HandleOpcode(void) { Token* opcode = PeekToken(); AdvanceParser(); switch(opcode->Value.Mnemonic) { case COPY: { Token* arg = PeekToken(); int isByte = 0; if (arg->Class == DirectiveClass) { if (arg->Value.Directive != Byte) { fprintf(stderr, "Syntax error on line %d: expected keyword 'byte'.\n", opcode->LineNumber); exit(1); } RemoveCurrentToken(); //byte isByte = 1; arg = PeekToken(); } if (arg->Class == RegisterClass) { ExpectRegister(); ExpectPuncuation(Comma, ForwardParser); arg = PeekToken(); if (arg->Class == NumberClass) { opcode->Value.Mnemonic = isByte ? COPYB : COPYI; opcode->Lemexe = isByte ? "copyb" : "copyi"; AdvanceParser(); } else if (arg->Class == RegisterClass) { if (isByte) { fprintf(stderr, "Syntax error on line %d: unexpected modifier 'Byte' for Register to Register copy.\n", opcode->LineNumber); exit(1); } ExpectRegister(); opcode->Value.Mnemonic = COPY; opcode->Lemexe = "copy"; } else if (arg->Class & IdentifierClass) { opcode->Value.Mnemonic = isByte ? COPYAB : COPYA; opcode->Lemexe = isByte ? "copyab" : "copya"; AdvanceParser(); } else { ExpectPuncuation(LBracket, ForwardParser); ExpectRegister(); ExpectPuncuation(RBracket, ForwardParser); opcode->Value.Mnemonic = isByte ? COPYRAB : COPYRA; opcode->Lemexe = isByte ? "copyrab" : "copyra"; } } else { ExpectPuncuation(LBracket, ForwardParser); ExpectRegister(); ExpectPuncuation(RBracket, ForwardParser); ExpectPuncuation(Comma, ForwardParser); ExpectPuncuation(LBracket, ForwardParser); ExpectRegister(); ExpectPuncuation(RBracket, ForwardParser); opcode->Value.Mnemonic = isByte ? COPYRARAB : COPYRARA; opcode->Lemexe = isByte ? "copyrarab" : "copyrara"; } } break; case CMP: { ExpectRegister(); ExpectPuncuation(Comma, ForwardParser); TokenClass class = PeekToken()->Class; if (class == NumberClass || class & IdentifierClass) { opcode->Value.Mnemonic = CMPI; opcode->Lemexe = "CMPI"; AdvanceParser(); } else { ExpectRegister(); } } break; case ADD: case SUB: case AND: case OR: case XOR: ExpectRegister(); ExpectPuncuation(Comma, ForwardParser); ExpectRegister(); break; case SHL: case SHR: ExpectRegister(); ExpectPuncuation(Comma, ForwardParser); if (PeekToken()->Class != NumberClass) { fprintf(stderr, "[Line %d] Syntax error, expected numeric literal.\n", PeekToken()->LineNumber); exit(12); } AdvanceParser(); break; case INC: case DEC: case PUSH: case POP: ExpectRegister(); break; case JMP: { Token* arg = PeekToken(); if (arg->Class & IdentifierClass) { ExpectIdentifier(0, ForwardParser); opcode->Value.Mnemonic = JMP; opcode->Lemexe = "jmp"; } else { ExpectPuncuation(LBracket, ForwardParser); ExpectRegister(); ExpectPuncuation(RBracket, ForwardParser); opcode->Value.Mnemonic = JMPI; opcode->Lemexe = "jmpi"; } } break; case JZ: { ExpectIdentifier(0, ForwardParser); opcode->Value.Mnemonic = JZ; opcode->Lemexe = "jz"; } break; case JG: { ExpectIdentifier(0, ForwardParser); opcode->Value.Mnemonic = JG; opcode->Lemexe = "jg"; } break; case JL: { ExpectIdentifier(0, ForwardParser); opcode->Value.Mnemonic = JL; opcode->Lemexe = "jl"; } break; case CALL: { Token* arg = PeekToken(); if ((arg->Class & IdentifierClass) == 0) { fprintf(stderr, "Syntax error on line %d: expected subroutine call target.\n", opcode->LineNumber); exit(1); } ExpectIdentifier(0, ForwardParser); } break; default: break; } ExpectLineEndOrFileEnd(ForwardParser); } void ExpectPuncuation(TokenPunctuation punctuation, ExpectOptions options) { Token* token = PeekToken(); if (token->Class != PunctuationClass || token->Value.Punctuation != punctuation) { fprintf(stderr, "[Line %d] Syntac error, expected %c.\n", token->LineNumber, punctuation); exit(1); } if (options & RemoveExpected) RemoveCurrentToken(); if (options & ForwardParser) AdvanceParser(); } void ExpectRegister() { Token* token = PeekToken(); if (token->Class != RegisterClass) { fprintf(stderr, "[Line %d] Syntax error, expected Register.\n", token->LineNumber); exit(2); } AdvanceParser(); } Symbol* ExpectIdentifier(int resolved, ExpectOptions options) { Token* token = PeekToken(); if (token->Class != IdentifierClass) { fprintf(stderr, "[Line %d] Expected Identifier.\n", token->LineNumber); exit(3); } Symbol* symbol; int found = TryGetSymbol(token->Lemexe, MachineState.SymbolsTable, &symbol); if (found && symbol->Resolved && resolved) { fprintf(stderr, "[Line %d] Redefinition of symbol '%s'.\n", token->LineNumber, token->Lemexe); exit(4); } if (found) { symbol->Address = HeapSize; symbol->Resolved = resolved || symbol->Resolved; } else { symbol = AddSymbolToTable(token->Lemexe, HeapSize, resolved, MachineState.SymbolsTable); } if (options & RemoveExpected) RemoveCurrentToken(); if (options & ForwardParser) AdvanceParser(); return symbol; } void ExpectCharacterClass(Symbol* symbol) { Token* token = PeekToken(); if (token->Class != CharacterClass) { fprintf(stderr, "[Line %d] Syntax error, expected character string.\n", token->LineNumber); exit(5); } symbol->Length = strlen(token->Lemexe); RemoveCurrentToken(); //Remove the string declared by this DB command. token = PeekToken(); if (token->EndOfFile) return; if (token->Class == PunctuationClass && token->Value.Punctuation == NewLine) { RemoveCurrentToken(); return; } ExpectPuncuation(Comma, RemoveExpected); token = PeekToken(); if (token->Class != NumberClass) { fprintf(stderr, "[Line %d] Syntax error, expected terminating byte.\n", token->LineNumber); exit(7); } RemoveCurrentToken(); //Remove terminating byte. //TODO: add the raw value of the byte to the end of the string, but for now just pretend all numbers are zero. symbol->Length++; ExpectLineEndOrFileEnd(RemoveExpected); } void ExpectLineEndOrFileEnd(ExpectOptions options) { Token* token = PeekToken(); if (token->EndOfFile) return; if (token->Class != PunctuationClass || token->Value.Punctuation != NewLine) { fprintf(stderr, "[Line %d] Syntax error, expected line break.\n", token->LineNumber); exit(9); } if (options & RemoveExpected) RemoveCurrentToken(); if (options & ForwardParser) AdvanceParser(); } void PrintSymbols(void) { //char mn[12]; printf("-----SYMBOLS-----\n"); for(int i = 0; i < MachineState.SymbolsTable->Size; i++) { Symbol* symbol = MachineState.SymbolsTable->Symbols[i]; printf("[%s] %s [%d] [Width: %d]", symbol->Resolved == 0 ? "Unresolved" : "Resolved", symbol->Name, symbol->Address, symbol->Length); printf("\n"); } printf("-----SYMBOLS-----\n"); } void AdvanceParser(void) { if (ParserAtEnd()) return; CurrentToken++; } int ParserAtEnd(void) { if (CurrentToken >= TokensList->size) return 1; return 0; } Token* PeekToken(void) { return TokensList->content[CurrentToken]; } void IgnoreParserLine(void) { while(!ParserAtEnd()) { if (PeekToken()->Class == PunctuationClass && PeekToken()->Value.Punctuation == NewLine) { AdvanceParser(); break; } if (PeekToken()->EndOfFile) break; AdvanceParser(); } } void RemoveCurrentToken(void) { RemoveItem(CurrentToken, TokensList); //if (CurrentToken > 0) CurrentToken--; }