Files
assm-test/src/parser.c
T

470 lines
13 KiB
C

#include "../includes/parser.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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--;
}