Compare commits

32 Commits
Author SHA1 Message Date
glm94 307519a2b1 Updated parser. 2022-10-06 22:08:33 -05:00
glm94 d3d2b06dbd Redesigning the way the Symbol's represent string declaration (the .db msg 'Hello World' type of declarations). 2022-10-06 21:33:29 -05:00
glm94 f38da9cc74 A bit of cleanup. 2022-10-04 21:05:15 +00:00
glm94 33309a2759 Updated the Instruction's structure and updated the Parser accordingly. 2022-10-04 20:37:47 +00:00
glm94 1f7989533b Fixed a bug in the SymbolsTable where it wouldn't update its size. 2022-10-03 20:11:04 -05:00
glm94 cd1258a724 Fixed various Parser bugs. 2022-10-03 19:58:44 -05:00
glm94 be91e3c112 Updated the parser to better handle parameters, sort of and including a string length assembly program to use as a test for the whole assembler. 2022-10-03 21:26:28 +00:00
glm94 706f480e31 The Scanner will now check for empty lines (is the previous token and the current token a new line?) and simply not emit a NewLine Token. 2022-10-03 19:40:00 +00:00
glm94 a949007c75 Updated the ISA so the program will correctly see things like 'load', 'inc' and 'dec'. 2022-10-03 16:56:39 +00:00
glm94 a0d5d62a34 Fixed a bug in the Scanner when parsing a hex number, still not super robust but it'll work. 2022-10-03 15:20:31 +00:00
glm94 f7cd87f13f Started reworking the Parser to simplify how instructions will be represented. It will act like a 'first pass' that will do grammar checks but not verify the parameters of the opcodes. 2022-10-02 22:54:18 -05:00
glm94 55f4c32764 Missed this for the Scanner fix. 2022-10-02 22:12:16 -05:00
glm94 097eca383b Fixed a bug with the Scanner adding a blank line via a single NewLine Token when a file starts with a block of comments. 2022-10-01 20:43:55 -05:00
glm94 984683bfc5 Minor adjustment to Figure 1.1 2022-09-29 22:57:12 -05:00
glm94 0f42ad2997 Updated the ISA and added links in the table of contents. 2022-09-29 22:11:19 -05:00
glm94 63438b551b Got the scanner running again. Seems to be picking up punctuation, labels, identifiers and strings as expected. 2022-09-29 21:32:08 -05:00
glm94 e94e486e18 More refinements to the loading data instructions. I am truly bad at this whole thing... 2022-09-29 20:42:37 +00:00
glm94 2b71ac05a0 Added a note about a proposal regarding assembly language design. 2022-09-27 17:46:50 +00:00
glm94 02cf72902e Updated the load instructions. 2022-09-26 22:13:48 -05:00
glm94 afa84076c8 Added a command to make generating an opcode table a one liner. Updated the ISA. 2022-09-23 19:36:27 +00:00
glm94 925f7703d6 Updated the ISA, hopefully I can get this all put together in a thought out way. 2022-09-22 20:49:20 +00:00
glm94 a82a4c23ad Updated the docs. 2022-09-21 21:44:38 -05:00
glm94 f5c82d1c36 Added a LaTex document to put in writing how the machine should behave. 2022-09-21 16:23:11 +00:00
glm94 0b58e0124f Some refactoring to update everything to use the new structures and some new considerations for how Symbols and Instructions shoudl be represented. 2022-09-15 22:14:38 -05:00
glm94 2ae60a607c Incomplete, but I want to make sure the ideas I have here don't get wiped. Sadly this commit won't compile. 2022-09-15 21:29:27 +00:00
glm94 6d17dffcdf Added a SymbolTable object (untested at the moment) and redefined the Symbol object. I think when a Symbol is made only the size of it should matter to the code that will assemble the final binary. 2022-09-08 20:56:02 +00:00
glm94 2518214585 Added a length attribute to the symbol. 2022-09-06 14:15:45 +00:00
glm94 7004fff659 This feels like a trainwreck but eh. Changed the way the opcodes are managed. Hopefully this is the right direction when I add support for multiple ASM files. 2022-09-01 18:46:59 +00:00
glm94 13f8ff194b Smoothbrain indeed... 2022-08-30 22:48:49 -05:00
glm94 dac01ffd0c Changed the TokenClass from opcode to nomic, a less smoothbrain name IMO and also frees up Opcode for a better use later on. 2022-08-30 22:06:50 -05:00
glm94 3c7056c5e6 The main function will now write out the output of the parser. 2022-08-29 21:23:02 +00:00
glm94 6c7b8d5356 Fixed a bug where CMP REG, REG wouldn't get encoded and a disassembler bug related to said CMP bug. 2022-08-29 19:29:34 +00:00
15 changed files with 973 additions and 625 deletions
+3
View File
@@ -1,3 +1,6 @@
assm assm
obj/ obj/
bin/ bin/
*.bin
docs/*
!docs/*.tex
+144
View File
@@ -0,0 +1,144 @@
\documentclass[a4paper,12pt]{book}
\usepackage{tikz}
\usepackage{hyperref}
\hypersetup{
linktoc=all
}
\title{Unnamed Machine}
\author{A Very Terrible 16-bit Machine}
\newcommand{\OpcodeTable}[4] {
\begin{tabular}{ c c c c }
\hline
Opcode & Mnemonic & Operand 1 & Operand 2 \\
\hline\hline
#1 & #2 & #3 & #4 \\
\hline
\end{tabular}
}
\begin{document}
\maketitle
\tableofcontents
\chapter{Overview}
\section{Introduction}
This is a very poorly thought out 16-bit machine, but you've got to start somewhere. Currently debating between a CPU status register, 80x86 style, or just placing arithmetic results into a predetermined register. This is more of a loadstore architecture to try and keep the instruction set simple. The machine will be big-endian.
\section{Registers}
The following are the general purpose registers that can be used.
\begin{itemize}
\item[] R1
\item[] ...
\item[] R8
\end{itemize}
Additionally, there will be a special status register that will be a signed 16 bit register that the compare and jump instructions will read or write to when determining what action, if any, they'll take.
\section{Memory Model}
Memory will be implicitly mapped I/O. The bottom 3201 bytes of memory will be reserved for the keyboard input and graphics.
A single byte is reserved for the keyboard's input. The current key will be stored in byte 0xF37E, with the most significant bit being a flag indicating that the keyboard
is ready to be read from. This means that the character encoding is actually 7 bits.
Video memory starts at 0xF37F (62335 decimal), and every byte represents an ASCII character in monochrome.
\begin{figure}[!htb]
\centering
\begin{tikzpicture}
\fill[gray!5] (0,0)rectangle(5,10);
%\draw (0,10) .. controls (-2,6) and (-2,4) .. (0,1);
%\draw (0,10) arc (0:180:3cm);
\draw (0,10) -- (5,10);
\draw (0,1) -- node[above] {Video 0xF37F} (5,1);
\draw (0,0) -- (5,0);
\node[label=right:Top 0x0000] at (5,10) {};
\node[label=right:Bottom 0xFFFF] at (5,0) {};
\end{tikzpicture}
\caption{Memory Layout}
\end{figure}
\chapter{Instruction Set Architecture}
\section{Instruction Encoding}
Instructions are fixed to exactly one byte (8 bits).
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.
%https://tex.stackexchange.com/questions/32598/force-latex-image-to-appear-in-the-section-in-which-its-declared
\begin{figure}[!htb]
\centering
\begin{tabular}{ c c }
\hline
Instruction & Register \\
\hline\hline
0000 0 & 000 \\
\hline
\end{tabular}
\caption{Encoding Layout}
\end{figure}
\section{Notes}
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"
or "word" for two bytes. That would make the assembly easier to read but put a bit more work on the
assembler.
\section{STOB (Store Byte)}
\OpcodeTable{0x20}{stob}{Register}{Address}\\[6pt]
Stores a single byte (the lower nibble) from a register to a memory address.
\section{STOW (Store Machine Word)}
\OpcodeTable{0x20}{stow}{Register}{Address}\\[6pt]
Stores a machine word from a register to a memory address.
\section{LAA (Load Absolute Address)}
\OpcodeTable{0x00}{laa}{Register}{Address}\\[6pt]
Loads an address (2 bytes) into the register.
\section{LODB (Load Byte)}
\OpcodeTable{0x20}{lodb}{Register}{Register}\\[6pt]
Loads a single byte into a register from a memory address in the second operand register, zeroing out the high nibble.
\section{LODW (Load Machine Word)}
\OpcodeTable{0x20}{lodw}{Register}{Register}\\[6pt]
Loads a word into a register from a memory address in the second operand register.
\section{LODWI (Load Immediate Word)}
\OpcodeTable{0x00}{lodwi}{Register}{Constant}\\[6pt]
Loads an immediate machine word into the register clearing the high nibble if the value is less then 256.
\section{CMP (Compare)}
\OpcodeTable{0x20}{cmp}{Register}{Register}\\[6pt]
Compares two registers and somewhere sets a result in the status register.
\section{CMPI (Compare Immediate)}
\OpcodeTable{0x00}{cmpi}{Register}{Constant}\\[6pt]
Compares an immediate 2 byte value to the contents of a register setting the status register accordingly.
\section{ADD (Add)}
\OpcodeTable{0x20}{add}{Register}{Register}\\[6pt]
Performs addition on a register with a value from another (or the same) register.
\section{SUB (Subtract)}
\OpcodeTable{0x20}{sub}{Register}{Register}\\[6pt]
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)}
\OpcodeTable{0x00}{and}{Register}{Register}\\[6pt]
Logical ANDs the two registers together storing the result in operand 1.
\section{XOR (Logical Exclusive OR)}
\OpcodeTable{0x00}{xor}{Register}{Register}\\[6pt]
Logical XORs the two registers together storing the result in operand 1.
\section{OR (Logical OR)}
\OpcodeTable{0x00}{or}{Register}{Register}\\[6pt]
Logical ORs the two registers together storing the result in operand 1.
\section{NOT (Logical Negation)}
\OpcodeTable{0x00}{not}{Register}{None}\\[6pt]
Inverts the bits of the target register.
\section{SHR (Shift Right)}
\OpcodeTable{0x00}{shr}{Register}{Constant}\\[6pt]
Bit-wise shifts the contents of the register right Constant number of times.
\section{SHL (Shift Left)}
\OpcodeTable{0x00}{shl}{Register}{Constant}\\[6pt]
Bit-wise shifts the contents of the register left Constant number of times.
\section{INC (Increment)}
\OpcodeTable{0x00}{inc}{Register}{None}\\[6pt]
Increments the contents of the register by one. Over-flows will not be reported.
\section{DEC (Decrement)}
\OpcodeTable{0x00}{dec}{Register}{None}\\[6pt]
Decrements the contents of the register by one. Under-flows will not be reported.
\section{NOP (No Operation)}
\OpcodeTable{0x00}{nop}{None}{None}\\[6pt]
Skips a clock cycle, incrementing the program counter.
\end{document}
+1 -1
View File
@@ -3,7 +3,7 @@
#include "parser.h" #include "parser.h"
void Disassemble(unsigned char image[HIGHMEMORY]); //void Disassemble(unsigned char image[HIGHMEMORY]);
#endif #endif
+37 -19
View File
@@ -2,29 +2,47 @@
#define OPCODES_H #define OPCODES_H
#include <string.h> #include <string.h>
#include "token.h" #include "symbols_table.h"
#define OPCODECOUNT 13 typedef enum {
#define REGISTERCOUNT 8 R1, R2, R3, R4, R5, R6, R7, R8
} Registers;
typedef enum {
ADD, SUB, JZ, INT, YLD, RET,
CMP, NOP, JMP, CALL, LOAD, JE, INC, DEC, LOADB
} Mnemonic;
typedef enum {
NoParameter,
ConstantParameter,
AddressParameter,
RegisterParameter
} OpcodeParameter;
typedef struct { typedef struct {
char* lexeme; OpcodeParameter ParameterType;
TokenType op; OpcodeParameter InterpretedAs;
TokenClass parameter_one;
TokenClass parameter_two; union {
int Number; //ConstanrParam
Registers Register; //Register param
Symbol* Symbol; //Address param
} Value;
} Parameter;
typedef struct {
Mnemonic Mnemonic;
Parameter* ParameterOne;
Parameter* ParameterTwo;
} Instruction; } Instruction;
typedef struct { Instruction* CreateInstruction(Mnemonic mnemonic);
char* lexeme; Parameter* CreateParameter(OpcodeParameter parameterType);
TokenType type; void FreeInstruction(Instruction* instruction);
} Register; int IsOpcode(const char*, Mnemonic*);
int IsRegister(const char*, Registers*);
extern Instruction instructions[OPCODECOUNT]; void GetMnemonicText(Mnemonic mnemonic, char buffer[12]);
extern Register registers[REGISTERCOUNT]; unsigned char GetInstructionMask(Mnemonic type);
int IsOpcode(const char*, TokenType*);
int IsRegister(const char*, TokenType*);
const Instruction* GetOpcodeDetails(TokenType);
unsigned char GetInstructionMask(TokenType type, TokenClass parameterOneType);
#endif #endif
+11 -2
View File
@@ -1,14 +1,23 @@
#ifndef PARSER_H #ifndef PARSER_H
#define PARSER_H #define PARSER_H
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "list.h" #include "list.h"
#include "token.h" #include "token.h"
#include "opcodes.h" #include "opcodes.h"
#include "symbols_table.h"
#define HIGHMEMORY 65535 //64KiB - 1 AKA 0xFFFF //#define HIGHMEMORY 65535 //64KiB - 1 AKA 0xFFFF
unsigned char* ParseTokens(List*); typedef struct {
List* Instructions;
SymbolTable* SymbolsTable;
} IRState;
IRState* ParseTokens(List*);
#endif #endif
+48
View File
@@ -0,0 +1,48 @@
#ifndef SYMBOLSTABLE_H
#define SYMBOLSTABLE_H
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define SYMBOLSTABLE_DEFAULT_CAPACITY 128
typedef enum {
ValueAt,
Address
} SymbolType;
typedef struct {
char* String;
uint8_t TerminatorByte;
int HasTerminatorByte;
} SymbolString;
typedef struct {
char* Name;
int Length;
int Resolved;
union {
SymbolString String;
int Number;
//Instruction Instruction;
} Value;
} Symbol;
typedef struct {
Symbol** Symbols;
int Size;
int Capacity;
} SymbolTable;
SymbolTable* CreateSymbolTable(void);
Symbol* TryGetSymbol(char* name, SymbolTable* table);
Symbol* AddSymbolToTable(char* name, SymbolTable* table);
SymbolString* CreateSymbolString(char* text);
void FreeSymbolTable(SymbolTable* table);
void FreeSymbol(Symbol* symbol);
#endif
+42 -38
View File
@@ -5,52 +5,56 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include "opcodes.h"
#define REGISTEROFFSET 29
typedef enum { typedef enum {
PLUS, Plus = '+',
MINUS, Minus = '-',
STAR, Star = '*',
SLASH, Slash = '/',
POWER, Power = '^',
LPARAM, LParan = '(',
RPARAM, RParan = ')',
LBRACKET, LBracket = '[',
RBracket, RBracket = ']',
COMMA, Comma = ',',
STRING, NewLine = '\n'
IDENTIFIER, } TokenPunctuation;
LABEL,
NUMBER,
LineEnd,
//Keywords
DB, ORG,
//Opcodes
COPY, ADD, SUB, JZ, INT, YLD, RET,
CMP, NOP, JMP, CALL, IN, OUT,
//Registers
R1, R2, R3, R4, R5, R6, R7, R8
} TokenType;
typedef enum { typedef enum {
None = 0, DB,
Reg = 1, Origin,
Constant = 2, Byte
Address = 4, } Directive;
Opcode = 8,
Directive = 16 typedef enum {
RegisterClass = 0,
NumberClass = 1,
CharacterClass = 2,
MnemonicClass = 4,
DirectiveClass = 8,
PunctuationClass = 16,
IdentifierClass = 32,
LabelClass = 64,
AddressClass = LabelClass | IdentifierClass
} TokenClass; } TokenClass;
typedef struct { typedef struct {
TokenType type; char* Lemexe;
char* lexeme; TokenClass Class;
void* value; int LineNumber;
int line; int EndOfFile;
TokenClass token_class;
union {
TokenPunctuation Punctuation;
Registers Register;
Mnemonic Mnemonic;
Directive Directive;
int Number;
} Value;
} Token; } Token;
Token* CreateToken(char*, void*, int, TokenType); Token* CreateToken(int lineNumber, TokenClass tokenClass);
void FreeToken(Token*); void FreeToken(Token* token);
#endif #endif
+25 -25
View File
@@ -1,27 +1,27 @@
;.org 0x100 .db video_start 0xF37F
.db msg "Hello, world!", 0 .db msg "Hello, world!", 0
.db more_stuff "AA", 0
copy r7, msg ; //
cmp r8, 45 ;1000 1111
add r4, 30
sub r1, 69
int 20
jz 45
jmp msg
in 10
call more_stuff
ret
yld
;copy r1, 45 ;//B0 = 10110000 load r1, msg ; Because the lod* instructions can't load an address
;copy 2, 45 ; from anything but a register, this becomes laa r1, msg
;loop: load r8, [15]
; cmp r1, 0 ;Routine: string_length
; jz loop ;In: String address in r1
; add r1, 1 ;Out: Length in R2
;mov r1, 5 ; move the immediate value 5 into r1
;add r1,5 ; add 5 into r1 string_length:
;int 21 ; maybe that will call some string drawing BIOS-like routine loadb r3, [r1] ; Load the byte from the address in R1, into R3
;ret load r2, 0 ; String length
; 4 byte header cmp r3, 0 ; Is R3 a null byte?
; | Address of First Opcode (2 bytes) | End of Binary (2 bytes) | je end
inc r2
start:
inc r1 ; next char
loadb r3, [r1] ; Load the next character byte into R3
cmp r3, 0 ; Null byte?
je end
inc r2 ; Nope, increment the length counter
jmp start
end:
ret
+5 -4
View File
@@ -14,7 +14,7 @@ const unsigned char ADDRESSMASK = 0x10; //0001 0000
int IsRegisterPattern(unsigned char pattern, char* lexeme); int IsRegisterPattern(unsigned char pattern, char* lexeme);
void GetParameter(unsigned char instruction, char* text); void GetParameter(unsigned char instruction, char* text);
/*
void Disassemble(unsigned char image[HIGHMEMORY]) { void Disassemble(unsigned char image[HIGHMEMORY]) {
Image = image; Image = image;
int position = image[0] + image[1]; int position = image[0] + image[1];
@@ -32,8 +32,9 @@ void Disassemble(unsigned char image[HIGHMEMORY]) {
IsRegisterPattern(instruction & 0x07, parameter1); IsRegisterPattern(instruction & 0x07, parameter1);
unsigned char parameterType = instruction & 0x18; unsigned char parameterType = instruction & 0x18;
if (!parameterType) { if (parameterType == REGMASK) {
IsRegisterPattern(Image[position], parameter2); IsRegisterPattern(Image[position + 1], parameter2);
position += 2;
} else if (parameterType == CONSTMASK) { } else if (parameterType == CONSTMASK) {
snprintf(parameter2, sizeof(char) * 31, "%d", Image[position + 1] + Image[position + 2]); snprintf(parameter2, sizeof(char) * 31, "%d", Image[position + 1] + Image[position + 2]);
position += 3; position += 3;
@@ -116,7 +117,7 @@ void Disassemble(unsigned char image[HIGHMEMORY]) {
memset(parameter2, '\0', sizeof(char) * 32); memset(parameter2, '\0', sizeof(char) * 32);
} }
} }
*/
int IsRegisterPattern(unsigned char pattern, char* lexeme) { int IsRegisterPattern(unsigned char pattern, char* lexeme) {
if (pattern > 8) { if (pattern > 8) {
lexeme[0] = '\0'; lexeme[0] = '\0';
+68 -13
View File
@@ -1,3 +1,4 @@
#include <bits/types/FILE.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -6,7 +7,6 @@
#include "../includes/parser.h" #include "../includes/parser.h"
#include "../includes/futil.h" #include "../includes/futil.h"
#include "../includes/scanner.h" #include "../includes/scanner.h"
#include "../includes/disass.h"
int main(int argc, char* args[]) { int main(int argc, char* args[]) {
if (argc == 1) { if (argc == 1) {
@@ -20,23 +20,78 @@ int main(int argc, char* args[]) {
if (!ReadAllString(args[1], &source_code, &bytes_read)) return EX_IOERR; if (!ReadAllString(args[1], &source_code, &bytes_read)) return EX_IOERR;
List* list = GenerateTokenList(source_code); List* list = GenerateTokenList(source_code);
char mnemonic[12];
// 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->type == LineEnd) { if (t->EndOfFile) {
// if (i - 1 >= 0 && ((Token*) list->content[i - 1])->type != LineEnd) printf("EOF\n");
// printf("\n"); break;
}
// continue; if (t->Class == PunctuationClass){
// } if(t->Value.Punctuation == NewLine) {
printf("\n");
continue;
}
// printf("[%i] '%s' [%i] ", t->type, t->lexeme, t->token_class); printf("<%d>", t->LineNumber);
// if (t->type == LABEL) printf("* ");
// }
unsigned char* image = ParseTokens(list); printf("%c ", t->Value.Punctuation);
Disassemble(image); continue;
}
printf("<%d>", t->LineNumber);
if (t->Class == LabelClass) {
printf("[L]%s* ", t->Lemexe);
continue;
}
if (t->Class == IdentifierClass) {
printf("[I]%s ", t->Lemexe);
continue;
}
if (t->Class == RegisterClass) {
printf("[R]%d", t->Value.Register);
continue;
}
if (t->Class == NumberClass) {
printf("[N]%d ", t->Value.Number);
continue;
}
if (t->Class == MnemonicClass) {
GetMnemonicText(t->Value.Mnemonic, mnemonic);
printf("[M]%s ", mnemonic);
continue;
}
if (t->Class == DirectiveClass) {
printf("[D]%d ", t->Value.Directive);
}
if (t->Class == CharacterClass) {
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); free(source_code);
} }
+121 -48
View File
@@ -2,28 +2,71 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
Instruction instructions[OPCODECOUNT] = { #define OPCODECOUNT 15
{ "copy", COPY, Reg | Address, Reg | Constant | Address },
{ "add", ADD, Reg, Reg | Constant }, struct _instruction {
{ "sub", SUB, Reg, Reg | Constant }, char* Name;
{ "jz", JZ, Address, None }, Mnemonic Mnemonic;
{ "int", INT, Constant, None },
{ "yld", YLD, None, None },
{ "ret", RET, None, None },
{ "cmp", CMP, Reg, Reg | Constant },
{ "in", IN, Constant | Reg, None},
{ "out", OUT, None, None},
{ "nop", NOP, None, None},
{ "jmp", JMP, Address, None},
{ "call", CALL, Address, None}
}; };
unsigned char GetInstructionMask(TokenType type, TokenClass parameterOneType) { struct _instruction instructions[OPCODECOUNT] = {
switch (type) { { "add", ADD },//, Reg, Reg | Constant },
case COPY: { "sub", SUB },//, Reg, Reg | Constant },
if (parameterOneType & Reg) return 0x20; //0b00100000; { "jz", JZ },//, Address, None },
{ "int", INT },//, Constant, None },
{ "yld", YLD },//, None, None },
{ "ret", RET },//, None, None },
{ "cmp", CMP },//, Reg, Reg | Constant },
{ "inc", INC },//, Constant | Reg, None},
{ "dec", DEC },//, None, None},
{ "nop", NOP },//, None, None},
{ "jmp", JMP },//, Address, None},
{ "call", CALL },//, Address, None}
{ "load", LOAD },
{ "je", JE },
{ "loadb", LOADB}
};
return 0xA0;//0b10100000; 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: case ADD:
return 0x40;//0b01000000; return 0x40;//0b01000000;
case SUB: case SUB:
@@ -42,15 +85,26 @@ unsigned char GetInstructionMask(TokenType type, TokenClass parameterOneType) {
return 0x05; return 0x05;
case JMP: case JMP:
return 0x06;//0b00000110; return 0x06;//0b00000110;
case IN: case INC:
return 0x07;//0b00000111; return 0x07;//0b00000111;
case OUT: case DEC:
return 0x08;//0b00001000; return 0x08;//0b00001000;
default: default:
return 0x00; return 0x00;
} }
} }
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]) {
memset(buffer, '\0', 12);
for(int i = 0; i < OPCODECOUNT; i++) {
if (instructions[i].Mnemonic == mnemonic) {
strncpy(buffer, instructions[i].Name, 11);
break;
}
}
}
/* /*
NOP - 0000 0000 NOP NOP - 0000 0000 NOP
JZ - 0000 0001 JZ Address JZ - 0000 0001 JZ Address
@@ -84,31 +138,31 @@ unsigned char GetInstructionMask(TokenType type, TokenClass parameterOneType) {
//Address XXX1 0XXX //Address XXX1 0XXX
//R1 XXXX X000 -> XXXX X111 (R1 to R8) //R1 XXXX X000 -> XXXX X111 (R1 to R8)
Register registers[REGISTERCOUNT] = { // Register registers[REGISTERCOUNT] = {
{ "r1", R1 }, // { "r1", R1 },
{ "r2", R2 }, // { "r2", R2 },
{ "r3", R3 }, // { "r3", R3 },
{ "r4", R4 }, // { "r4", R4 },
{ "r5", R5 }, // { "r5", R5 },
{ "r6", R6 }, // { "r6", R6 },
{ "r7", R7 }, // { "r7", R7 },
{ "r8", R8 } // { "r8", R8 }
}; // };
const Instruction* GetOpcodeDetails(TokenType type) { // const Instruction* GetOpcodeDetails(Mnemonic type) {
for(int i = 0; i < OPCODECOUNT; i++) { // for(int i = 0; i < OPCODECOUNT; i++) {
if (instructions[i].op == type) return &instructions[i]; // if (instructions[i].op == type) return &instructions[i];
} // }
return NULL; // return NULL;
} // }
int IsOpcode(const char* text, TokenType* opcode) { int IsOpcode(const char* text, Mnemonic* opcode) {
if (!text) return 0; if (!text) return 0;
for(int i = 0; i < OPCODECOUNT; i++) { for(int i = 0; i < OPCODECOUNT; i++) {
if (strcmp(instructions[i].lexeme, text) == 0) { if (strcmp(instructions[i].Name, text) == 0) {
if (opcode) *opcode = instructions[i].op; if (opcode) *opcode = instructions[i].Mnemonic;
return 1; return 1;
} }
} }
@@ -116,15 +170,34 @@ int IsOpcode(const char* text, TokenType* opcode) {
return 0; return 0;
} }
int IsRegister(const char* text, TokenType* reg) { int IsRegister(const char* text, Registers* reg) {
if (!text) return 0; if (!text) return 0;
for(int i = 0; i < REGISTERCOUNT; i++) { int length = strlen(text);
if (strcmp(registers[i].lexeme, text) == 0) { Registers r = R8;
*reg = registers[i].type;
return 1;
}
}
return 0; if (length != 2) return 0;
if (text[0] != 'r') return 0;
switch(text[1]) {
case '1':
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;
return 1;
default:
return 0;
}
} }
+226 -421
View File
@@ -1,461 +1,271 @@
#include "../includes/parser.h" #include "../includes/parser.h"
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct {
Token* token;
int address;
} Symbol;
struct intr {
TokenType struction;
unsigned int parameter1;
unsigned int parameter2;
};
Symbol* CreateSymbol(Token* token, int address);
const List* TokensList; const List* TokensList;
int CurrentToken = 0; int CurrentToken = 0;
//int HeapStart = 4; // zero indexed, used for declared variables.
//int BinaryEnd = 4; // Zero indexed (binary starts with a 4 byte header)
void AddSymbol(Token*, int);
void PrintSymbols(void); void PrintSymbols(void);
void HandleOperation(void); SymbolString* ParseIdentifierParameter(void);
Instruction* HandleOperation(void);
void HandleAssemblerDirective(void); void HandleAssemblerDirective(void);
void AdvanceParser(void); void AdvanceParser(void);
void IgnoreParserLine(void);
Token* PeekToken(void); Token* PeekToken(void);
int ParserAtEnd(void); int ParserAtEnd(void);
int Expect(int, ...); IRState MachineState;
int ExpectTokenClass(int, ...);
const Symbol* GetSymbol(char*);
List* SymbolsTable;
void WriteMemory(unsigned char value, int location);
void WriteMemoryORMask(unsigned char mask, int location);
unsigned int HeapTop = 4;
unsigned int ProgramCounter = 0;
unsigned char Heap[HIGHMEMORY];
unsigned char Memory[HIGHMEMORY];
unsigned char* ParseTokens(List* tokens) { IRState* ParseTokens(List* tokens) {
if (!tokens) return NULL; if (!tokens) return NULL;
memset(Memory, 0, sizeof(Memory));
memset(Heap, 0, sizeof(Heap));
TokensList = tokens; TokensList = tokens;
SymbolsTable = CreateList(); MachineState.SymbolsTable = CreateSymbolTable();
MachineState.Instructions = CreateList();
while(!ParserAtEnd()) { while(!ParserAtEnd()) {
Token* t = PeekToken(); Token* t = PeekToken();
switch(t->token_class) { switch(t->Class) {
case Directive: case DirectiveClass: //Maybe these should be ignored, let another process handle that.
HandleAssemblerDirective(); IgnoreParserLine();
break; break;
case Opcode: case MnemonicClass:
HandleOperation(); HandleOperation();
break; break;
case Address: case LabelClass:
if (t->type == LABEL) { {
printf("%s: \n", t->lexeme); Symbol* symbol = TryGetSymbol(t->Lemexe, MachineState.SymbolsTable);
AddSymbol(t, ProgramCounter);
}
break;
default:
break;
}
AdvanceParser(); if (symbol && symbol->Resolved) {
} fprintf(stderr, "[Error] Line %d: Redefinition of symbol '%s'\n", t->LineNumber, t->Lemexe);
if (SymbolsTable->size > 0) PrintSymbols();
DestroyList(SymbolsTable);
memcpy(&Heap[HeapTop], Memory, ProgramCounter);
int totalSize = HeapTop + ProgramCounter;
Heap[0] = 2 >> HeapTop & 0xFF;
Heap[1] = HeapTop & 0xFF;
Heap[2] = 2 >> totalSize & 0xFF;
Heap[3] = totalSize & 0xFF;
// for(int i = 0; i < 33; i++) {
// if (i != 0 && i % 3 == 0) printf("\n");
// printf("%02X ", Heap[i] & 0xFF);
// }
// printf("\n");
// printf("Program Counter: %d\n", ProgramCounter);
// printf("Heap Top: %#06X\n", HeapTop);
return Heap;
}
void HandleAssemblerDirective(void) {
if (PeekToken()->type == DB) {
AdvanceParser();
Token* identifier = PeekToken();
if (!Expect(1, IDENTIFIER)) {
fprintf(stderr, "Expected identifier on line %d\n", identifier->line);
exit(1);
}
AddSymbol(identifier, HeapTop);
identifier = PeekToken();
switch(identifier->type) {
case STRING:
//printf("[INFO] %s = '%s' (%#04X)\n", identifier->lexeme, identifier->lexeme, HeapTop);
for(int i = 0; i < strlen(identifier->lexeme); i++) {
//Memory[ProgramCounter + i] = PeekToken()->lexeme[i];
Heap[HeapTop + i] = identifier->lexeme[i];
}
//ProgramCounter += strlen(PeekToken()->lexeme);
HeapTop += strlen(identifier->lexeme);
AdvanceParser();
if (PeekToken()->type == COMMA) {
AdvanceParser();
if (PeekToken()-> type != NUMBER) {
fprintf(stderr, "Expected string termination byte on line %d\n", PeekToken()->line);
exit(1); exit(1);
} }
else {
//Add the NULL byte. AdvanceParser(); //Consume the label token
//Memory[ProgramCounter] = '\0';
Heap[HeapTop] = '\0'; if (!symbol) AddSymbolToTable(t->Lemexe, MachineState.SymbolsTable)->Resolved = 1;
//ProgramCounter++; else symbol->Resolved = 1;
HeapTop++;
return; AdvanceParser(); //Consume the NewLine
}
// Instruction* ins = HandleOperation();
// if (!ins) continue;
// symbol->Value.Instruction = ins;
// symbol->InstructionPointer = 1;
} }
case NUMBER:
break; break;
default: default:
fprintf(stderr, "[Line: %d] Expected either a number or string after identifier '%s'.\n", PeekToken()->line, identifier->lexeme); 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();
break;
} }
} }
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 HandleRegisterBasedOpcode(unsigned char instruction, unsigned char mask) { SymbolString* ParseIdentifierParameter(void) {
Memory[ProgramCounter] = mask; Token* token = PeekToken();
ProgramCounter++; if (token->Class != IdentifierClass) {
fprintf(stderr, "[Error] Line %d: Expected identifier\n", token->LineNumber);
const Token* token = PeekToken(); IgnoreParserLine();
return NULL;
if (token->token_class == Reg) {
Memory[ProgramCounter - 1] |= (PeekToken()->type - R1) & 0x07;
AdvanceParser();
}
else {
fprintf(stderr, "[Error] Line %d: Expected register operand.\n", token->line);
exit(1);
} }
token = PeekToken(); SymbolString* string = CreateSymbolString(token->Lemexe);
if (!Expect(1, COMMA)) {
fprintf(stderr, "[Error] Expected command one line %d.\n", token->line);
exit(1);
}
token = PeekToken();
if (token->type == IDENTIFIER || token->type == LABEL) {
const Symbol* symbol = GetSymbol(token->lexeme);
if (!symbol) {
fprintf(stderr, "[Error] Line %d: %s is undefined.\n", token->line, token->lexeme);
exit(1);
}
Memory[ProgramCounter - 1] |= 0x10;//0b00010000;
Memory[ProgramCounter] = 2 >> symbol->address & 0xFF;
Memory[ProgramCounter + 1] = symbol->address & 0xFF;
AdvanceParser();
}
else if (token->type == NUMBER) {
Memory[ProgramCounter - 1] |= 0x08; //0b00001000;
int* value = PeekToken()->value;
Memory[ProgramCounter] = 2 >> *value & 0xFF;
Memory[ProgramCounter + 1] = *value & 0xFF;
AdvanceParser();
} else {
fprintf(stderr, "[Error] Expected operand, got %s\n", token->lexeme);
exit(1);
}
ProgramCounter += 2;
}
void HandleOperation(void) {
const Instruction* inst = GetOpcodeDetails(PeekToken()->type);
const unsigned char registerBasedOpcodeMask = 0xE0;
if (!inst) return;
AdvanceParser(); AdvanceParser();
unsigned char mask = GetInstructionMask(inst->op, inst->parameter_one); if (token->Class == PunctuationClass && token->Value.Punctuation == NewLine) {
return string;
if (mask & registerBasedOpcodeMask) {
HandleRegisterBasedOpcode(Memory[ProgramCounter], mask);
return;
} }
else if (token->Class == PunctuationClass && token->Value.Punctuation == Comma) {
AdvanceParser(); // Comsume the comma
switch (mask) { token = PeekToken();
case 0: //NOP
Memory[ProgramCounter] = 0x00;
ProgramCounter++;
return;
case 1: //JZ
Memory[ProgramCounter] = 0x01;
ProgramCounter++; if (token->Class != NumberClass) {
fprintf(stderr, "[Error] Line %d: Expected string termination number.\n", token->LineNumber);
if (PeekToken()->type == IDENTIFIER || PeekToken()->type == LABEL) { IgnoreParserLine();
const Symbol* symbol = GetSymbol(PeekToken()->lexeme); free(string);
return NULL;
if (!symbol) {
fprintf(stderr, "[Error] %s is undefined.\n", PeekToken()->lexeme);
exit(1);
}
Memory[ProgramCounter] = 2 >> symbol->address & 0xFF;
Memory[ProgramCounter + 1] = symbol->address & 0xFF;
}
else if (PeekToken()->type == NUMBER) {
int* value = PeekToken()->value;
Memory[ProgramCounter] = 2 >> *value & 0xFF;
Memory[ProgramCounter + 1] = *value & 0xFF;
}
else {
fprintf(stderr, "[Error] Line: %d: Expected address after jump if zero (JZ) instruction.\n", ((Token*) TokensList->content[CurrentToken - 1])->line);
exit(1);
}
ProgramCounter += 2;
return;
case 2: //INT
Memory[ProgramCounter] = 0x02;
ProgramCounter++;
if (PeekToken()->type == NUMBER) {
int* value = PeekToken()->value;
Memory[ProgramCounter] = 2 >> *value & 0xFF;
Memory[ProgramCounter + 1] = *value & 0xFF;
}
else {
fprintf(stderr, "[Error] Line %d: Expected Interrupt vector.\n", PeekToken()->line);
exit(1);
}
ProgramCounter += 2;
return;
case 3: //YLD
Memory[ProgramCounter] = 0x03;
ProgramCounter++;
break;
case 4: //RET
Memory[ProgramCounter] = 0x04;
ProgramCounter++;
break;
case 5: //CALL
Memory[ProgramCounter] = 0x05;
ProgramCounter++;
if (PeekToken()->type == IDENTIFIER || PeekToken()->type == LABEL) {
const Symbol* symbol = GetSymbol(PeekToken()->lexeme);
if (!symbol) {
fprintf(stderr, "[Error] Line %d: %s is undefined.\n", PeekToken()->line, PeekToken()->lexeme);
exit(1);
}
Memory[ProgramCounter] = 2 >> symbol->address & 0xFF;
Memory[ProgramCounter + 1] = symbol->address & 0xFF;
}
else {
fprintf(stderr, "[Error] Line %d: Expected address or label.\n", PeekToken()->line);
exit(1);
}
ProgramCounter += 2;
break;
case 6: //JMP
Memory[ProgramCounter] = 0x06;
ProgramCounter++;
if (PeekToken()->type == IDENTIFIER || PeekToken()->type == LABEL) {
const Symbol* symbol = GetSymbol(PeekToken()->lexeme);
if (!symbol) {
fprintf(stderr, "[Error] Line %d: %s is undefined.\n", PeekToken()->line, PeekToken()->lexeme);
exit(1);
}
Memory[ProgramCounter] = 2 >> symbol->address & 0xFF;
Memory[ProgramCounter + 1] = symbol->address & 0xFF;
}
else {
fprintf(stderr, "[Error] Line %d: Expected address or label.\n", PeekToken()->line);
exit(1);
}
ProgramCounter += 2;
break;
case 7: //IN
Memory[ProgramCounter] = 0x07;
ProgramCounter++;
if (PeekToken()->type == NUMBER) {
int* value = PeekToken()->value;
Memory[ProgramCounter] = 2 >> *value & 0xFF;
Memory[ProgramCounter + 1] = *value & 0xFF;
}
else {
fprintf(stderr, "[Error] Line %d: Expected port number.\n", PeekToken()->line);
exit(1);
}
ProgramCounter += 2;
break;
case 8: //OUT
Memory[ProgramCounter] = 0x08;
ProgramCounter++;
if (PeekToken()->type == NUMBER) {
int* value = PeekToken()->value;
Memory[ProgramCounter] = 2 >> *value & 0xFF;
Memory[ProgramCounter + 1] = *value & 0xFF;
}
else {
fprintf(stderr, "[Error] Line %d: Expected port number.\n", PeekToken()->line);
exit(1);
}
ProgramCounter += 2;
break;
}
return;
}
int ExpectTokenClass(int count, ...) {
va_list list;
Token* token = PeekToken();
va_start(list, count);
for(int i = 0; i < count; i++) {
if (va_arg(list, TokenClass) == token->token_class) {
va_end(list);
AdvanceParser();
return 1;
} }
}
va_end(list); string->HasTerminatorByte = 1;
string->TerminatorByte = token->Value.Number;
return 0; return string;
}
int Expect(int count, ...) {
va_list list;
Token* token = PeekToken();
va_start(list, count);
for(int i = 0; i < count; i++) {
if (va_arg(list, TokenType) == token->type) {
va_end(list);
AdvanceParser();
return 1;
}
}
va_end(list);
return 0;
}
void PrintSymbols(void) {
printf("-----SYMBOLS-----\n");
for(int i = 0; i < SymbolsTable->size; i++) {
Symbol* symbol = SymbolsTable->content[i];
printf("[%#06X] %s\n", symbol->address, symbol->token->lexeme);
}
printf("-----SYMBOLS-----\n");
}
void AddSymbol(Token* token, int address) {
if (!token) return;
if (token->type != IDENTIFIER && token->type != LABEL) return;
for(int i = 0; i < SymbolsTable->size; i++) {
Symbol* s = SymbolsTable->content[i];
if (strcmp(s->token->lexeme, token->lexeme) == 0) return;
}
Symbol* symbol = CreateSymbol(token, address);
AddListItem(symbol, sizeof(Symbol), SymbolsTable);
}
const Symbol* GetSymbol(char* name) {
if (!name) return NULL;
for(int i = 0; i < SymbolsTable->size; i++) {
const Symbol* s = SymbolsTable->content[i];
if (strcmp(s->token->lexeme, name) == 0) return s;
} }
return NULL; return NULL;
} }
Symbol* CreateSymbol(Token* token, int address) { Parameter* GetParameterType() {
Symbol* symbol = calloc(1, sizeof(Symbol)); Token* token = PeekToken();
Symbol* symbol = NULL;
Parameter* param = CreateParameter(NoParameter);
if (!symbol) return NULL; switch(token->Class) {
case RegisterClass:
param->ParameterType = RegisterParameter;
param->InterpretedAs = RegisterParameter;
symbol->token = token; param->Value.Register = token->Value.Register;
symbol->address = address;
return symbol; 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);
}
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) {
printf("-----SYMBOLS-----\n");
for(int i = 0; i < MachineState.SymbolsTable->Size; i++) {
Symbol* symbol = MachineState.SymbolsTable->Symbols[i];
printf("[Resolved? %d] %s\n", symbol->Resolved, symbol->Name);
}
printf("-----SYMBOLS-----\n");
} }
void AdvanceParser(void) { void AdvanceParser(void) {
@@ -474,20 +284,15 @@ Token* PeekToken(void) {
return TokensList->content[CurrentToken]; return TokensList->content[CurrentToken];
} }
void WriteMemory(unsigned char value, int location) { void IgnoreParserLine(void) {
if (location > HIGHMEMORY) { while(!ParserAtEnd()) {
fprintf(stderr, "[Error] Exceeded memmory size\n"); if (PeekToken()->Class == PunctuationClass && PeekToken()->Value.Punctuation == NewLine) {
exit(1); AdvanceParser();
break;
}
if (PeekToken()->EndOfFile) break;
AdvanceParser();
} }
Memory[location] = value;
}
void WriteMemoryORMask(unsigned char mask, int location) {
if (location > HIGHMEMORY) {
fprintf(stderr, "[Error] Exceeded memmory size\n");
exit(1);
}
Memory[location] |= mask;
} }
+129 -26
View File
@@ -1,13 +1,16 @@
#include "../includes/scanner.h" #include "../includes/scanner.h"
#include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h>
const char* SourceCode; const char* SourceCode;
int Line = 0; int Line = 1;
int Position = 0; int Position = 0;
int SourceLength = 0; int SourceLength = 0;
int ScannerAtEnd(void); int ScannerAtEnd(void);
int IsPunctuation(char); int IsPunctuation(char);
int IsWhiteSpace(char);
char PeekScanner(void); char PeekScanner(void);
char PeekAheadScanner(void); char PeekAheadScanner(void);
void AdvanceScanner(void); void AdvanceScanner(void);
@@ -34,16 +37,35 @@ List* GenerateTokenList(const char* source) {
case ' ': case ' ':
case '\r': case '\r':
case '\t': case '\t':
case '\v':
case '\f':
AdvanceScanner(); AdvanceScanner();
break; //Ignore whitespace break; //Ignore whitespace
case '\n': case '\n':
token = CreateToken("^", NULL, Line, LineEnd); if (tokens->size > 0) {
token = tokens->content[tokens->size - 1];
if (token->Class == PunctuationClass && token->Value.Punctuation == NewLine) {
AdvanceScanner();
Line++;
continue;
}
}
token = CreateToken(Line, PunctuationClass);
token->Value.Punctuation = NewLine;
AddListItem(token, sizeof(Token), tokens); AddListItem(token, sizeof(Token), tokens);
AdvanceScanner(); AdvanceScanner();
Line++; Line++;
break; break;
case ';': case ';':
IgnoreLine(); IgnoreLine();
if (tokens->size == 0) {
//There's nothing here so that means this is some comments block at the start of the file.
AdvanceScanner(); //Consume the actual new line char.
Line++;
}
break; break;
case '.': //directive like ".org" or ".db" case '.': //directive like ".org" or ".db"
token = ParseDirective(); token = ParseDirective();
@@ -76,6 +98,21 @@ List* GenerateTokenList(const char* source) {
token = NULL; token = NULL;
} }
if (tokens->size > 0) {
token = tokens->content[tokens->size - 1];
if (token->Class == PunctuationClass && token->Value.Punctuation == NewLine) {
//If the last token is a line break, remove it as its not too meaningful.
tokens->size--;
}
}
token = CreateToken(Line, PunctuationClass);
token->EndOfFile = 1;
AddListItem(token, sizeof(Token), tokens);
return tokens; return tokens;
} }
@@ -85,9 +122,21 @@ Token* ParseNumber(void) {
while(!ScannerAtEnd() && isdigit(PeekScanner())) while(!ScannerAtEnd() && isdigit(PeekScanner()))
AdvanceScanner(); AdvanceScanner();
if (PeekScanner() == 'x' && isdigit(PeekAheadScanner())) { if (tolower(PeekScanner()) == 'x') {
AdvanceScanner(); //Consume the 'x' char ahead = tolower(PeekAheadScanner());
while(!ScannerAtEnd() && isdigit(PeekScanner())) AdvanceScanner();
if ((ahead >= 'a' && ahead <= 'f') || isdigit(ahead)) {
AdvanceScanner(); //Consume the 'x'
while(!ScannerAtEnd() && PeekScanner() != '\n' && !IsWhiteSpace(PeekScanner())) {
if (isdigit(PeekScanner())) {
AdvanceScanner();
continue;
}
if (tolower(PeekScanner()) >= 'a' && tolower(PeekScanner()) <= 'f') AdvanceScanner();
}
}
} }
int length = Position - start; int length = Position - start;
@@ -95,24 +144,26 @@ Token* ParseNumber(void) {
if (length == 0) return NULL; if (length == 0) return NULL;
char* lexeme = calloc(sizeof(char), length + 1); char* lexeme = calloc(sizeof(char), length + 1);
long* value = calloc(1, sizeof(long));
if (!lexeme) { if (!lexeme) {
fprintf(stderr, "Failed to calloc space for number. %s.\n", strerror(errno)); fprintf(stderr, "Failed to calloc space for number. %s.\n", strerror(errno));
return NULL; return NULL;
} }
if (!value) { memcpy(lexeme, &SourceCode[start], length);
free(lexeme);
fprintf(stderr, "Failed to calloc space for the raw numeric value of a token. %s.\n", strerror(errno)); Token* token = CreateToken(Line, NumberClass);
return NULL;
token->Value.Number = strtol(lexeme, NULL, 0);
if (errno != 0) {
fprintf(stderr, "[Error] Line %d: Invalid number detected. %s.\n", Line, strerror(errno));
exit(1);
} }
memcpy(lexeme, &SourceCode[start], length); token->Lemexe = lexeme;
// Setting the base to zero means the function will pick the base.
*value = strtol(lexeme, NULL, 0);
return CreateToken(lexeme, value, Line, NUMBER); return token;
} }
Token* ParseDirective(void) { Token* ParseDirective(void) {
@@ -133,12 +184,17 @@ Token* ParseDirective(void) {
memcpy(directive, &SourceCode[start], length); memcpy(directive, &SourceCode[start], length);
Token* token = CreateToken(Line, DirectiveClass);
if (strcmp(directive, ".db") == 0) { if (strcmp(directive, ".db") == 0) {
return CreateToken(directive, directive, Line, DB); token->Value.Directive = DB;
return token;
} }
else if (strcmp(directive, ".org") == 0) { else if (strcmp(directive, ".org") == 0) {
fprintf(stderr, "[Warning] Org is not a supported directive.\n"); fprintf(stderr, "[Warning] Org is not a supported directive.\n");
free(directive); free(directive);
free(token);
IgnoreLine(); IgnoreLine();
return NULL; return NULL;
} }
@@ -178,7 +234,9 @@ Token* ParseString(void) {
AdvanceScanner(); //Consume the trailing double quote. AdvanceScanner(); //Consume the trailing double quote.
Token* token = CreateToken(lexeme, lexeme, Line, STRING); Token* token = CreateToken(Line, CharacterClass);
token->Lemexe = lexeme;
return token; return token;
} }
@@ -194,7 +252,8 @@ Token* ParseIdentifier(void) {
if (length == 0) return NULL; if (length == 0) return NULL;
TokenType type; Mnemonic mnemonics;
Registers reg;
char* lexeme = calloc(sizeof(char), length + 1); char* lexeme = calloc(sizeof(char), length + 1);
if (!lexeme) { if (!lexeme) {
@@ -204,14 +263,33 @@ Token* ParseIdentifier(void) {
memcpy(lexeme, &SourceCode[start], length); memcpy(lexeme, &SourceCode[start], length);
if (IsOpcode(lexeme, &type)) return CreateToken(lexeme, lexeme, Line, type); if (IsOpcode(lexeme, &mnemonics)) {
if (IsRegister(lexeme, &type)) return CreateToken(lexeme, lexeme, Line, type); Token* token = CreateToken(Line, MnemonicClass);
token->Value.Mnemonic = mnemonics;
return token;
}
if (IsRegister(lexeme, &reg)) {
Token* token = CreateToken(Line, RegisterClass);
token->Value.Register = reg;
return token;
}
if (lexeme[length - 1] == ':') { if (lexeme[length - 1] == ':') {
lexeme[length - 1] = '\0'; //Bit hacky, but this makes the parser's job a bit easier. lexeme[length - 1] = '\0'; //Bit hacky, but this makes the parser's job a bit easier.
return CreateToken(lexeme, lexeme, Line, LABEL); Token* token = CreateToken(Line, LabelClass);
token->Lemexe = lexeme;
return token;
} }
return CreateToken(lexeme, lexeme, Line, IDENTIFIER); Token* token = CreateToken(Line, IdentifierClass);
token->Lemexe = lexeme;
return token;
} }
char PeekScanner(void) { char PeekScanner(void) {
@@ -249,19 +327,44 @@ int IsPunctuation(char c) {
} }
} }
int IsWhiteSpace(char c) {
switch(c) {
case ' ':
case '\t':
case '\v':
case '\f':
case '\r':
return 1;
default:
return 0;
}
}
Token* ParsePunctuation(char c) { Token* ParsePunctuation(char c) {
TokenPunctuation punctuation;
switch(c) { switch(c) {
case '[': case '[':
return CreateToken("[", NULL, Line, LBRACKET); punctuation = LBracket;
break;
case ']': case ']':
return CreateToken("]", NULL, Line, RBracket); punctuation = RBracket;
break;
case '(': case '(':
return CreateToken("(", NULL, Line, LPARAM); punctuation = LParan;
break;
case ')': case ')':
return CreateToken(")", NULL, Line, RPARAM); punctuation = RParan;
break;
case ',': case ',':
return CreateToken(",", NULL, Line, COMMA); punctuation = Comma;
break;
default: default:
return NULL; return NULL;
} }
Token* token = CreateToken(Line, PunctuationClass);
token->Value.Punctuation = punctuation;
return token;
} }
+109
View File
@@ -0,0 +1,109 @@
#include "../includes/symbols_table.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
SymbolTable* CreateSymbolTable(void){
SymbolTable* table = calloc(1, sizeof(SymbolTable));
if (!table) {
fprintf(stderr, "Failed to calloc memory for a SymbolTable. %s.\n", strerror(errno));
return NULL;
}
table->Symbols = calloc(SYMBOLSTABLE_DEFAULT_CAPACITY, sizeof(Symbol*));
if (!table->Symbols) {
fprintf(stderr, "Failed to calloc Symbol list. %s.\n", strerror(errno));
free(table);
return NULL;
}
table->Capacity = SYMBOLSTABLE_DEFAULT_CAPACITY;
table->Size = 0;
return table;
}
Symbol* CreateSymbol(char* name) {
Symbol* symbol = calloc(1, sizeof(Symbol));
if (!symbol) {
fprintf(stderr, "Failed to create Symbol '%s'. %s.\n", name, strerror(errno));
return NULL;
}
symbol->Name = name;
return symbol;
}
SymbolString* CreateSymbolString(char* text) {
SymbolString* string = calloc(1, sizeof(SymbolString));
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++) {
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;
for(int i = 0; i < table->Size; i++) {
if (strcmp(table->Symbols[i]->Name, name) == 0) {
//TODO: Do we update or throw some kind of an error?
return table->Symbols[i];
}
}
if (table->Capacity < table->Size + 1) {
Symbol** newBlock = realloc(table->Symbols, sizeof(Symbol*) * table->Capacity * 2);//calloc(table->Size * 2, sizeof(Symbol*));
if (!newBlock) {
fprintf(stderr, "Failed to realloc space for a new symbol '%s'. %s.\n", name, strerror(errno));
return NULL;
}
table->Capacity *= 2;
table->Symbols = newBlock;
}
Symbol* symbol = CreateSymbol(name);
table->Symbols[table->Size] = symbol;
table->Size++;
return symbol;
}
void FreeSymbolTable(SymbolTable* table) {
if (!table) return;
for(int i = 0; i < table->Size; i++) FreeSymbol(table->Symbols[i]);
free(table);
}
void FreeSymbol(Symbol* symbol) {
if (!symbol) return;
free(symbol);
}
+3 -27
View File
@@ -1,8 +1,6 @@
#include "../includes/token.h" #include "../includes/token.h"
TokenClass GetTokenClass(TokenType); Token* CreateToken(int lineNumber, TokenClass tokenClass) {
Token* CreateToken(char* lexeme, void* value, int lineNumber, TokenType type) {
Token* token = calloc(1, sizeof(Token)); Token* token = calloc(1, sizeof(Token));
if (!token) { if (!token) {
@@ -10,36 +8,14 @@ Token* CreateToken(char* lexeme, void* value, int lineNumber, TokenType type) {
return NULL; return NULL;
} }
token->type = type; token->Class = tokenClass;
token->line = lineNumber; token->LineNumber = lineNumber;
token->lexeme = lexeme;
token->value = value;
token->token_class = GetTokenClass(type);
return token; return token;
} }
TokenClass GetTokenClass(TokenType type) {
if (type >= R1 && type <= R8) return Reg;
if (type >= COPY && type <= OUT) return Opcode;
if (type >= DB && type <= ORG) return Directive;
switch(type) {
case STRING:
case IDENTIFIER:
case LABEL:
return Address;
case NUMBER:
return Constant;
default:
return None;
}
}
void FreeToken(Token* token) { void FreeToken(Token* token) {
if (!token) return; if (!token) return;
if (token->value && (token->type >= STRING || token->type == NUMBER)) free(token->value);
free(token); free(token);
} }