476 lines
13 KiB
C
476 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";
|
|
|
|
ExpectIdentifier(0, ForwardParser);
|
|
}
|
|
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) {
|
|
opcode->Value.Mnemonic = CMPI;
|
|
opcode->Lemexe = "CMPI";
|
|
|
|
AdvanceParser();
|
|
}
|
|
else if (class & IdentifierClass) {
|
|
opcode->Value.Mnemonic = CMPI;
|
|
opcode->Lemexe = "CMPI";
|
|
|
|
ExpectIdentifier(0, ForwardParser);
|
|
}
|
|
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--;
|
|
} |