2 Commits
17 changed files with 651 additions and 1007 deletions
+3 -3
View File
@@ -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
View File
@@ -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}
+21
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+22 -9
View File
@@ -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
View File
@@ -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
-44
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+28 -179
View File
@@ -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,16 +32,20 @@ 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);
} }
} }
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);
} }
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++;
}
}
+153 -47
View File
@@ -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;
}
} }
+196 -456
View File
@@ -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);
}
return &MachineState;
} }
void HandleAssemblerDirective() { SymbolString* ParseIdentifierParameter(void) {
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;
}
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;
}
return NULL;
} }
void ExpectLineEndOrFileEnd(ExpectOptions options) { 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
View File
@@ -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);
+22 -33
View File
@@ -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));
for(int i = 0; i < table->Size; i++) { return NULL;
if (strcmp(table->Symbols[i]->Name, name) == 0) {
*outSymbol = table->Symbols[i];
return 1;
}
} }
return 0; string->String = text;
return string;
} }
Symbol* AddSymbolToTable(char* name, int address, SymbolTable* table) { Symbol* TryGetSymbol(char* name, SymbolTable* table) {
if (!name || !table) return NULL;
for(int i = 0; i < table->Size; i++) {
if (strcmp(table->Symbols[i]->Name, name) == 0) return table->Symbols[i];
}
return NULL;
}
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
View File
@@ -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);
}