Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
307519a2b1 | ||
|
|
d3d2b06dbd |
@@ -1,5 +1,5 @@
|
|||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS=-g -Wall -DDEBUG -Wpedantic -Wextra -Wunused-result -std=c99 -pedantic-errors
|
CFLAGS=-g -Wall -DDEBUG -Wpedantic
|
||||||
SRCDIR=src
|
SRCDIR=src
|
||||||
OBJDIR=obj
|
OBJDIR=obj
|
||||||
SRCS=$(wildcard $(SRCDIR)/*.c)
|
SRCS=$(wildcard $(SRCDIR)/*.c)
|
||||||
@@ -11,7 +11,7 @@ BIN=$(BINDIR)/assm
|
|||||||
|
|
||||||
all: $(BIN)
|
all: $(BIN)
|
||||||
|
|
||||||
release: CFLAGS=-Wall -Wpedantic -std=c99 -pedantic-errors -O2
|
release: CFLAGS=-Wall -Wpedantic -O2
|
||||||
release: clean
|
release: clean
|
||||||
release: $(BIN)
|
release: $(BIN)
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ clean:
|
|||||||
rm -rf $(BINDIR)/* $(OBJDIR)/*
|
rm -rf $(BINDIR)/* $(OBJDIR)/*
|
||||||
|
|
||||||
test:
|
test:
|
||||||
$(BIN) misc/another_test.asm
|
$(BIN) misc/test.asm
|
||||||
|
|
||||||
disass:
|
disass:
|
||||||
objdump -S --disassemble $(OBJDIR)/$(FILE).o > $(OBJDIR)/$(FILE).s
|
objdump -S --disassemble $(OBJDIR)/$(FILE).o > $(OBJDIR)/$(FILE).s
|
||||||
+54
-97
@@ -8,12 +8,12 @@
|
|||||||
\title{Unnamed Machine}
|
\title{Unnamed Machine}
|
||||||
\author{A Very Terrible 16-bit Machine}
|
\author{A Very Terrible 16-bit Machine}
|
||||||
|
|
||||||
\newcommand{\OpcodeTable}[5] {
|
\newcommand{\OpcodeTable}[4] {
|
||||||
\begin{tabular}{ c c c c c }
|
\begin{tabular}{ c c c c }
|
||||||
\hline
|
\hline
|
||||||
Opcode & Bit Pattern & Mnemonic & Operand 1 & Operand 2 \\
|
Opcode & Mnemonic & Operand 1 & Operand 2 \\
|
||||||
\hline\hline
|
\hline\hline
|
||||||
#1 & #2 & #3 & #4 & #5 \\
|
#1 & #2 & #3 & #4 \\
|
||||||
\hline
|
\hline
|
||||||
\end{tabular}
|
\end{tabular}
|
||||||
}
|
}
|
||||||
@@ -53,135 +53,92 @@
|
|||||||
\end{figure}
|
\end{figure}
|
||||||
\chapter{Instruction Set Architecture}
|
\chapter{Instruction Set Architecture}
|
||||||
\section{Instruction Encoding}
|
\section{Instruction Encoding}
|
||||||
The instruction encoding is fixed width to exactly 8 bites wide.
|
Instructions are fixed to exactly one byte (8 bits).
|
||||||
The encoding for the instructions will differ depending on if the opcode requires a register as its first operand.
|
Instructions that work with two operands the register for operand one will be encoded in the three least significant bits. So an instruction with format XXXX X000 will use Register 1 and so forth all the way to XXXX X111, which will be Register 8.
|
||||||
For instructions that require, as their first argument, a register the encoding format will be as shown in Figure \ref{fig:WithRegister}.
|
|
||||||
The lower 3 bits may be any bit pattern as long as at least one bit is set in the upper 5 bits.
|
|
||||||
%https://tex.stackexchange.com/questions/32598/force-latex-image-to-appear-in-the-section-in-which-its-declared
|
%https://tex.stackexchange.com/questions/32598/force-latex-image-to-appear-in-the-section-in-which-its-declared
|
||||||
\begin{figure}[!htb]
|
\begin{figure}[!htb]
|
||||||
\centering
|
\centering
|
||||||
\begin{tabular}{ c c }
|
\begin{tabular}{ c c }
|
||||||
|
\hline
|
||||||
Instruction & Register \\
|
Instruction & Register \\
|
||||||
\hline
|
\hline\hline
|
||||||
XXXX X & 000 \\
|
0000 0 & 000 \\
|
||||||
\hline
|
\hline
|
||||||
\end{tabular}
|
\end{tabular}
|
||||||
\caption{Encoding Layout, Register Required}
|
\caption{Encoding Layout}
|
||||||
\label{fig:WithRegister}
|
|
||||||
\end{figure}
|
\end{figure}
|
||||||
|
|
||||||
Figure \ref{fig:NoRegisterEncoding} shows how encoding will look for instructions that lack arguments or do not require a register.
|
|
||||||
In contrast with the previous encoding scheme the upper 5 bits MUST be zero, allowing 7 possible instructions to use this format.
|
|
||||||
All zeroes is not considered a legal instruction.
|
|
||||||
|
|
||||||
\begin{figure}[!htb]
|
|
||||||
\centering
|
|
||||||
\begin{tabular}{ c c }
|
|
||||||
Must Be Zero & Instruction \\
|
|
||||||
\hline
|
|
||||||
0000 0 & XXX \\
|
|
||||||
\hline
|
|
||||||
\end{tabular}
|
|
||||||
\caption{Encoding Layout, No Register Required}
|
|
||||||
\label{fig:NoRegisterEncoding}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\section{Notes}
|
\section{Notes}
|
||||||
For the opcodes that load or store data at the assembly language level we could have the mnemonics
|
For the opcodes that load or store data at the assembly language level we could have the mnemonics
|
||||||
"store" and "load" and have the assembler pick the opcode based on the inclusion of the word "byte"
|
"store" and "load" and have the assembler pick the opcode based on the inclusion of the word "byte"
|
||||||
or "word" for two bytes. That would make the assembly easier to read but put a bit more work on the
|
or "word" for two bytes. That would make the assembly easier to read but put a bit more work on the
|
||||||
assembler. The Stack Pointer will start 2 bytes above the video memory start.
|
assembler.
|
||||||
\section{COPY (Copy Word from Address)}
|
\section{STOB (Store Byte)}
|
||||||
\OpcodeTable{0x08}{0000 1000}{copya}{Register}{Address}\\[6pt]
|
\OpcodeTable{0x20}{stob}{Register}{Address}\\[6pt]
|
||||||
Copy a machine word from Operand 2 into Operand 1.
|
Stores a single byte (the lower nibble) from a register to a memory address.
|
||||||
\section{COPY BYTE (Copy Byte from Address)}
|
\section{STOW (Store Machine Word)}
|
||||||
\OpcodeTable{0x10}{0001 0000}{copyab}{Register}{Address}\\[6pt]
|
\OpcodeTable{0x20}{stow}{Register}{Address}\\[6pt]
|
||||||
Copy a byte (8 bits) from Operand 2 into Operand 1, clearing the setting the most significant bits to zero.
|
Stores a machine word from a register to a memory address.
|
||||||
\section{COPY (Copy Word Indirect Address)}
|
\section{LAA (Load Absolute Address)}
|
||||||
\OpcodeTable{0x18}{0001 1000}{copyra}{Register}{[Register]}\\[6pt]
|
\OpcodeTable{0x00}{laa}{Register}{Address}\\[6pt]
|
||||||
Copy a machine word from the address stored in Operand 2 into Operand 1.
|
Loads an address (2 bytes) into the register.
|
||||||
\section{COPY BYTE (Copy Byte Indirect Address)}
|
\section{LODB (Load Byte)}
|
||||||
\OpcodeTable{0x20}{0010 0000}{copyrab}{Register}{[Register]}\\[6pt]
|
\OpcodeTable{0x20}{lodb}{Register}{Register}\\[6pt]
|
||||||
Copy a byte (8 bits) from the address stored in Operand 2 into Operand 1.
|
Loads a single byte into a register from a memory address in the second operand register, zeroing out the high nibble.
|
||||||
\section{COPY (Copy)}
|
\section{LODW (Load Machine Word)}
|
||||||
\OpcodeTable{0x28}{0010 1000}{copyrara}{[Register]}{[Register]}\\[6pt]
|
\OpcodeTable{0x20}{lodw}{Register}{Register}\\[6pt]
|
||||||
Copy a machine word from the address stored in Operand 2 into the address stored in Operand 1.
|
Loads a word into a register from a memory address in the second operand register.
|
||||||
\section{COPY BYTE (Copy Byte)}
|
\section{LODWI (Load Immediate Word)}
|
||||||
\OpcodeTable{0x30}{0011 0000}{copyrarab}{[Register]}{[Register]}\\[6pt]
|
\OpcodeTable{0x00}{lodwi}{Register}{Constant}\\[6pt]
|
||||||
Copy a byte (8 bits) from the address stored in Operand 2 into the address stored in Operand 1.
|
Loads an immediate machine word into the register clearing the high nibble if the value is less then 256.
|
||||||
\section{COPY (Copy)}
|
|
||||||
\OpcodeTable{0x38}{0011 1000}{copy}{Register}{Register}\\[6pt]
|
|
||||||
Copy a machine word from Operand 2 into Operand 1.
|
|
||||||
\section{COPY (Copy Immediate)}
|
|
||||||
\OpcodeTable{0xC0}{1100 0000}{copyi}{Register}{Constant}\\[6pt]
|
|
||||||
Copy a machine word from Operand 2 into Operand 1.
|
|
||||||
\section{COPY BYTE (Copy Byte)}
|
|
||||||
\OpcodeTable{0x40}{0100 0000}{copyb}{Register}{Constant}\\[6pt]
|
|
||||||
Copy a byte (8 bits) from Operand 2 into Operand 1.
|
|
||||||
\section{CMP (Compare)}
|
\section{CMP (Compare)}
|
||||||
\OpcodeTable{0x48}{0100 1000}{cmp}{Register}{Register}\\[6pt]
|
\OpcodeTable{0x20}{cmp}{Register}{Register}\\[6pt]
|
||||||
Compares two registers and somewhere sets a result in the status register.
|
Compares two registers and somewhere sets a result in the status register.
|
||||||
\section{CMPI (Compare Immediate)}
|
\section{CMPI (Compare Immediate)}
|
||||||
\OpcodeTable{0x50}{0101 0000}{cmpi}{Register}{Constant}\\[6pt]
|
\OpcodeTable{0x00}{cmpi}{Register}{Constant}\\[6pt]
|
||||||
Compares an immediate 2 byte value to the contents of a register setting the status register accordingly.
|
Compares an immediate 2 byte value to the contents of a register setting the status register accordingly.
|
||||||
\section{ADD (Add)}
|
\section{ADD (Add)}
|
||||||
\OpcodeTable{0x58}{0101 1000}{add}{Register}{Register}\\[6pt]
|
\OpcodeTable{0x20}{add}{Register}{Register}\\[6pt]
|
||||||
Performs addition on a register with a value from another (or the same) register.
|
Performs addition on a register with a value from another (or the same) register.
|
||||||
\section{SUB (Subtract)}
|
\section{SUB (Subtract)}
|
||||||
\OpcodeTable{0x60}{0110 0000}{sub}{Register}{Register}\\[6pt]
|
\OpcodeTable{0x20}{sub}{Register}{Register}\\[6pt]
|
||||||
Performs subtraction on a register with a value from another (or the same) register.
|
Performs subtraction on a register with a value from another (or the same) register.
|
||||||
|
\section{JMP (Jump)}
|
||||||
|
\OpcodeTable{0x20}{jmp}{Address}{None}\\[6pt]
|
||||||
|
Jumps unconditionally to a memory address.
|
||||||
|
\section{JZ (Jump if Zero)}
|
||||||
|
\OpcodeTable{0x20}{jz}{Register}{None}\\[6pt]
|
||||||
|
Jumps to a memory address if the status flag is zero.
|
||||||
|
\section{JG (Jump if Greater Than)}
|
||||||
|
\OpcodeTable{0x70}{jg}{Address}{None}\\[6pt]
|
||||||
|
Jump to the Address if the status flag is greater than zero.
|
||||||
|
\section{JL (Jump if Less Than)}
|
||||||
|
\OpcodeTable{0x00}{jl}{Address}{None}\\[6pt]
|
||||||
|
Jumps to the address if the status flag is less than zero.
|
||||||
\section{AND (Logical AND)}
|
\section{AND (Logical AND)}
|
||||||
\OpcodeTable{0x68}{0110 1000}{and}{Register}{Register}\\[6pt]
|
\OpcodeTable{0x00}{and}{Register}{Register}\\[6pt]
|
||||||
Logical ANDs the two registers together storing the result in operand 1.
|
Logical ANDs the two registers together storing the result in operand 1.
|
||||||
\section{XOR (Logical Exclusive OR)}
|
\section{XOR (Logical Exclusive OR)}
|
||||||
\OpcodeTable{0x70}{0111 0000}{xor}{Register}{Register}\\[6pt]
|
\OpcodeTable{0x00}{xor}{Register}{Register}\\[6pt]
|
||||||
Logical XORs the two registers together storing the result in operand 1.
|
Logical XORs the two registers together storing the result in operand 1.
|
||||||
\section{OR (Logical OR)}
|
\section{OR (Logical OR)}
|
||||||
\OpcodeTable{0x78}{0111 1000}{or}{Register}{Register}\\[6pt]
|
\OpcodeTable{0x00}{or}{Register}{Register}\\[6pt]
|
||||||
Logical ORs the two registers together storing the result in operand 1.
|
Logical ORs the two registers together storing the result in operand 1.
|
||||||
\section{NOT (Logical Negation)}
|
\section{NOT (Logical Negation)}
|
||||||
\OpcodeTable{0x80}{1000 0000}{not}{Register}{None}\\[6pt]
|
\OpcodeTable{0x00}{not}{Register}{None}\\[6pt]
|
||||||
Inverts the bits of the target register.
|
Inverts the bits of the target register.
|
||||||
\section{SHR (Shift Right)}
|
\section{SHR (Shift Right)}
|
||||||
\OpcodeTable{0x88}{1000 1000}{shr}{Register}{Constant}\\[6pt]
|
\OpcodeTable{0x00}{shr}{Register}{Constant}\\[6pt]
|
||||||
Bit-wise shifts the contents of the register right Constant number of times.
|
Bit-wise shifts the contents of the register right Constant number of times.
|
||||||
\section{SHL (Shift Left)}
|
\section{SHL (Shift Left)}
|
||||||
\OpcodeTable{0x90}{1001 0000}{shl}{Register}{Constant}\\[6pt]
|
\OpcodeTable{0x00}{shl}{Register}{Constant}\\[6pt]
|
||||||
Bit-wise shifts the contents of the register left Constant number of times.
|
Bit-wise shifts the contents of the register left Constant number of times.
|
||||||
\section{INC (Increment)}
|
\section{INC (Increment)}
|
||||||
\OpcodeTable{0x98}{1001 1000}{inc}{Register}{None}\\[6pt]
|
\OpcodeTable{0x00}{inc}{Register}{None}\\[6pt]
|
||||||
Increments the contents of the register by one. Over-flows will not be reported.
|
Increments the contents of the register by one. Over-flows will not be reported.
|
||||||
\section{DEC (Decrement)}
|
\section{DEC (Decrement)}
|
||||||
\OpcodeTable{0xA0}{1010 0000}{dec}{Register}{None}\\[6pt]
|
\OpcodeTable{0x00}{dec}{Register}{None}\\[6pt]
|
||||||
Decrements the contents of the register by one. Under-flows will not be reported.
|
Decrements the contents of the register by one. Under-flows will not be reported.
|
||||||
\section{Push}
|
|
||||||
\OpcodeTable{0xA8}{1010 1000}{push}{Register}{None}
|
|
||||||
Pushes the value of Register onto the stack, decrementing the Stack Pointer by 2.
|
|
||||||
\section{Pop}
|
|
||||||
\OpcodeTable{0xB0}{1011 0000}{pop}{Register}{None}
|
|
||||||
Pops the top of the stack into Register, incrementing the Stack Pointer by 2.
|
|
||||||
\section{JMPI (Jump Indirect)}
|
|
||||||
\OpcodeTable{0xB8}{1011 1000}{jmpi}{Register}{None}\\[6pt]
|
|
||||||
Jumps unconditionally to a memory address stored in Operand 1. Sets the Program Counter to Operand 1.
|
|
||||||
\section{JMP (Jump)}
|
|
||||||
\OpcodeTable{0x02}{0000 0010}{jmp}{Address}{None}\\[6pt]
|
|
||||||
Jumps unconditionally to a memory address. Sets the Program Counter to Address.
|
|
||||||
\section{JZ (Jump if Zero)}
|
|
||||||
\OpcodeTable{0x03}{0000 0011}{jz}{Address}{None}\\[6pt]
|
|
||||||
Jumps to a memory address if the status flag is zero. Sets the Program Counter to Address.
|
|
||||||
\section{JG (Jump if Greater Than)}
|
|
||||||
\OpcodeTable{0x04}{0000 0100}{jg}{Address}{None}\\[6pt]
|
|
||||||
Jump to the Address if the status flag is greater than zero. Sets the Program Counter to Address.
|
|
||||||
\section{JL (Jump if Less Than)}
|
|
||||||
\OpcodeTable{0x05}{0000 0101}{jl}{Address}{None}\\[6pt]
|
|
||||||
Jumps to the address if the status flag is less than zero. Sets the Program Counter to Address.
|
|
||||||
\section{NOP (No Operation)}
|
\section{NOP (No Operation)}
|
||||||
\OpcodeTable{0x01}{0000 0001}{nop}{None}{None}\\[6pt]
|
\OpcodeTable{0x00}{nop}{None}{None}\\[6pt]
|
||||||
Skips a clock cycle, incrementing the program counter.
|
Skips a clock cycle, incrementing the program counter.
|
||||||
\section{CALL (Call Subroutine)}
|
|
||||||
\OpcodeTable{0x06}{0000 0110}{call}{Address}{None}\\[6pt]
|
|
||||||
Pushes the base address to the stack and sets the Program Counter to Address.
|
|
||||||
\section{RET (Return from Subroutine)}
|
|
||||||
\OpcodeTable{0x07}{0000 0111}{ret}{None}{None}\\[6pt]
|
|
||||||
Pops the stack and sets the Program Counter to that value.
|
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef LIST_H
|
||||||
|
#define LIST_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define LISTDEFAULTSIZE 4
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void** content;
|
||||||
|
int size;
|
||||||
|
int capacity;
|
||||||
|
} List;
|
||||||
|
|
||||||
|
List* CreateList(void);
|
||||||
|
int AddListItem(const void *, size_t, List *);
|
||||||
|
void DestroyList(List*);
|
||||||
|
|
||||||
|
#endif
|
||||||
+32
-8
@@ -2,23 +2,47 @@
|
|||||||
#define OPCODES_H
|
#define OPCODES_H
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include "symbols_table.h"
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
R1 = 0, R2, R3, R4, R5, R6, R7, R8 = 7
|
R1, R2, R3, R4, R5, R6, R7, R8
|
||||||
} Registers;
|
} Registers;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
COPYA = 0x08, COPYAB = 0x10, COPYRA = 0x18, COPYRAB = 0x20, COPYRARA = 0x28, COPYRARAB = 0x30, COPY = 0x38, COPYB = 0x40, COPYI = 0xC0,
|
ADD, SUB, JZ, INT, YLD, RET,
|
||||||
CMP = 0x48, CMPI = 0x50, ADD = 0x58, SUB = 0x60, AND = 0x68, XOR = 0x70, OR = 0x78, NOT = 0x80, SHR = 0x88, SHL = 0x90,
|
CMP, NOP, JMP, CALL, LOAD, JE, INC, DEC, LOADB
|
||||||
INC = 0x98, DEC = 0xA0, PUSH = 0xA8, POP = 0xB0,
|
|
||||||
JMPI = 0xB8, JMP = 0x02, JZ = 0x03, JG = 0x04, JL = 0x05, NOP = 0x01, CALL = 0x06, RET = 0x07
|
|
||||||
} Mnemonic;
|
} Mnemonic;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NoParameter,
|
||||||
|
ConstantParameter,
|
||||||
|
AddressParameter,
|
||||||
|
RegisterParameter
|
||||||
|
} OpcodeParameter;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
OpcodeParameter ParameterType;
|
||||||
|
OpcodeParameter InterpretedAs;
|
||||||
|
|
||||||
|
union {
|
||||||
|
int Number; //ConstanrParam
|
||||||
|
Registers Register; //Register param
|
||||||
|
Symbol* Symbol; //Address param
|
||||||
|
} Value;
|
||||||
|
} Parameter;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Mnemonic Mnemonic;
|
||||||
|
Parameter* ParameterOne;
|
||||||
|
Parameter* ParameterTwo;
|
||||||
|
} Instruction;
|
||||||
|
|
||||||
|
Instruction* CreateInstruction(Mnemonic mnemonic);
|
||||||
|
Parameter* CreateParameter(OpcodeParameter parameterType);
|
||||||
|
void FreeInstruction(Instruction* instruction);
|
||||||
int IsOpcode(const char*, Mnemonic*);
|
int IsOpcode(const char*, Mnemonic*);
|
||||||
int IsRegister(const char*, Registers*);
|
int IsRegister(const char*, Registers*);
|
||||||
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]);
|
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]);
|
||||||
void GetRegisterText(Registers reg, char buffer[3]);
|
unsigned char GetInstructionMask(Mnemonic type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+9
-1
@@ -6,10 +6,18 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include "list.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
#include "symbols_table.h"
|
#include "symbols_table.h"
|
||||||
|
|
||||||
void ParseTokens(TokenList* tokens, SymbolTable** symbolsTable);
|
//#define HIGHMEMORY 65535 //64KiB - 1 AKA 0xFFFF
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
List* Instructions;
|
||||||
|
SymbolTable* SymbolsTable;
|
||||||
|
} IRState;
|
||||||
|
|
||||||
|
IRState* ParseTokens(List*);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+2
-1
@@ -7,8 +7,9 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
|
#include "list.h"
|
||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
|
|
||||||
TokenList* GenerateTokenList(const char*);
|
List* GenerateTokenList(const char*);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -6,17 +6,30 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include "opcodes.h"
|
|
||||||
#include "token.h"
|
|
||||||
|
|
||||||
#define SYMBOLSTABLE_DEFAULT_CAPACITY 128
|
#define SYMBOLSTABLE_DEFAULT_CAPACITY 128
|
||||||
|
|
||||||
typedef struct _symbol {
|
typedef enum {
|
||||||
|
ValueAt,
|
||||||
|
Address
|
||||||
|
} SymbolType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* String;
|
||||||
|
uint8_t TerminatorByte;
|
||||||
|
int HasTerminatorByte;
|
||||||
|
} SymbolString;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
char* Name;
|
char* Name;
|
||||||
int Address;
|
|
||||||
int Length;
|
int Length;
|
||||||
Token* Token;
|
int Resolved;
|
||||||
|
|
||||||
|
union {
|
||||||
|
SymbolString String;
|
||||||
|
int Number;
|
||||||
|
//Instruction Instruction;
|
||||||
|
} Value;
|
||||||
} Symbol;
|
} Symbol;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -26,10 +39,10 @@ typedef struct {
|
|||||||
} SymbolTable;
|
} SymbolTable;
|
||||||
|
|
||||||
SymbolTable* CreateSymbolTable(void);
|
SymbolTable* CreateSymbolTable(void);
|
||||||
int TryGetSymbol(char* name, SymbolTable* table, Symbol** outSymbol);
|
Symbol* TryGetSymbol(char* name, SymbolTable* table);
|
||||||
Symbol* AddSymbolToTable(char* name, int address, SymbolTable* table);
|
Symbol* AddSymbolToTable(char* name, SymbolTable* table);
|
||||||
|
SymbolString* CreateSymbolString(char* text);
|
||||||
void FreeSymbolTable(SymbolTable* table);
|
void FreeSymbolTable(SymbolTable* table);
|
||||||
void FreeSymbol(Symbol* symbol);
|
void FreeSymbol(Symbol* symbol);
|
||||||
int SymbolResolved(Symbol* symbol);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+2
-14
@@ -23,7 +23,7 @@ typedef enum {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DB,
|
DB,
|
||||||
Include,
|
Origin,
|
||||||
Byte
|
Byte
|
||||||
} Directive;
|
} Directive;
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ typedef enum {
|
|||||||
AddressClass = LabelClass | IdentifierClass
|
AddressClass = LabelClass | IdentifierClass
|
||||||
} TokenClass;
|
} TokenClass;
|
||||||
|
|
||||||
typedef struct __token {
|
typedef struct {
|
||||||
char* Lemexe;
|
char* Lemexe;
|
||||||
TokenClass Class;
|
TokenClass Class;
|
||||||
int LineNumber;
|
int LineNumber;
|
||||||
@@ -52,21 +52,9 @@ typedef struct __token {
|
|||||||
Directive Directive;
|
Directive Directive;
|
||||||
int Number;
|
int Number;
|
||||||
} Value;
|
} Value;
|
||||||
|
|
||||||
struct __token* Prev;
|
|
||||||
struct __token* Next;
|
|
||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Token** content;
|
|
||||||
int size;
|
|
||||||
int capacity;
|
|
||||||
} TokenList;
|
|
||||||
|
|
||||||
Token* CreateToken(int lineNumber, TokenClass tokenClass);
|
Token* CreateToken(int lineNumber, TokenClass tokenClass);
|
||||||
TokenList* CreateTokenList(void);
|
|
||||||
int AddToken(Token* token, TokenList* list);
|
|
||||||
void RemoveToken(int index, TokenList* list);
|
|
||||||
void FreeToken(Token* token);
|
void FreeToken(Token* token);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
.db MAX_MEM 0xFFFF
|
|
||||||
.db VIDEO_MEM 0xF37F
|
|
||||||
.db MAX_LENGTH MAX_MEM; - MAX_LENGTH
|
|
||||||
.db MSG "Hello, World!", 0
|
|
||||||
|
|
||||||
__start:
|
|
||||||
copy r1, MSG ; Pointer into r1
|
|
||||||
copy r8, VIDEO_MEM
|
|
||||||
call strlen
|
|
||||||
copy r1, MSG
|
|
||||||
cmp r2, 0
|
|
||||||
jz _end
|
|
||||||
cmp r2, MAX_LENGTH
|
|
||||||
jg _end
|
|
||||||
draw_loop:
|
|
||||||
copy byte [r8], [r1]
|
|
||||||
inc r1
|
|
||||||
inc r8
|
|
||||||
dec r2
|
|
||||||
cmp r2, 0
|
|
||||||
jz _end
|
|
||||||
jmp draw_loop
|
|
||||||
_end:
|
|
||||||
jmp _end
|
|
||||||
|
|
||||||
.db NewMsg "My message", 0
|
|
||||||
|
|
||||||
; Returns the length of a NULL terminated string
|
|
||||||
; Arguments: R1 - Pointer to the string
|
|
||||||
; Returns: R2 - Contains the length of the string
|
|
||||||
strlen:
|
|
||||||
copy r2, 0 ; length
|
|
||||||
copy byte r3, [r1]
|
|
||||||
cmp r3, 0
|
|
||||||
jz end ;The string is zero length
|
|
||||||
loop:
|
|
||||||
inc r1
|
|
||||||
copy byte r3, [r1]
|
|
||||||
cmp r3, 0
|
|
||||||
jz end
|
|
||||||
inc r2
|
|
||||||
jmp loop
|
|
||||||
end:
|
|
||||||
ret
|
|
||||||
+25
-25
@@ -1,27 +1,27 @@
|
|||||||
;.include "./another_test.asm"
|
|
||||||
.db labelsz reference
|
|
||||||
.db video_start 0xF37F
|
.db video_start 0xF37F
|
||||||
.db msg "Hello, world!", 0
|
.db msg "Hello, world!", 0
|
||||||
.db NOTERM "No terminating byte here"
|
|
||||||
.db null_byte 0
|
load r1, msg ; Because the lod* instructions can't load an address
|
||||||
jmp [r4]
|
; from anything but a register, this becomes laa r1, msg
|
||||||
;load r2, label
|
load r8, [15]
|
||||||
something_insance:
|
;Routine: string_length
|
||||||
load r1, unknown_symbol
|
;In: String address in r1
|
||||||
load r1, 5
|
;Out: Length in R2
|
||||||
.db fun_alright 0x70;does this break?
|
|
||||||
load r3, r4
|
string_length:
|
||||||
store byte r3, r5
|
loadb r3, [r1] ; Load the byte from the address in R1, into R3
|
||||||
store r5, r7
|
load r2, 0 ; String length
|
||||||
unknown_symbol:;Does this work?
|
cmp r3, 0 ; Is R3 a null byte?
|
||||||
cmp r1, 5;or one after the register?
|
je end
|
||||||
cmp r1, r2;This might work
|
inc r2
|
||||||
and r1, r2
|
|
||||||
add r4, r7
|
start:
|
||||||
inc r1 ;increment r1
|
inc r1 ; next char
|
||||||
xor r1, r1 ;clear self
|
loadb r3, [r1] ; Load the next character byte into R3
|
||||||
pop r3
|
cmp r3, 0 ; Null byte?
|
||||||
jmp unknown_symbol
|
je end
|
||||||
jmp [r4]
|
inc r2 ; Nope, increment the length counter
|
||||||
jz [r6]
|
jmp start
|
||||||
;And a comment at the end
|
|
||||||
|
end:
|
||||||
|
ret
|
||||||
|
|||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
#include "../includes/list.h"
|
||||||
|
|
||||||
|
List* CreateList() {
|
||||||
|
List *new = malloc(sizeof(List));
|
||||||
|
|
||||||
|
if (!new) {
|
||||||
|
fprintf(stderr, "Failed to malloc() for new new List.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
new->content = malloc(sizeof(void*) * LISTDEFAULTSIZE);
|
||||||
|
|
||||||
|
if (!new->content) {
|
||||||
|
fprintf(stderr, "Failed to malloc() memory for List contents.\n");
|
||||||
|
free(new);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
new->size = 0;
|
||||||
|
new->capacity = LISTDEFAULTSIZE;
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AddListItem(const void *value, size_t size, List* list) {
|
||||||
|
if (!list) return -1;
|
||||||
|
if (!value) return -1;
|
||||||
|
if (size == 0) return -1;
|
||||||
|
|
||||||
|
if (list->capacity < list->size + 1) {
|
||||||
|
void* ptr = realloc(list->content, sizeof(void*) * list->capacity * 2);
|
||||||
|
//Note: realloc will free list->root if it succeeds.
|
||||||
|
if (!ptr) {
|
||||||
|
fprintf(stderr, "Failed to resize array with realloc() (%d bytes).\n", list->capacity * 2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->content = ptr;
|
||||||
|
list->capacity = list->capacity * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* item = calloc(1, size);
|
||||||
|
|
||||||
|
if (!item) {
|
||||||
|
fprintf(stderr, "Failed to calloc() new memory (%lu bytes).\n", size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(item, value, size);
|
||||||
|
|
||||||
|
list->content[list->size] = item;
|
||||||
|
list->size++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyList(List* list) {
|
||||||
|
if (!list) return;
|
||||||
|
|
||||||
|
for(int i = 0; i < list->size; i++) {
|
||||||
|
free(list->content[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(list->content);
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
+27
-178
@@ -3,18 +3,10 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sysexits.h>
|
#include <sysexits.h>
|
||||||
#include "../includes/token.h"
|
#include "../includes/list.h"
|
||||||
|
#include "../includes/parser.h"
|
||||||
#include "../includes/futil.h"
|
#include "../includes/futil.h"
|
||||||
#include "../includes/scanner.h"
|
#include "../includes/scanner.h"
|
||||||
#include "../includes/parser.h"
|
|
||||||
|
|
||||||
const char* MagicStartName = "__start";
|
|
||||||
TokenList* LIST;
|
|
||||||
SymbolTable* Symbols = NULL;
|
|
||||||
|
|
||||||
unsigned char mem[128] = {0};
|
|
||||||
void print(void);
|
|
||||||
void assemble(void);
|
|
||||||
|
|
||||||
int main(int argc, char* args[]) {
|
int main(int argc, char* args[]) {
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
@@ -22,36 +14,16 @@ int main(int argc, char* args[]) {
|
|||||||
return EX_USAGE;
|
return EX_USAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
atexit(print);
|
|
||||||
|
|
||||||
char* source_code;
|
char* source_code;
|
||||||
size_t bytes_read;
|
size_t bytes_read;
|
||||||
|
|
||||||
if (!ReadAllString(args[1], &source_code, &bytes_read)) return EX_IOERR;
|
if (!ReadAllString(args[1], &source_code, &bytes_read)) return EX_IOERR;
|
||||||
|
|
||||||
LIST = GenerateTokenList(source_code);
|
List* list = GenerateTokenList(source_code);
|
||||||
|
|
||||||
ParseTokens(LIST, &Symbols);
|
|
||||||
|
|
||||||
free(source_code);
|
|
||||||
|
|
||||||
assemble();
|
|
||||||
|
|
||||||
printf("\nBytes:\n");
|
|
||||||
for(unsigned long i = 0; i < sizeof(mem); i++) {
|
|
||||||
if (i != 0 && i % 8 == 0) printf("\n");
|
|
||||||
printf("%02X ", mem[i] & 0xFF);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void print(void) {
|
|
||||||
char mnemonic[12];
|
char mnemonic[12];
|
||||||
printf("printing tokens...\n");
|
|
||||||
|
|
||||||
|
for(int i = 0; i < list->size; i++) {
|
||||||
for(int i = 0; i < LIST->size; i++) {
|
Token* t = (Token*) list->content[i];
|
||||||
Token* t = (Token*) LIST->content[i];
|
|
||||||
|
|
||||||
if (t->EndOfFile) {
|
if (t->EndOfFile) {
|
||||||
printf("EOF\n");
|
printf("EOF\n");
|
||||||
@@ -60,14 +32,18 @@ void print(void) {
|
|||||||
|
|
||||||
if (t->Class == PunctuationClass){
|
if (t->Class == PunctuationClass){
|
||||||
if(t->Value.Punctuation == NewLine) {
|
if(t->Value.Punctuation == NewLine) {
|
||||||
printf("<%d>\n", t->LineNumber);
|
printf("\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("[P]%c", t->Value.Punctuation);
|
printf("<%d>", t->LineNumber);
|
||||||
|
|
||||||
|
printf("%c ", t->Value.Punctuation);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("<%d>", t->LineNumber);
|
||||||
|
|
||||||
if (t->Class == LabelClass) {
|
if (t->Class == LabelClass) {
|
||||||
printf("[L]%s* ", t->Lemexe);
|
printf("[L]%s* ", t->Lemexe);
|
||||||
continue;
|
continue;
|
||||||
@@ -100,149 +76,22 @@ void print(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (t->Class == CharacterClass) {
|
if (t->Class == CharacterClass) {
|
||||||
printf("[C]'%s'", t->Lemexe);
|
printf("%s ", t->Lemexe);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int CurrentIndex = 0;
|
|
||||||
int PC2 = 0;
|
|
||||||
|
|
||||||
void WriteByte(unsigned char byte) {
|
|
||||||
mem[PC2] = byte;
|
|
||||||
PC2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteWord(unsigned short word) {
|
|
||||||
mem[PC2] = (word >> 8) & 0xFF;
|
|
||||||
mem[PC2 + 1] = word & 0xFF;
|
|
||||||
PC2 += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned short GetValueFromToken(Token* token) {
|
|
||||||
if (token->Class & IdentifierClass) {
|
|
||||||
Symbol* symbol;
|
|
||||||
|
|
||||||
if (TryGetSymbol(token->Lemexe, Symbols, &symbol)) {
|
|
||||||
return symbol->Address;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "Failed to find symbol %s while assembling.\n", token->Lemexe);
|
|
||||||
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (token->Class == NumberClass) return token->Value.Number;
|
|
||||||
|
|
||||||
fprintf(stderr, "Failed to find token '%d' while assmbling.\n", token->Class);
|
|
||||||
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int IsAtEnd(void){
|
|
||||||
return CurrentIndex >= LIST->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void assemble() {
|
|
||||||
while(!IsAtEnd()) {
|
|
||||||
Token* current = LIST->content[CurrentIndex];
|
|
||||||
switch(current->Value.Mnemonic) {
|
|
||||||
case COPYA:
|
|
||||||
case COPYAB:
|
|
||||||
CurrentIndex++;
|
|
||||||
|
|
||||||
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
|
||||||
CurrentIndex++;
|
|
||||||
WriteWord(GetValueFromToken(LIST->content[CurrentIndex]));
|
|
||||||
break;
|
|
||||||
case COPYRA:
|
|
||||||
case COPYRAB:
|
|
||||||
case COPYRARA:
|
|
||||||
case COPYRARAB:
|
|
||||||
case COPY:
|
|
||||||
CurrentIndex++;
|
|
||||||
|
|
||||||
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
|
||||||
CurrentIndex++;
|
|
||||||
WriteByte(((Token*) LIST->content[CurrentIndex])->Value.Register);
|
|
||||||
break;
|
|
||||||
case COPYI: //TODO: should explicitly get number from value I feel
|
|
||||||
CurrentIndex++;
|
|
||||||
|
|
||||||
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
|
||||||
CurrentIndex++;
|
|
||||||
WriteWord(GetValueFromToken(LIST->content[CurrentIndex]));
|
|
||||||
break;
|
|
||||||
case COPYB:
|
|
||||||
CurrentIndex++;
|
|
||||||
|
|
||||||
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
|
||||||
CurrentIndex++;
|
|
||||||
WriteByte((unsigned char)GetValueFromToken(LIST->content[CurrentIndex]));
|
|
||||||
break;
|
|
||||||
case CMP:
|
|
||||||
CurrentIndex++;
|
|
||||||
|
|
||||||
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
|
||||||
CurrentIndex++;
|
|
||||||
WriteByte(((Token*) LIST->content[CurrentIndex])->Value.Register);
|
|
||||||
break;
|
|
||||||
case CMPI:
|
|
||||||
CurrentIndex++;
|
|
||||||
|
|
||||||
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
|
||||||
CurrentIndex++;
|
|
||||||
WriteWord(GetValueFromToken(LIST->content[CurrentIndex]));
|
|
||||||
break;
|
|
||||||
case ADD:
|
|
||||||
case SUB:
|
|
||||||
case AND:
|
|
||||||
case OR:
|
|
||||||
case XOR:
|
|
||||||
CurrentIndex++;
|
|
||||||
|
|
||||||
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
|
||||||
CurrentIndex++;
|
|
||||||
WriteByte(((Token*) LIST->content[CurrentIndex])->Value.Register);
|
|
||||||
break;
|
|
||||||
case SHL:
|
|
||||||
case SHR:
|
|
||||||
CurrentIndex++;
|
|
||||||
|
|
||||||
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
|
||||||
CurrentIndex++;
|
|
||||||
WriteWord(GetValueFromToken(LIST->content[CurrentIndex]));
|
|
||||||
break;
|
|
||||||
case INC:
|
|
||||||
case DEC:
|
|
||||||
case PUSH:
|
|
||||||
case POP:
|
|
||||||
case JMPI:
|
|
||||||
CurrentIndex++;
|
|
||||||
|
|
||||||
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
|
||||||
break;
|
|
||||||
case JMP:
|
|
||||||
case JZ:
|
|
||||||
case JG:
|
|
||||||
case JL:
|
|
||||||
WriteByte(current->Value.Mnemonic);
|
|
||||||
CurrentIndex++;
|
|
||||||
WriteWord(GetValueFromToken(LIST->content[CurrentIndex]));
|
|
||||||
break;
|
|
||||||
case NOP:
|
|
||||||
case RET:
|
|
||||||
WriteByte(current->Value.Mnemonic);
|
|
||||||
break;
|
|
||||||
case CALL:
|
|
||||||
WriteByte(current->Value.Mnemonic);
|
|
||||||
CurrentIndex++;
|
|
||||||
WriteWord(GetValueFromToken(LIST->content[CurrentIndex]));
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentIndex++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IRState* image = ParseTokens(list);
|
||||||
|
//free(image);
|
||||||
|
//Disassemble(image);
|
||||||
|
//for(int i = 0; i < image->Opcodes->size; i++) {
|
||||||
|
// printf("%d\n", ((IROpcode*) image->Opcodes->content[i])->Mnemonic);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//FILE* program = fopen("program.bin", "w+b");
|
||||||
|
|
||||||
|
//fwrite(image, 1, image[2] + image[3], program);
|
||||||
|
|
||||||
|
//fclose(program);
|
||||||
|
|
||||||
|
free(source_code);
|
||||||
|
}
|
||||||
+153
-47
@@ -1,50 +1,99 @@
|
|||||||
#include "../includes/opcodes.h"
|
#include "../includes/opcodes.h"
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define OPCODECOUNT 34
|
#define OPCODECOUNT 15
|
||||||
|
|
||||||
struct _instruction {
|
struct _instruction {
|
||||||
char* Name;
|
char* Name;
|
||||||
Mnemonic Mnemonic;
|
Mnemonic Mnemonic;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _instruction instructions[31] = {
|
struct _instruction instructions[OPCODECOUNT] = {
|
||||||
{ "copya", COPYA },
|
{ "add", ADD },//, Reg, Reg | Constant },
|
||||||
{ "copyab", COPYAB },
|
{ "sub", SUB },//, Reg, Reg | Constant },
|
||||||
{ "copyra", COPYRA },
|
{ "jz", JZ },//, Address, None },
|
||||||
{ "copyrab", COPYRAB },
|
{ "int", INT },//, Constant, None },
|
||||||
{ "copyrara", COPYRARA },
|
{ "yld", YLD },//, None, None },
|
||||||
{ "copyrarab", COPYRARAB },
|
{ "ret", RET },//, None, None },
|
||||||
{ "copy", COPY },
|
{ "cmp", CMP },//, Reg, Reg | Constant },
|
||||||
{ "copyi", COPYI },
|
{ "inc", INC },//, Constant | Reg, None},
|
||||||
{ "copyb", COPYB },
|
{ "dec", DEC },//, None, None},
|
||||||
{ "cmp", CMP },
|
{ "nop", NOP },//, None, None},
|
||||||
{ "cmpi", CMPI },
|
{ "jmp", JMP },//, Address, None},
|
||||||
{ "add", ADD },
|
{ "call", CALL },//, Address, None}
|
||||||
{ "sub", SUB },
|
{ "load", LOAD },
|
||||||
{ "and", AND },
|
{ "je", JE },
|
||||||
{ "xor", XOR },
|
{ "loadb", LOADB}
|
||||||
{ "or", OR },
|
|
||||||
{ "not", NOT },
|
|
||||||
{ "shr", SHR },
|
|
||||||
{ "shl", SHL },
|
|
||||||
{ "inc", INC },
|
|
||||||
{ "dec", DEC },
|
|
||||||
{ "push", PUSH },
|
|
||||||
{ "pop", POP },
|
|
||||||
{ "jmpi", JMPI },
|
|
||||||
{ "jmp", JMP },
|
|
||||||
{ "jz", JZ },
|
|
||||||
{ "jg", JG },
|
|
||||||
{ "jl", JL },
|
|
||||||
{ "nop", NOP },
|
|
||||||
{ "call", CALL },
|
|
||||||
{ "ret", RET }
|
|
||||||
//yld
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Instruction* CreateInstruction(Mnemonic mnemonic) {
|
||||||
|
Instruction* instruction = calloc(1, sizeof(Instruction));
|
||||||
|
|
||||||
|
if (!instruction) {
|
||||||
|
fprintf(stderr, "Failed to calloc room for an Instruction. %s.\n", strerror(errno));
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction->Mnemonic = mnemonic;
|
||||||
|
// instruction->ParameterOne = CreateParameter(NoParameter);
|
||||||
|
// instruction->ParameterTwo = CreateParameter(NoParameter);
|
||||||
|
|
||||||
|
return instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter* CreateParameter(OpcodeParameter parameterType) {
|
||||||
|
Parameter* param = calloc(1, sizeof(Parameter));
|
||||||
|
|
||||||
|
if (!param) {
|
||||||
|
fprintf(stderr, "Failed to calloc room for a Parameter. %s,\n", strerror(errno));
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
param->ParameterType = parameterType;
|
||||||
|
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeInstruction(Instruction* instruction) {
|
||||||
|
if (!instruction) return;
|
||||||
|
|
||||||
|
free(instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char GetInstructionMask(Mnemonic type) {
|
||||||
|
switch (type) {
|
||||||
|
case LOAD:
|
||||||
|
return 0x20; //0b00100000; ORing 0x80 marks the first parameter as an address
|
||||||
|
case ADD:
|
||||||
|
return 0x40;//0b01000000;
|
||||||
|
case SUB:
|
||||||
|
return 0x60;//0b01100000;
|
||||||
|
case CMP:
|
||||||
|
return 0x80;//0b10000000;
|
||||||
|
case JZ:
|
||||||
|
return 0x01;//0b00000001;
|
||||||
|
case INT:
|
||||||
|
return 0x02; //0b00000010;
|
||||||
|
case YLD:
|
||||||
|
return 0x03;
|
||||||
|
case RET:
|
||||||
|
return 0x04;
|
||||||
|
case CALL:
|
||||||
|
return 0x05;
|
||||||
|
case JMP:
|
||||||
|
return 0x06;//0b00000110;
|
||||||
|
case INC:
|
||||||
|
return 0x07;//0b00000111;
|
||||||
|
case DEC:
|
||||||
|
return 0x08;//0b00001000;
|
||||||
|
default:
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]) {
|
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]) {
|
||||||
memset(buffer, '\0', 12);
|
memset(buffer, '\0', 12);
|
||||||
|
|
||||||
@@ -56,19 +105,62 @@ void GetMnemonicText(Mnemonic mnemonic, char buffer[12]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetRegisterText(Registers reg, char buffer[3]) {
|
/*
|
||||||
memset(buffer, '\0', 3);
|
NOP - 0000 0000 NOP
|
||||||
|
JZ - 0000 0001 JZ Address
|
||||||
|
INT - 0000 0010 INT Constant
|
||||||
|
YLD - 0000 0011 YLD
|
||||||
|
RET - 0000 0100 RET
|
||||||
|
CALL - 0000 0101 CALL Address
|
||||||
|
JMP - 0000 0110 JMP Address
|
||||||
|
IN - 0000 0111 IN Constant
|
||||||
|
OUT - 0000 1000 OUT Constant
|
||||||
|
COPY - 0010 0XXX COPY REG, REG
|
||||||
|
- 0010 1XXX COPY REG, Constant
|
||||||
|
- 0011 0XXX COPY REG, Address
|
||||||
|
- 1010 0XXX COPY Address, REG
|
||||||
|
- 1010 1XXX COPY Address, Constant
|
||||||
|
- 1011 0XXX COPY Address, Address
|
||||||
|
ADD - 0100 0XXX ADD REG, REG
|
||||||
|
- 0100 1XXX ADD REG, Constant
|
||||||
|
SUB - 0110 0XXX SUB REG, REG
|
||||||
|
- 0110 1XXX SUB REG, Constant
|
||||||
|
CMP - 1000 0XXX CMP REG, REG
|
||||||
|
- 1000 1XXX CMP REG, Constant
|
||||||
|
- 1001 0XXX CMP REG, Address
|
||||||
|
*/
|
||||||
|
//COPY X01X XXXX
|
||||||
|
//ADD 010X XXXX
|
||||||
|
//SUB 011X XXXX
|
||||||
|
//CMP 100X XXXX
|
||||||
|
//REG XXX0 0XXX
|
||||||
|
//Constant XXX0 1XXX
|
||||||
|
//Address XXX1 0XXX
|
||||||
|
//R1 XXXX X000 -> XXXX X111 (R1 to R8)
|
||||||
|
|
||||||
if (reg < R1 || reg > R8) return;
|
// Register registers[REGISTERCOUNT] = {
|
||||||
|
// { "r1", R1 },
|
||||||
|
// { "r2", R2 },
|
||||||
|
// { "r3", R3 },
|
||||||
|
// { "r4", R4 },
|
||||||
|
// { "r5", R5 },
|
||||||
|
// { "r6", R6 },
|
||||||
|
// { "r7", R7 },
|
||||||
|
// { "r8", R8 }
|
||||||
|
// };
|
||||||
|
|
||||||
buffer[0] = 'r';
|
// const Instruction* GetOpcodeDetails(Mnemonic type) {
|
||||||
buffer[1] = reg + 49;
|
// for(int i = 0; i < OPCODECOUNT; i++) {
|
||||||
}
|
// if (instructions[i].op == type) return &instructions[i];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return NULL;
|
||||||
|
// }
|
||||||
|
|
||||||
int IsOpcode(const char* text, Mnemonic* opcode) {
|
int IsOpcode(const char* text, Mnemonic* opcode) {
|
||||||
if (!text) return 0;
|
if (!text) return 0;
|
||||||
|
|
||||||
for(unsigned long i = 0; i < sizeof(instructions) / sizeof(struct _instruction); i++) {
|
for(int i = 0; i < OPCODECOUNT; i++) {
|
||||||
if (strcmp(instructions[i].Name, text) == 0) {
|
if (strcmp(instructions[i].Name, text) == 0) {
|
||||||
if (opcode) *opcode = instructions[i].Mnemonic;
|
if (opcode) *opcode = instructions[i].Mnemonic;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -87,11 +179,25 @@ int IsRegister(const char* text, Registers* reg) {
|
|||||||
if (length != 2) return 0;
|
if (length != 2) return 0;
|
||||||
if (text[0] != 'r') return 0;
|
if (text[0] != 'r') return 0;
|
||||||
|
|
||||||
if (!isdigit(text[1])) return 0;
|
switch(text[1]) {
|
||||||
|
case '1':
|
||||||
r = text[1] - 0x31;
|
r--;
|
||||||
|
case '2':
|
||||||
|
r--;
|
||||||
|
case '3':
|
||||||
|
r--;
|
||||||
|
case '4':
|
||||||
|
r--;
|
||||||
|
case '5':
|
||||||
|
r--;
|
||||||
|
case '6':
|
||||||
|
r--;
|
||||||
|
case '7':
|
||||||
|
r--;
|
||||||
|
case '8':
|
||||||
if (reg) *reg = r;
|
if (reg) *reg = r;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+194
-454
@@ -1,525 +1,269 @@
|
|||||||
#include "../includes/parser.h"
|
#include "../includes/parser.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
typedef enum {
|
const List* TokensList;
|
||||||
NoOptions = 0, ForwardParser = 1, RemoveExpected = 2
|
|
||||||
} ExpectOptions;
|
|
||||||
|
|
||||||
TokenList* TokensList;
|
|
||||||
int CurrentToken = 0;
|
int CurrentToken = 0;
|
||||||
|
|
||||||
void PrintSymbols(void);
|
void PrintSymbols(void);
|
||||||
void RemoveCurrentToken(void);
|
SymbolString* ParseIdentifierParameter(void);
|
||||||
|
Instruction* HandleOperation(void);
|
||||||
void HandleAssemblerDirective(void);
|
void HandleAssemblerDirective(void);
|
||||||
Token* ExpectMnemonic(void);
|
|
||||||
void AdvanceParser(void);
|
void AdvanceParser(void);
|
||||||
void IgnoreParserLine(void);
|
void IgnoreParserLine(void);
|
||||||
Token* PeekToken(void);
|
Token* PeekToken(void);
|
||||||
int ParserAtEnd(void);
|
int ParserAtEnd(void);
|
||||||
|
IRState MachineState;
|
||||||
|
|
||||||
void ExpectPuncuation(TokenPunctuation punctuation, ExpectOptions options);
|
IRState* ParseTokens(List* tokens) {
|
||||||
void ExpectRegister(void);
|
if (!tokens) return NULL;
|
||||||
Symbol* ExpectIdentifier(ExpectOptions options, int expectUnresolved);
|
|
||||||
void ExpectCharacterClass(Symbol* symbol);
|
|
||||||
void ExpectLineEndOrFileEnd(ExpectOptions options);
|
|
||||||
|
|
||||||
SymbolTable* SymbolsTable;
|
|
||||||
|
|
||||||
//int HeapSize = 0;
|
|
||||||
int PC = 0;
|
|
||||||
|
|
||||||
void ParseTokens(TokenList* tokens, SymbolTable** symbols) {
|
|
||||||
if (!tokens) return;
|
|
||||||
if (!symbols) return;
|
|
||||||
|
|
||||||
TokensList = tokens;
|
TokensList = tokens;
|
||||||
|
|
||||||
if (!*symbols) *symbols = CreateSymbolTable();
|
MachineState.SymbolsTable = CreateSymbolTable();
|
||||||
|
MachineState.Instructions = CreateList();
|
||||||
SymbolsTable = *symbols;
|
|
||||||
|
|
||||||
while(!ParserAtEnd()) {
|
while(!ParserAtEnd()) {
|
||||||
Token* t = PeekToken();
|
Token* t = PeekToken();
|
||||||
if (!t || t->EndOfFile) break;
|
|
||||||
|
|
||||||
switch(t->Class) {
|
switch(t->Class) {
|
||||||
case DirectiveClass:
|
case DirectiveClass: //Maybe these should be ignored, let another process handle that.
|
||||||
HandleAssemblerDirective();
|
IgnoreParserLine();
|
||||||
break;
|
break;
|
||||||
case MnemonicClass:
|
case MnemonicClass:
|
||||||
ExpectMnemonic();
|
HandleOperation();
|
||||||
break;
|
break;
|
||||||
case LabelClass:
|
case LabelClass:
|
||||||
{
|
{
|
||||||
Symbol* symbol;
|
Symbol* symbol = TryGetSymbol(t->Lemexe, MachineState.SymbolsTable);
|
||||||
int found = TryGetSymbol(t->Lemexe, SymbolsTable, &symbol);
|
|
||||||
|
|
||||||
if (found && SymbolResolved(symbol)) {
|
if (symbol && symbol->Resolved) {
|
||||||
fprintf(stderr, "[Error] Line %d: Redefinition of symbol '%s'\n", t->LineNumber, t->Lemexe);
|
fprintf(stderr, "[Error] Line %d: Redefinition of symbol '%s'\n", t->LineNumber, t->Lemexe);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) symbol = AddSymbolToTable(t->Lemexe, PC, SymbolsTable);
|
AdvanceParser(); //Consume the label token
|
||||||
// else
|
|
||||||
// {
|
|
||||||
symbol->Address = PC;
|
|
||||||
//symbol->Type = RefPointer;
|
|
||||||
//symbol->Token = t;
|
|
||||||
//}
|
|
||||||
|
|
||||||
RemoveCurrentToken(); //label
|
if (!symbol) AddSymbolToTable(t->Lemexe, MachineState.SymbolsTable)->Resolved = 1;
|
||||||
|
else symbol->Resolved = 1;
|
||||||
|
|
||||||
ExpectLineEndOrFileEnd(RemoveExpected);
|
AdvanceParser(); //Consume the NewLine
|
||||||
|
|
||||||
//symbol->Value.Mnemonic = ExpectMnemonic();
|
// Instruction* ins = HandleOperation();
|
||||||
symbol->Token = ExpectMnemonic();
|
|
||||||
|
// if (!ins) continue;
|
||||||
|
|
||||||
|
// symbol->Value.Instruction = ins;
|
||||||
|
// symbol->InstructionPointer = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "[Warning] Line %d: Syntax error, expected start of expression, got '%c' [%d].\n", t->LineNumber, t->Value.Punctuation, t->Class);
|
fprintf(stderr, "[Warning] Line %d: Syntax error, expected start of expression, got '%c' [%d].\n", t->LineNumber, t->Value.Punctuation, t->Class);
|
||||||
exit(1);
|
//exit(1);
|
||||||
//IgnoreParserLine();
|
IgnoreParserLine();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintSymbols();
|
if (MachineState.SymbolsTable->Size > 0) PrintSymbols();
|
||||||
|
|
||||||
|
for(int i = 0; i < MachineState.Instructions->size; i++) {
|
||||||
|
char mn[12];
|
||||||
|
|
||||||
|
Instruction* ins = MachineState.Instructions->content[i];
|
||||||
|
|
||||||
|
GetMnemonicText(ins->Mnemonic, mn);
|
||||||
|
|
||||||
|
printf("%s\n", mn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleAssemblerDirective() {
|
return &MachineState;
|
||||||
Token* directive = PeekToken();
|
|
||||||
|
|
||||||
switch(directive->Value.Directive){
|
|
||||||
case DB:
|
|
||||||
{
|
|
||||||
RemoveCurrentToken();
|
|
||||||
|
|
||||||
Symbol* symbol = ExpectIdentifier(RemoveExpected, 1);
|
|
||||||
|
|
||||||
if (PeekToken()->Class == CharacterClass) {
|
|
||||||
ExpectCharacterClass(symbol);
|
|
||||||
|
|
||||||
//symbol->Type = RefLiteral;
|
|
||||||
}
|
|
||||||
else if (PeekToken()->Class == NumberClass) {
|
|
||||||
symbol->Length = 2;
|
|
||||||
|
|
||||||
RemoveCurrentToken(); //Clear the number token.
|
|
||||||
|
|
||||||
ExpectLineEndOrFileEnd(RemoveExpected);
|
|
||||||
|
|
||||||
//symbol->Type = RefLiteral;
|
|
||||||
}
|
|
||||||
else if (PeekToken()->Class == IdentifierClass) {
|
|
||||||
//symbol->Type = RefExpression;
|
|
||||||
|
|
||||||
symbol = ExpectIdentifier(RemoveExpected, 0);
|
|
||||||
symbol->Length = 2;
|
|
||||||
|
|
||||||
//TODO: This needs to be expanded to handle expressions, a symbol to symbol reg is not allowed.
|
|
||||||
|
|
||||||
ExpectLineEndOrFileEnd(RemoveExpected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//HeapSize += symbol->Length;
|
SymbolString* ParseIdentifierParameter(void) {
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Synatx error on line %d, %s.\n", directive->LineNumber, directive->Lemexe);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Token* ExpectMnemonic(void) {
|
|
||||||
Token* opcode = PeekToken();
|
|
||||||
|
|
||||||
if (opcode->Class != MnemonicClass) {
|
|
||||||
fprintf(stderr, "Syntax error on line %d: expected mnemonic.\n", opcode->LineNumber);
|
|
||||||
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
PC++;
|
|
||||||
|
|
||||||
if (arg->Class == RegisterClass) {
|
|
||||||
ExpectRegister();
|
|
||||||
|
|
||||||
ExpectPuncuation(Comma, RemoveExpected);
|
|
||||||
|
|
||||||
arg = PeekToken();
|
|
||||||
|
|
||||||
if (arg->Class == NumberClass) {
|
|
||||||
opcode->Value.Mnemonic = isByte ? COPYB : COPYI;
|
|
||||||
opcode->Lemexe = isByte ? "copyb" : "copyi";
|
|
||||||
|
|
||||||
isByte ? PC++ : (PC += 2);
|
|
||||||
|
|
||||||
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";
|
|
||||||
|
|
||||||
PC++;
|
|
||||||
}
|
|
||||||
else if (arg->Class & IdentifierClass) {
|
|
||||||
opcode->Value.Mnemonic = isByte ? COPYAB : COPYA;
|
|
||||||
opcode->Lemexe = isByte ? "copyab" : "copya";
|
|
||||||
PC += 2;
|
|
||||||
|
|
||||||
ExpectIdentifier(ForwardParser, 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ExpectPuncuation(LBracket, RemoveExpected);
|
|
||||||
|
|
||||||
ExpectRegister();
|
|
||||||
|
|
||||||
ExpectPuncuation(RBracket, RemoveExpected);
|
|
||||||
|
|
||||||
opcode->Value.Mnemonic = isByte ? COPYRAB : COPYRA;
|
|
||||||
opcode->Lemexe = isByte ? "copyrab" : "copyra";
|
|
||||||
PC++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ExpectPuncuation(LBracket, RemoveExpected);
|
|
||||||
|
|
||||||
ExpectRegister();
|
|
||||||
|
|
||||||
ExpectPuncuation(RBracket, RemoveExpected);
|
|
||||||
|
|
||||||
ExpectPuncuation(Comma, RemoveExpected);
|
|
||||||
|
|
||||||
ExpectPuncuation(LBracket, RemoveExpected);
|
|
||||||
|
|
||||||
ExpectRegister();
|
|
||||||
|
|
||||||
ExpectPuncuation(RBracket, RemoveExpected);
|
|
||||||
|
|
||||||
opcode->Value.Mnemonic = isByte ? COPYRARAB : COPYRARA;
|
|
||||||
opcode->Lemexe = isByte ? "copyrarab" : "copyrara";
|
|
||||||
|
|
||||||
PC++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CMP:
|
|
||||||
{
|
|
||||||
ExpectRegister();
|
|
||||||
|
|
||||||
ExpectPuncuation(Comma, RemoveExpected);
|
|
||||||
|
|
||||||
TokenClass class = PeekToken()->Class;
|
|
||||||
|
|
||||||
PC++;
|
|
||||||
|
|
||||||
if (class == NumberClass) {
|
|
||||||
opcode->Value.Mnemonic = CMPI;
|
|
||||||
opcode->Lemexe = "CMPI";
|
|
||||||
|
|
||||||
AdvanceParser();
|
|
||||||
|
|
||||||
PC += 2;
|
|
||||||
}
|
|
||||||
else if (class & IdentifierClass) {
|
|
||||||
opcode->Value.Mnemonic = CMPI;
|
|
||||||
opcode->Lemexe = "CMPI";
|
|
||||||
|
|
||||||
ExpectIdentifier(ForwardParser, 0);
|
|
||||||
|
|
||||||
PC += 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ExpectRegister();
|
|
||||||
|
|
||||||
PC++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ADD:
|
|
||||||
case SUB:
|
|
||||||
case AND:
|
|
||||||
case OR:
|
|
||||||
case XOR:
|
|
||||||
PC++;
|
|
||||||
|
|
||||||
ExpectRegister();
|
|
||||||
|
|
||||||
ExpectPuncuation(Comma, RemoveExpected);
|
|
||||||
|
|
||||||
ExpectRegister();
|
|
||||||
|
|
||||||
PC++;
|
|
||||||
break;
|
|
||||||
case SHL:
|
|
||||||
case SHR:
|
|
||||||
PC++;
|
|
||||||
ExpectRegister();
|
|
||||||
|
|
||||||
ExpectPuncuation(Comma, RemoveExpected);
|
|
||||||
|
|
||||||
if (PeekToken()->Class != NumberClass) {
|
|
||||||
fprintf(stderr, "[Line %d] Syntax error, expected numeric literal.\n", PeekToken()->LineNumber);
|
|
||||||
|
|
||||||
exit(12);
|
|
||||||
}
|
|
||||||
|
|
||||||
AdvanceParser();
|
|
||||||
|
|
||||||
PC += 2;
|
|
||||||
break;
|
|
||||||
case INC:
|
|
||||||
case DEC:
|
|
||||||
case PUSH:
|
|
||||||
case POP:
|
|
||||||
PC++;
|
|
||||||
ExpectRegister();
|
|
||||||
break;
|
|
||||||
case JMP:
|
|
||||||
{
|
|
||||||
PC++;
|
|
||||||
|
|
||||||
Token* arg = PeekToken();
|
|
||||||
|
|
||||||
if (arg->Class & IdentifierClass) {
|
|
||||||
ExpectIdentifier(ForwardParser, 0);
|
|
||||||
|
|
||||||
opcode->Value.Mnemonic = JMP;
|
|
||||||
opcode->Lemexe = "jmp";
|
|
||||||
|
|
||||||
PC += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ExpectPuncuation(LBracket, RemoveExpected);
|
|
||||||
|
|
||||||
ExpectRegister();
|
|
||||||
|
|
||||||
ExpectPuncuation(RBracket, RemoveExpected);
|
|
||||||
|
|
||||||
opcode->Value.Mnemonic = JMPI;
|
|
||||||
opcode->Lemexe = "jmpi";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JZ:
|
|
||||||
{
|
|
||||||
PC++;
|
|
||||||
|
|
||||||
ExpectIdentifier(ForwardParser, 0);
|
|
||||||
|
|
||||||
PC += 2;
|
|
||||||
|
|
||||||
opcode->Value.Mnemonic = JZ;
|
|
||||||
opcode->Lemexe = "jz";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JG:
|
|
||||||
{
|
|
||||||
PC++;
|
|
||||||
|
|
||||||
ExpectIdentifier(ForwardParser, 0);
|
|
||||||
|
|
||||||
PC += 2;
|
|
||||||
|
|
||||||
opcode->Value.Mnemonic = JG;
|
|
||||||
opcode->Lemexe = "jg";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JL:
|
|
||||||
{
|
|
||||||
PC++;
|
|
||||||
|
|
||||||
ExpectIdentifier(ForwardParser, 0);
|
|
||||||
|
|
||||||
PC += 2;
|
|
||||||
|
|
||||||
opcode->Value.Mnemonic = JL;
|
|
||||||
opcode->Lemexe = "jl";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CALL:
|
|
||||||
{
|
|
||||||
PC++;
|
|
||||||
|
|
||||||
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(ForwardParser, 0);
|
|
||||||
|
|
||||||
PC += 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpectLineEndOrFileEnd(ForwardParser);
|
|
||||||
|
|
||||||
return opcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
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(ExpectOptions options, int expectUnresolved) {
|
|
||||||
Token* token = PeekToken();
|
Token* token = PeekToken();
|
||||||
|
|
||||||
if (token->Class != IdentifierClass) {
|
if (token->Class != IdentifierClass) {
|
||||||
fprintf(stderr, "[Line %d] Expected Identifier.\n", token->LineNumber);
|
fprintf(stderr, "[Error] Line %d: Expected identifier\n", token->LineNumber);
|
||||||
exit(3);
|
IgnoreParserLine();
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol* symbol;
|
SymbolString* string = CreateSymbolString(token->Lemexe);
|
||||||
|
|
||||||
int found = TryGetSymbol(token->Lemexe, SymbolsTable, &symbol);
|
AdvanceParser();
|
||||||
|
|
||||||
if (found && SymbolResolved(symbol) && expectUnresolved) {
|
|
||||||
fprintf(stderr, "[Line %d] Redefinition of symbol '%s'.\n", token->LineNumber, token->Lemexe);
|
|
||||||
exit(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
//symbol->Resolved = resolved || symbol->Resolved(symbol);
|
|
||||||
symbol = AddSymbolToTable(token->Lemexe, PC, SymbolsTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expectUnresolved) symbol->Token = token;
|
|
||||||
|
|
||||||
// else {
|
|
||||||
// symbol = AddSymbolToTable(token->Lemexe, PC, 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) {
|
if (token->Class == PunctuationClass && token->Value.Punctuation == NewLine) {
|
||||||
RemoveCurrentToken();
|
return string;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else if (token->Class == PunctuationClass && token->Value.Punctuation == Comma) {
|
||||||
ExpectPuncuation(Comma, RemoveExpected);
|
AdvanceParser(); // Comsume the comma
|
||||||
|
|
||||||
token = PeekToken();
|
token = PeekToken();
|
||||||
|
|
||||||
if (token->Class != NumberClass) {
|
if (token->Class != NumberClass) {
|
||||||
fprintf(stderr, "[Line %d] Syntax error, expected terminating byte.\n", token->LineNumber);
|
fprintf(stderr, "[Error] Line %d: Expected string termination number.\n", token->LineNumber);
|
||||||
exit(7);
|
IgnoreParserLine();
|
||||||
|
free(string);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveCurrentToken(); //Remove terminating byte.
|
string->HasTerminatorByte = 1;
|
||||||
//TODO: add the raw value of the byte to the end of the string, but for now just pretend all numbers are zero.
|
string->TerminatorByte = token->Value.Number;
|
||||||
symbol->Length++;
|
|
||||||
|
|
||||||
ExpectLineEndOrFileEnd(RemoveExpected);
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpectLineEndOrFileEnd(ExpectOptions options) {
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter* GetParameterType() {
|
||||||
Token* token = PeekToken();
|
Token* token = PeekToken();
|
||||||
|
Symbol* symbol = NULL;
|
||||||
|
Parameter* param = CreateParameter(NoParameter);
|
||||||
|
|
||||||
if (token->EndOfFile) return;
|
switch(token->Class) {
|
||||||
|
case RegisterClass:
|
||||||
|
param->ParameterType = RegisterParameter;
|
||||||
|
param->InterpretedAs = RegisterParameter;
|
||||||
|
|
||||||
if (token->Class != PunctuationClass || token->Value.Punctuation != NewLine) {
|
param->Value.Register = token->Value.Register;
|
||||||
fprintf(stderr, "[Line %d] Syntax error, expected line break.\n", token->LineNumber);
|
|
||||||
exit(9);
|
AdvanceParser();
|
||||||
|
|
||||||
|
return param;
|
||||||
|
case IdentifierClass:
|
||||||
|
param->ParameterType = AddressParameter;
|
||||||
|
param->InterpretedAs = AddressParameter;
|
||||||
|
|
||||||
|
symbol = TryGetSymbol(token->Lemexe, MachineState.SymbolsTable);
|
||||||
|
|
||||||
|
if (!symbol) symbol = AddSymbolToTable(token->Lemexe, MachineState.SymbolsTable);
|
||||||
|
|
||||||
|
param->Value.Symbol = symbol;
|
||||||
|
|
||||||
|
AdvanceParser();
|
||||||
|
|
||||||
|
return param;
|
||||||
|
case PunctuationClass:
|
||||||
|
if (token->Value.Punctuation != LBracket) {
|
||||||
|
fprintf(stderr, "[Error] Line %d: Expected opening bracket\n", token->LineNumber);
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options & RemoveExpected) RemoveCurrentToken();
|
AdvanceParser(); // [
|
||||||
if (options & ForwardParser) AdvanceParser();
|
|
||||||
|
token = PeekToken();
|
||||||
|
|
||||||
|
if (token->Class == NumberClass) {
|
||||||
|
param->ParameterType = ConstantParameter;
|
||||||
|
param->InterpretedAs = AddressParameter;
|
||||||
|
param->Value.Number = token->Value.Number;
|
||||||
|
}
|
||||||
|
else if (token->Class == RegisterClass) {
|
||||||
|
param->ParameterType = RegisterParameter;
|
||||||
|
param->InterpretedAs = AddressParameter;
|
||||||
|
param->Value.Register = token->Value.Register;
|
||||||
|
}
|
||||||
|
else if (token->Class & AddressClass) {
|
||||||
|
param->ParameterType = AddressParameter;
|
||||||
|
param->ParameterType = AddressParameter;
|
||||||
|
|
||||||
|
symbol = TryGetSymbol(token->Lemexe, MachineState.SymbolsTable);
|
||||||
|
|
||||||
|
if (!symbol) symbol = AddSymbolToTable(token->Lemexe, MachineState.SymbolsTable);
|
||||||
|
|
||||||
|
param->Value.Symbol = symbol;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "[Error] Line %d: Expected identifier, constant number or register.\n", token->LineNumber);
|
||||||
|
IgnoreParserLine();
|
||||||
|
//return NULL;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvanceParser(); //Consume the parameter it self.
|
||||||
|
|
||||||
|
token = PeekToken();
|
||||||
|
|
||||||
|
if (token->Class != PunctuationClass || token->Value.Punctuation != RBracket) {
|
||||||
|
fprintf(stderr, "[Error] Line %d: Expected closing bracket.\n", token->LineNumber);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvanceParser(); // ]
|
||||||
|
|
||||||
|
return param;
|
||||||
|
case NumberClass:
|
||||||
|
param->ParameterType = ConstantParameter;
|
||||||
|
param->InterpretedAs = ConstantParameter;
|
||||||
|
|
||||||
|
param->Value.Number = token->Value.Number;
|
||||||
|
|
||||||
|
AdvanceParser();
|
||||||
|
|
||||||
|
return param;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleOperation() {
|
||||||
|
Token* token = PeekToken();
|
||||||
|
char mn[12];
|
||||||
|
|
||||||
|
Instruction* ins = CreateInstruction(token->Value.Mnemonic);
|
||||||
|
|
||||||
|
GetMnemonicText(ins->Mnemonic, mn);
|
||||||
|
|
||||||
|
AdvanceParser();
|
||||||
|
|
||||||
|
//No parameters here, we have a line break.
|
||||||
|
if (PeekToken()->EndOfFile || (PeekToken()->Class == PunctuationClass && PeekToken()->Value.Punctuation == NewLine)) {
|
||||||
|
goto InsertInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
ins->ParameterOne = GetParameterType();
|
||||||
|
|
||||||
|
if (ins->ParameterOne->ParameterType == NoParameter) {
|
||||||
|
//This would be an error if the next token isn't a line break.
|
||||||
|
if (PeekToken()->Class != PunctuationClass || PeekToken()->Value.Punctuation != NewLine) {
|
||||||
|
fprintf(stderr, "[Error] Line %d: Syntax error, expected line break but got %s.\n", token->LineNumber, token->Lemexe);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto InsertInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PeekToken()->Class == PunctuationClass && PeekToken()->Value.Punctuation == NewLine) {
|
||||||
|
goto InsertInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PeekToken()->Class != PunctuationClass || PeekToken()->Value.Punctuation != Comma) {
|
||||||
|
//Syntax error
|
||||||
|
fprintf(stderr, "[Error] Line %d: Expected comma.\n", token->LineNumber);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvanceParser(); //Consume the comma
|
||||||
|
|
||||||
|
ins->ParameterTwo = GetParameterType();
|
||||||
|
|
||||||
|
InsertInstruction:
|
||||||
|
|
||||||
|
AddListItem(ins, sizeof(Instruction), MachineState.Instructions);
|
||||||
|
|
||||||
|
AdvanceParser(); //Consume the line break
|
||||||
|
|
||||||
|
free(ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintSymbols(void) {
|
void PrintSymbols(void) {
|
||||||
char mn[12];
|
|
||||||
printf("-----SYMBOLS-----\n");
|
printf("-----SYMBOLS-----\n");
|
||||||
for(int i = 0; i < SymbolsTable->Size; i++) {
|
for(int i = 0; i < MachineState.SymbolsTable->Size; i++) {
|
||||||
Symbol* symbol = SymbolsTable->Symbols[i];
|
Symbol* symbol = MachineState.SymbolsTable->Symbols[i];
|
||||||
|
|
||||||
printf("[%s] %s [Width: %d]", SymbolResolved(symbol) == 0 ? "Unresolved" : "Resolved", symbol->Name, symbol->Length);
|
printf("[Resolved? %d] %s\n", symbol->Resolved, symbol->Name);
|
||||||
|
|
||||||
if (symbol->Token && symbol->Token->Class == MnemonicClass)
|
|
||||||
{
|
|
||||||
GetMnemonicText(symbol->Token->Value.Mnemonic, mn);
|
|
||||||
printf(" -> [%s]", mn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (symbol->Token) printf(" Line %d", symbol->Token->LineNumber);
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
printf("-----SYMBOLS-----\n");
|
printf("-----SYMBOLS-----\n");
|
||||||
}
|
}
|
||||||
@@ -552,7 +296,3 @@ void IgnoreParserLine(void) {
|
|||||||
AdvanceParser();
|
AdvanceParser();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveCurrentToken(void) {
|
|
||||||
RemoveToken(CurrentToken, TokensList);
|
|
||||||
}
|
|
||||||
+18
-25
@@ -21,8 +21,8 @@ Token* ParseNumber(void);
|
|||||||
Token* ParsePunctuation(char);
|
Token* ParsePunctuation(char);
|
||||||
void IgnoreLine(void);
|
void IgnoreLine(void);
|
||||||
|
|
||||||
TokenList* GenerateTokenList(const char* source) {
|
List* GenerateTokenList(const char* source) {
|
||||||
TokenList* tokens = CreateTokenList();
|
List* tokens = CreateList();
|
||||||
Token* token = NULL;
|
Token* token = NULL;
|
||||||
|
|
||||||
if (!tokens) return NULL;
|
if (!tokens) return NULL;
|
||||||
@@ -54,7 +54,7 @@ TokenList* GenerateTokenList(const char* source) {
|
|||||||
|
|
||||||
token = CreateToken(Line, PunctuationClass);
|
token = CreateToken(Line, PunctuationClass);
|
||||||
token->Value.Punctuation = NewLine;
|
token->Value.Punctuation = NewLine;
|
||||||
AddToken(token, tokens);
|
AddListItem(token, sizeof(Token), tokens);
|
||||||
AdvanceScanner();
|
AdvanceScanner();
|
||||||
Line++;
|
Line++;
|
||||||
break;
|
break;
|
||||||
@@ -67,30 +67,30 @@ TokenList* GenerateTokenList(const char* source) {
|
|||||||
Line++;
|
Line++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '.': //directive like ".include" or ".db"
|
case '.': //directive like ".org" or ".db"
|
||||||
token = ParseDirective();
|
token = ParseDirective();
|
||||||
if (token) AddToken(token, tokens);
|
if (token) AddListItem(token, sizeof(Token), tokens);
|
||||||
break;
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
token = ParseString();
|
token = ParseString();
|
||||||
if (token) AddToken(token, tokens);
|
if (token) AddListItem(token, sizeof(Token), tokens);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (isdigit(c)) {
|
if (isdigit(c)) {
|
||||||
AddToken(ParseNumber(), tokens);
|
AddListItem(ParseNumber(), sizeof(Token), tokens);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsPunctuation(c)) {
|
if (IsPunctuation(c)) {
|
||||||
AdvanceScanner();
|
AdvanceScanner();
|
||||||
AddToken(ParsePunctuation(c), tokens);
|
AddListItem(ParsePunctuation(c), sizeof(Token), tokens);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
token = ParseIdentifier();
|
token = ParseIdentifier();
|
||||||
|
|
||||||
if (token) AddToken(token, tokens);
|
if (token) AddListItem(token, sizeof(Token), tokens);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ TokenList* GenerateTokenList(const char* source) {
|
|||||||
|
|
||||||
token->EndOfFile = 1;
|
token->EndOfFile = 1;
|
||||||
|
|
||||||
AddToken(token, tokens);
|
AddListItem(token, sizeof(Token), tokens);
|
||||||
|
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
@@ -128,7 +128,7 @@ Token* ParseNumber(void) {
|
|||||||
if ((ahead >= 'a' && ahead <= 'f') || isdigit(ahead)) {
|
if ((ahead >= 'a' && ahead <= 'f') || isdigit(ahead)) {
|
||||||
AdvanceScanner(); //Consume the 'x'
|
AdvanceScanner(); //Consume the 'x'
|
||||||
|
|
||||||
while(!ScannerAtEnd() && PeekScanner() != '\n' && !IsWhiteSpace(PeekScanner()) && PeekScanner() != ';') {
|
while(!ScannerAtEnd() && PeekScanner() != '\n' && !IsWhiteSpace(PeekScanner())) {
|
||||||
if (isdigit(PeekScanner())) {
|
if (isdigit(PeekScanner())) {
|
||||||
AdvanceScanner();
|
AdvanceScanner();
|
||||||
continue;
|
continue;
|
||||||
@@ -191,16 +191,17 @@ Token* ParseDirective(void) {
|
|||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
else if (strcmp(directive, ".include") == 0) {
|
else if (strcmp(directive, ".org") == 0) {
|
||||||
token->Value.Directive = Include;
|
fprintf(stderr, "[Warning] Org is not a supported directive.\n");
|
||||||
|
free(directive);
|
||||||
return token;
|
free(token);
|
||||||
|
IgnoreLine();
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "[Error] Unknown assembler directive '%s'\n", directive);
|
fprintf(stderr, "[Error] Unknown assembler directive '%s'\n", directive);
|
||||||
|
|
||||||
free(directive);
|
free(directive);
|
||||||
free(token);
|
|
||||||
|
|
||||||
IgnoreLine();
|
IgnoreLine();
|
||||||
|
|
||||||
@@ -243,7 +244,7 @@ Token* ParseString(void) {
|
|||||||
Token* ParseIdentifier(void) {
|
Token* ParseIdentifier(void) {
|
||||||
int start = Position;
|
int start = Position;
|
||||||
|
|
||||||
while(!ScannerAtEnd() && !IsPunctuation(PeekScanner()) && PeekScanner() != ' ' && PeekScanner() != '\n' && PeekScanner() != ';') {
|
while(!ScannerAtEnd() && !IsPunctuation(PeekScanner()) && PeekScanner() != ' ' && PeekScanner() != '\n') {
|
||||||
AdvanceScanner();
|
AdvanceScanner();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,14 +284,6 @@ Token* ParseIdentifier(void) {
|
|||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
if (strcmp(lexeme, "byte") == 0) {
|
|
||||||
Token* token = CreateToken(Line, DirectiveClass);
|
|
||||||
|
|
||||||
token->Lemexe = lexeme;
|
|
||||||
token->Value.Directive = Byte;
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
Token* token = CreateToken(Line, IdentifierClass);
|
Token* token = CreateToken(Line, IdentifierClass);
|
||||||
|
|
||||||
|
|||||||
+20
-31
@@ -3,23 +3,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
int SymbolResolved(Symbol* symbol) {
|
|
||||||
if (!symbol) return 0;
|
|
||||||
|
|
||||||
return symbol->Token != NULL;
|
|
||||||
|
|
||||||
// switch (symbol->Type) {
|
|
||||||
// case RefLiteral:
|
|
||||||
// return 1;
|
|
||||||
// case RefExpression:
|
|
||||||
// return 0;
|
|
||||||
// case RefPointer:
|
|
||||||
// return symbol->Value.Mnemonic != 0;
|
|
||||||
// default:
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
SymbolTable* CreateSymbolTable(void){
|
SymbolTable* CreateSymbolTable(void){
|
||||||
SymbolTable* table = calloc(1, sizeof(SymbolTable));
|
SymbolTable* table = calloc(1, sizeof(SymbolTable));
|
||||||
|
|
||||||
@@ -42,7 +25,7 @@ SymbolTable* CreateSymbolTable(void){
|
|||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol* CreateSymbol(char* name, int address) {
|
Symbol* CreateSymbol(char* name) {
|
||||||
Symbol* symbol = calloc(1, sizeof(Symbol));
|
Symbol* symbol = calloc(1, sizeof(Symbol));
|
||||||
|
|
||||||
if (!symbol) {
|
if (!symbol) {
|
||||||
@@ -51,29 +34,35 @@ Symbol* CreateSymbol(char* name, int address) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol->Address = address;
|
|
||||||
symbol->Name = name;
|
symbol->Name = name;
|
||||||
//symbol->Type = RefUnknown;
|
|
||||||
|
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TryGetSymbol(char* name, SymbolTable* table, Symbol** outSymbol) {
|
SymbolString* CreateSymbolString(char* text) {
|
||||||
*outSymbol = NULL;
|
SymbolString* string = calloc(1, sizeof(SymbolString));
|
||||||
|
|
||||||
if (!name || !table) return 0;
|
if (!string) {
|
||||||
|
fprintf(stderr, "Failed to create string data for symbol. %s.\n", strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
string->String = text;
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol* TryGetSymbol(char* name, SymbolTable* table) {
|
||||||
|
if (!name || !table) return NULL;
|
||||||
|
|
||||||
for(int i = 0; i < table->Size; i++) {
|
for(int i = 0; i < table->Size; i++) {
|
||||||
if (strcmp(table->Symbols[i]->Name, name) == 0) {
|
if (strcmp(table->Symbols[i]->Name, name) == 0) return table->Symbols[i];
|
||||||
*outSymbol = table->Symbols[i];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol* AddSymbolToTable(char* name, int address, SymbolTable* table) {
|
Symbol* AddSymbolToTable(char* name, SymbolTable* table) {
|
||||||
//if (!name || !value || !table || length == 0) return NULL;
|
//if (!name || !value || !table || length == 0) return NULL;
|
||||||
|
|
||||||
for(int i = 0; i < table->Size; i++) {
|
for(int i = 0; i < table->Size; i++) {
|
||||||
@@ -85,7 +74,7 @@ Symbol* AddSymbolToTable(char* name, int address, SymbolTable* table) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (table->Capacity < table->Size + 1) {
|
if (table->Capacity < table->Size + 1) {
|
||||||
Symbol** newBlock = realloc(table->Symbols, sizeof(Symbol*) * table->Capacity * 2);
|
Symbol** newBlock = realloc(table->Symbols, sizeof(Symbol*) * table->Capacity * 2);//calloc(table->Size * 2, sizeof(Symbol*));
|
||||||
|
|
||||||
if (!newBlock) {
|
if (!newBlock) {
|
||||||
fprintf(stderr, "Failed to realloc space for a new symbol '%s'. %s.\n", name, strerror(errno));
|
fprintf(stderr, "Failed to realloc space for a new symbol '%s'. %s.\n", name, strerror(errno));
|
||||||
@@ -97,7 +86,7 @@ Symbol* AddSymbolToTable(char* name, int address, SymbolTable* table) {
|
|||||||
table->Symbols = newBlock;
|
table->Symbols = newBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol* symbol = CreateSymbol(name, address);
|
Symbol* symbol = CreateSymbol(name);
|
||||||
|
|
||||||
table->Symbols[table->Size] = symbol;
|
table->Symbols[table->Size] = symbol;
|
||||||
table->Size++;
|
table->Size++;
|
||||||
|
|||||||
-67
@@ -1,7 +1,5 @@
|
|||||||
#include "../includes/token.h"
|
#include "../includes/token.h"
|
||||||
|
|
||||||
#define LISTDEFAULTSIZE 32
|
|
||||||
|
|
||||||
Token* CreateToken(int lineNumber, TokenClass tokenClass) {
|
Token* CreateToken(int lineNumber, TokenClass tokenClass) {
|
||||||
Token* token = calloc(1, sizeof(Token));
|
Token* token = calloc(1, sizeof(Token));
|
||||||
|
|
||||||
@@ -21,68 +19,3 @@ void FreeToken(Token* token) {
|
|||||||
|
|
||||||
free(token);
|
free(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenList* CreateTokenList(void) {
|
|
||||||
TokenList *new = malloc(sizeof(TokenList));
|
|
||||||
|
|
||||||
if (!new) {
|
|
||||||
fprintf(stderr, "Failed to malloc() for new new List.\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
new->content = calloc(LISTDEFAULTSIZE, sizeof(void*));
|
|
||||||
|
|
||||||
if (!new->content) {
|
|
||||||
fprintf(stderr, "Failed to malloc() memory for List contents.\n");
|
|
||||||
free(new);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
new->size = 0;
|
|
||||||
new->capacity = LISTDEFAULTSIZE;
|
|
||||||
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AddToken(Token* token, TokenList* list) {
|
|
||||||
if (!list || !token) return 0;
|
|
||||||
|
|
||||||
if (list->capacity < list->size + 1) {
|
|
||||||
void* ptr = realloc(list->content, sizeof(void*) * list->capacity * 2);
|
|
||||||
//Note: realloc will free list->root if it succeeds.
|
|
||||||
if (!ptr) {
|
|
||||||
fprintf(stderr, "Failed to resize array with realloc() (%d bytes).\n", list->capacity * 2);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
list->content = ptr;
|
|
||||||
list->capacity *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list->size > 0)
|
|
||||||
{
|
|
||||||
Token* prev = list->content[list->size - 1];
|
|
||||||
|
|
||||||
token->Prev = prev;
|
|
||||||
prev->Next = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
list->content[list->size] = token;
|
|
||||||
list->size++;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoveToken(int index, TokenList* list) {
|
|
||||||
Token* token = list->content[index];
|
|
||||||
|
|
||||||
if (token->Prev) token->Prev->Next = token->Next;
|
|
||||||
|
|
||||||
memmove(&list->content[index], &list->content[index + 1], (list->size - index) * sizeof(Token*));
|
|
||||||
|
|
||||||
list->size--;
|
|
||||||
|
|
||||||
list->content[list->size] = NULL;
|
|
||||||
|
|
||||||
FreeToken(token);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user