Compare commits
75
Commits
ae1e73e00f
...
ast
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c95d739e16 | ||
|
|
21c2bf046e | ||
|
|
b810d7803c | ||
|
|
9e178ca3da | ||
|
|
82b2136a69 | ||
|
|
4bb90da6df | ||
|
|
4af2527806 | ||
|
|
65383cded2 | ||
|
|
9c8fe17c8f | ||
|
|
3031fa8b9b | ||
|
|
2918f2964d | ||
|
|
980b0449fc | ||
|
|
6741dde7ce | ||
|
|
c6e6e2c5dc | ||
|
|
0eaa5527ea | ||
|
|
403439def4 | ||
|
|
0fd6413d81 | ||
|
|
a9e57132be | ||
|
|
aa3888b578 | ||
|
|
c3d12da54a | ||
|
|
288ba9f9cb | ||
|
|
a9a50055a4 | ||
|
|
2e888913be | ||
|
|
ee60d14570 | ||
|
|
fa12a04bb3 | ||
|
|
2d7aad1617 | ||
|
|
ae03991fa5 | ||
|
|
95ed2143ea | ||
|
|
f96e1c6380 | ||
|
|
4f9f4202b2 | ||
|
|
4230708f15 | ||
|
|
5e9e1bdec4 | ||
|
|
1b246e90bc | ||
|
|
9a602824b6 | ||
|
|
6d6bf1cbaf | ||
|
|
bca2ad67f1 | ||
|
|
fd44e03b1b | ||
|
|
48a77950be | ||
|
|
8b6edc39be | ||
|
|
c142d2c6d0 | ||
|
|
4b08707e67 | ||
|
|
bdb4d2b241 | ||
|
|
d53833c25f | ||
|
|
f38da9cc74 | ||
|
|
33309a2759 | ||
|
|
1f7989533b | ||
|
|
cd1258a724 | ||
|
|
be91e3c112 | ||
|
|
706f480e31 | ||
|
|
a949007c75 | ||
|
|
a0d5d62a34 | ||
|
|
f7cd87f13f | ||
|
|
55f4c32764 | ||
|
|
097eca383b | ||
|
|
984683bfc5 | ||
|
|
0f42ad2997 | ||
|
|
63438b551b | ||
|
|
e94e486e18 | ||
|
|
2b71ac05a0 | ||
|
|
02cf72902e | ||
|
|
afa84076c8 | ||
|
|
925f7703d6 | ||
|
|
a82a4c23ad | ||
|
|
f5c82d1c36 | ||
|
|
0b58e0124f | ||
|
|
2ae60a607c | ||
|
|
6d17dffcdf | ||
|
|
2518214585 | ||
|
|
7004fff659 | ||
|
|
13f8ff194b | ||
|
|
dac01ffd0c | ||
|
|
3c7056c5e6 | ||
|
|
6c7b8d5356 | ||
|
|
5f437b6869 | ||
|
|
e3b4293314 |
+4
-1
@@ -1,3 +1,6 @@
|
|||||||
assm
|
assm
|
||||||
obj/
|
obj/
|
||||||
bin/
|
bin/
|
||||||
|
*.bin
|
||||||
|
docs/*
|
||||||
|
!docs/*.tex
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS=-g -Wall -DDEBUG -Wpedantic
|
CFLAGS=-g -Wall -DDEBUG -Wpedantic -Wextra -Wunused-result -std=c99 -pedantic-errors
|
||||||
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 -O2
|
release: CFLAGS=-Wall -Wpedantic -std=c99 -pedantic-errors -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/test.asm
|
$(BIN) misc/another_test.asm
|
||||||
|
|
||||||
disass:
|
disass:
|
||||||
objdump -S --disassemble $(OBJDIR)/$(FILE).o > $(OBJDIR)/$(FILE).s
|
objdump -S --disassemble $(OBJDIR)/$(FILE).o > $(OBJDIR)/$(FILE).s
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
\documentclass[a4paper,12pt]{book}
|
||||||
|
\usepackage{tikz}
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\hypersetup{
|
||||||
|
linktoc=all
|
||||||
|
}
|
||||||
|
|
||||||
|
\title{Unnamed Machine}
|
||||||
|
\author{A Very Terrible 16-bit Machine}
|
||||||
|
|
||||||
|
\newcommand{\OpcodeTable}[5] {
|
||||||
|
\begin{tabular}{ c c c c c }
|
||||||
|
\hline
|
||||||
|
Opcode & Bit Pattern & Mnemonic & Operand 1 & Operand 2 \\
|
||||||
|
\hline\hline
|
||||||
|
#1 & #2 & #3 & #4 & #5 \\
|
||||||
|
\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 load–store 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}
|
||||||
|
The instruction encoding is fixed width to exactly 8 bites wide.
|
||||||
|
The encoding for the instructions will differ depending on if the opcode requires a register as its first operand.
|
||||||
|
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
|
||||||
|
\begin{figure}[!htb]
|
||||||
|
\centering
|
||||||
|
\begin{tabular}{ c c }
|
||||||
|
Instruction & Register \\
|
||||||
|
\hline
|
||||||
|
XXXX X & 000 \\
|
||||||
|
\hline
|
||||||
|
\end{tabular}
|
||||||
|
\caption{Encoding Layout, Register Required}
|
||||||
|
\label{fig:WithRegister}
|
||||||
|
\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}
|
||||||
|
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. The Stack Pointer will start 2 bytes above the video memory start.
|
||||||
|
\section{COPY (Copy Word from Address)}
|
||||||
|
\OpcodeTable{0x08}{0000 1000}{copya}{Register}{Address}\\[6pt]
|
||||||
|
Copy a machine word from Operand 2 into Operand 1.
|
||||||
|
\section{COPY BYTE (Copy Byte from Address)}
|
||||||
|
\OpcodeTable{0x10}{0001 0000}{copyab}{Register}{Address}\\[6pt]
|
||||||
|
Copy a byte (8 bits) from Operand 2 into Operand 1, clearing the setting the most significant bits to zero.
|
||||||
|
\section{COPY (Copy Word Indirect Address)}
|
||||||
|
\OpcodeTable{0x18}{0001 1000}{copyra}{Register}{[Register]}\\[6pt]
|
||||||
|
Copy a machine word from the address stored in Operand 2 into Operand 1.
|
||||||
|
\section{COPY BYTE (Copy Byte Indirect Address)}
|
||||||
|
\OpcodeTable{0x20}{0010 0000}{copyrab}{Register}{[Register]}\\[6pt]
|
||||||
|
Copy a byte (8 bits) from the address stored in Operand 2 into Operand 1.
|
||||||
|
\section{COPY (Copy)}
|
||||||
|
\OpcodeTable{0x28}{0010 1000}{copyrara}{[Register]}{[Register]}\\[6pt]
|
||||||
|
Copy a machine word from the address stored in Operand 2 into the address stored in Operand 1.
|
||||||
|
\section{COPY BYTE (Copy Byte)}
|
||||||
|
\OpcodeTable{0x30}{0011 0000}{copyrarab}{[Register]}{[Register]}\\[6pt]
|
||||||
|
Copy a byte (8 bits) from the address stored in Operand 2 into the address stored in Operand 1.
|
||||||
|
\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)}
|
||||||
|
\OpcodeTable{0x48}{0100 1000}{cmp}{Register}{Register}\\[6pt]
|
||||||
|
Compares two registers and somewhere sets a result in the status register.
|
||||||
|
\section{CMPI (Compare Immediate)}
|
||||||
|
\OpcodeTable{0x50}{0101 0000}{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{0x58}{0101 1000}{add}{Register}{Register}\\[6pt]
|
||||||
|
Performs addition on a register with a value from another (or the same) register.
|
||||||
|
\section{SUB (Subtract)}
|
||||||
|
\OpcodeTable{0x60}{0110 0000}{sub}{Register}{Register}\\[6pt]
|
||||||
|
Performs subtraction on a register with a value from another (or the same) register.
|
||||||
|
\section{AND (Logical AND)}
|
||||||
|
\OpcodeTable{0x68}{0110 1000}{and}{Register}{Register}\\[6pt]
|
||||||
|
Logical ANDs the two registers together storing the result in operand 1.
|
||||||
|
\section{XOR (Logical Exclusive OR)}
|
||||||
|
\OpcodeTable{0x70}{0111 0000}{xor}{Register}{Register}\\[6pt]
|
||||||
|
Logical XORs the two registers together storing the result in operand 1.
|
||||||
|
\section{OR (Logical OR)}
|
||||||
|
\OpcodeTable{0x78}{0111 1000}{or}{Register}{Register}\\[6pt]
|
||||||
|
Logical ORs the two registers together storing the result in operand 1.
|
||||||
|
\section{NOT (Logical Negation)}
|
||||||
|
\OpcodeTable{0x80}{1000 0000}{not}{Register}{None}\\[6pt]
|
||||||
|
Inverts the bits of the target register.
|
||||||
|
\section{SHR (Shift Right)}
|
||||||
|
\OpcodeTable{0x88}{1000 1000}{shr}{Register}{Constant}\\[6pt]
|
||||||
|
Bit-wise shifts the contents of the register right Constant number of times.
|
||||||
|
\section{SHL (Shift Left)}
|
||||||
|
\OpcodeTable{0x90}{1001 0000}{shl}{Register}{Constant}\\[6pt]
|
||||||
|
Bit-wise shifts the contents of the register left Constant number of times.
|
||||||
|
\section{INC (Increment)}
|
||||||
|
\OpcodeTable{0x98}{1001 1000}{inc}{Register}{None}\\[6pt]
|
||||||
|
Increments the contents of the register by one. Over-flows will not be reported.
|
||||||
|
\section{DEC (Decrement)}
|
||||||
|
\OpcodeTable{0xA0}{1010 0000}{dec}{Register}{None}\\[6pt]
|
||||||
|
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)}
|
||||||
|
\OpcodeTable{0x01}{0000 0001}{nop}{None}{None}\\[6pt]
|
||||||
|
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}
|
||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
void Disassemble(unsigned char image[HIGHMEMORY]);
|
//void Disassemble(unsigned char image[HIGHMEMORY]);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
#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
|
|
||||||
+15
-21
@@ -2,29 +2,23 @@
|
|||||||
#define OPCODES_H
|
#define OPCODES_H
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "token.h"
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#define OPCODECOUNT 12
|
typedef enum {
|
||||||
#define REGISTERCOUNT 8
|
R1 = 0, R2, R3, R4, R5, R6, R7, R8 = 7
|
||||||
|
} Registers;
|
||||||
|
|
||||||
typedef struct {
|
typedef enum {
|
||||||
char* lexeme;
|
COPYA = 0x08, COPYAB = 0x10, COPYRA = 0x18, COPYRAB = 0x20, COPYRARA = 0x28, COPYRARAB = 0x30, COPY = 0x38, COPYB = 0x40, COPYI = 0xC0,
|
||||||
TokenType op;
|
CMP = 0x48, CMPI = 0x50, ADD = 0x58, SUB = 0x60, AND = 0x68, XOR = 0x70, OR = 0x78, NOT = 0x80, SHR = 0x88, SHL = 0x90,
|
||||||
TokenClass parameter_one;
|
INC = 0x98, DEC = 0xA0, PUSH = 0xA8, POP = 0xB0,
|
||||||
TokenClass parameter_two;
|
JMPI = 0xB8, JMP = 0x02, JZ = 0x03, JG = 0x04, JL = 0x05, NOP = 0x01, CALL = 0x06, RET = 0x07
|
||||||
} Instruction;
|
} Mnemonic;
|
||||||
|
|
||||||
typedef struct {
|
int IsOpcode(const char*, Mnemonic*);
|
||||||
char* lexeme;
|
int IsRegister(const char*, Registers*);
|
||||||
TokenType type;
|
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]);
|
||||||
} Register;
|
void GetRegisterText(Registers reg, char buffer[3]);
|
||||||
|
|
||||||
extern Instruction instructions[OPCODECOUNT];
|
|
||||||
extern Register registers[REGISTERCOUNT];
|
|
||||||
|
|
||||||
int IsOpcode(const char*, TokenType*);
|
|
||||||
int IsRegister(const char*, TokenType*);
|
|
||||||
const Instruction* GetOpcodeDetails(TokenType);
|
|
||||||
unsigned char GetInstructionMask(TokenType type, TokenClass parameterOneType);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+5
-4
@@ -1,14 +1,15 @@
|
|||||||
#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 "list.h"
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
|
#include "symbols_table.h"
|
||||||
|
|
||||||
#define HIGHMEMORY 65535 //64KiB - 1 AKA 0xFFFF
|
void ParseTokens(TokenList* tokens, SymbolTable** symbolsTable);
|
||||||
|
|
||||||
unsigned char* ParseTokens(List*);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+1
-2
@@ -7,9 +7,8 @@
|
|||||||
#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"
|
||||||
|
|
||||||
List* GenerateTokenList(const char*);
|
TokenList* GenerateTokenList(const char*);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef SYMBOLSTABLE_H
|
||||||
|
#define SYMBOLSTABLE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "opcodes.h"
|
||||||
|
#include "token.h"
|
||||||
|
|
||||||
|
#define SYMBOLSTABLE_DEFAULT_CAPACITY 128
|
||||||
|
|
||||||
|
typedef struct __token_node {
|
||||||
|
const Token* Token;
|
||||||
|
struct __token_node* Left;
|
||||||
|
struct __token_node* Right;
|
||||||
|
} TokenNode;
|
||||||
|
|
||||||
|
typedef struct _symbol {
|
||||||
|
const char* Name;
|
||||||
|
int Address;
|
||||||
|
int Length;
|
||||||
|
const Token* Token;
|
||||||
|
TokenNode* ValueExpression;
|
||||||
|
} Symbol;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Symbol** Symbols;
|
||||||
|
int Size;
|
||||||
|
int Capacity;
|
||||||
|
} SymbolTable;
|
||||||
|
|
||||||
|
SymbolTable* CreateSymbolTable(void);
|
||||||
|
TokenNode* CreateTokenNode(const Token* token);
|
||||||
|
int TryGetSymbol(const char* name, const SymbolTable* table, Symbol** outSymbol);
|
||||||
|
Symbol* AddSymbolToTable(const char* name, int address, SymbolTable* table);
|
||||||
|
void FreeSymbolTable(SymbolTable* table);
|
||||||
|
void FreeSymbol(Symbol* symbol);
|
||||||
|
int SymbolResolved(const Symbol* symbol, const SymbolTable* table);
|
||||||
|
int TryGetSymbolValue(const Symbol* symbol, const SymbolTable* table, unsigned short* value);
|
||||||
|
|
||||||
|
#endif
|
||||||
+55
-39
@@ -5,52 +5,68 @@
|
|||||||
#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, IN, OUT,
|
|
||||||
//Registers
|
|
||||||
R1, R2, R3, R4, R5, R6, R7, R8
|
|
||||||
} TokenType;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
None = 0,
|
DB,
|
||||||
Reg = 1,
|
Include,
|
||||||
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 __token {
|
||||||
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;
|
||||||
|
unsigned short Number;
|
||||||
|
} Value;
|
||||||
|
|
||||||
|
struct __token* Prev;
|
||||||
|
struct __token* Next;
|
||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
Token* CreateToken(char*, void*, int, TokenType);
|
typedef struct {
|
||||||
void FreeToken(Token*);
|
Token** content;
|
||||||
|
int size;
|
||||||
|
int capacity;
|
||||||
|
} TokenList;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
.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
|
||||||
+26
-21
@@ -1,22 +1,27 @@
|
|||||||
;.org 0x100
|
;.include "./another_test.asm"
|
||||||
|
.db labelsz reference
|
||||||
|
.db video_start 0xF37F
|
||||||
.db msg "Hello, world!", 0
|
.db msg "Hello, world!", 0
|
||||||
;.db more_stuff "AA", 0
|
.db NOTERM "No terminating byte here"
|
||||||
copy r7, msg ; //
|
.db null_byte 0
|
||||||
cmp r8, 45 ;1000 1111
|
jmp [r4]
|
||||||
add r4, 30
|
;load r2, label
|
||||||
sub r1, 69
|
something_insance:
|
||||||
int 20
|
load r1, unknown_symbol
|
||||||
jz 45
|
load r1, 5
|
||||||
|
.db fun_alright 0x70;does this break?
|
||||||
;copy r1, 45 ;//B0 = 10110000
|
load r3, r4
|
||||||
;copy 2, 45
|
store byte r3, r5
|
||||||
;loop:
|
store r5, r7
|
||||||
; cmp r1, 0
|
unknown_symbol:;Does this work?
|
||||||
; jz loop
|
cmp r1, 5;or one after the register?
|
||||||
; add r1, 1
|
cmp r1, r2;This might work
|
||||||
;mov r1, 5 ; move the immediate value 5 into r1
|
and r1, r2
|
||||||
;add r1,5 ; add 5 into r1
|
add r4, r7
|
||||||
;int 21 ; maybe that will call some string drawing BIOS-like routine
|
inc r1 ;increment r1
|
||||||
;ret
|
xor r1, r1 ;clear self
|
||||||
; 4 byte header
|
pop r3
|
||||||
; | Address of First Opcode (2 bytes) | End of Binary (2 bytes) |
|
jmp unknown_symbol
|
||||||
|
jmp [r4]
|
||||||
|
jz [r6]
|
||||||
|
;And a comment at the end
|
||||||
+23
-11
@@ -14,31 +14,27 @@ 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];
|
||||||
int end = image[2] + image[3];
|
int end = image[2] + image[3];
|
||||||
|
|
||||||
printf("Start: %d and End: %d\n", position, end);
|
|
||||||
|
|
||||||
char* parameter1 = calloc(32, sizeof(char));
|
char* parameter1 = calloc(32, sizeof(char));
|
||||||
char* parameter2 = calloc(32, sizeof(char));
|
char* parameter2 = calloc(32, sizeof(char));
|
||||||
|
|
||||||
unsigned char instruction = image[position];
|
unsigned char instruction = image[position];
|
||||||
|
|
||||||
while(end >= position) {//(instruction != 0) {
|
while(end > position) {
|
||||||
// printf("%d\n", position);
|
|
||||||
// printf("%#04X\n", instruction);
|
|
||||||
|
|
||||||
unsigned char masked = instruction & 0xE0;
|
unsigned char masked = instruction & 0xE0;
|
||||||
|
|
||||||
if (masked) {
|
if (masked) {
|
||||||
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;
|
||||||
@@ -82,7 +78,7 @@ void Disassemble(unsigned char image[HIGHMEMORY]) {
|
|||||||
position += 3;
|
position += 3;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
printf("INT %d\n", Image[position + 1] + Image[position + 2]);
|
printf("INT %d\n", parameter);
|
||||||
position += 3;
|
position += 3;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
@@ -93,6 +89,22 @@ void Disassemble(unsigned char image[HIGHMEMORY]) {
|
|||||||
printf("RET\n");
|
printf("RET\n");
|
||||||
position++;
|
position++;
|
||||||
break;
|
break;
|
||||||
|
case 5:
|
||||||
|
printf("CALL [%#04X]\n", parameter);
|
||||||
|
position += 3;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
printf("JMP [%#04X]\n", parameter);
|
||||||
|
position += 3;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
printf("IN %d\n", parameter);
|
||||||
|
position += 3;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
printf("OUT %d\n", parameter);
|
||||||
|
position += 3;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
position++;
|
position++;
|
||||||
break;
|
break;
|
||||||
@@ -105,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';
|
||||||
|
|||||||
-66
@@ -1,66 +0,0 @@
|
|||||||
#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);
|
|
||||||
}
|
|
||||||
+228
-22
@@ -1,12 +1,20 @@
|
|||||||
|
#include <bits/types/FILE.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sysexits.h>
|
#include <sysexits.h>
|
||||||
#include "../includes/list.h"
|
#include "../includes/token.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"
|
#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) {
|
||||||
@@ -14,29 +22,227 @@ 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* list = GenerateTokenList(source_code);
|
LIST = GenerateTokenList(source_code);
|
||||||
|
|
||||||
// for(int i = 0; i < list->size; i++) {
|
ParseTokens(LIST, &Symbols);
|
||||||
// Token* t = (Token*) list->content[i];
|
|
||||||
|
|
||||||
// if (t->type == LineEnd) {
|
|
||||||
// if (i - 1 >= 0 && ((Token*) list->content[i - 1])->type != LineEnd)
|
|
||||||
// printf("\n");
|
|
||||||
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// printf("[%i] '%s' [%i] ", t->type, t->lexeme, t->token_class);
|
|
||||||
// if (t->type == LABEL) printf("* ");
|
|
||||||
// }
|
|
||||||
|
|
||||||
unsigned char* image = ParseTokens(list);
|
|
||||||
Disassemble(image);
|
|
||||||
|
|
||||||
free(source_code);
|
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];
|
||||||
|
printf("printing tokens...\n");
|
||||||
|
|
||||||
|
|
||||||
|
for(int i = 0; i < LIST->size; i++) {
|
||||||
|
Token* t = (Token*) LIST->content[i];
|
||||||
|
|
||||||
|
if (t->EndOfFile) {
|
||||||
|
printf("EOF\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->Class == PunctuationClass){
|
||||||
|
if(t->Value.Punctuation == NewLine) {
|
||||||
|
printf("<%d>\n", t->LineNumber);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("[P]%c", t->Value.Punctuation);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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("[C]'%s'", t->Lemexe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int CurrentIndex = 0;
|
||||||
|
int PC2 = 0;
|
||||||
|
|
||||||
|
void WriteByte(unsigned char byte) {
|
||||||
|
mem[PC2] = byte;
|
||||||
|
PC2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteWord(unsigned short word) {
|
||||||
|
mem[PC2] = (word >> 8) & 0xFF;
|
||||||
|
mem[PC2 + 1] = word & 0xFF;
|
||||||
|
PC2 += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short GetValueFromToken(Token* token) {
|
||||||
|
if (token->Class & IdentifierClass) {
|
||||||
|
Symbol* symbol;
|
||||||
|
|
||||||
|
if (TryGetSymbol(token->Lemexe, Symbols, &symbol)) {
|
||||||
|
return symbol->Address;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Failed to find symbol %s while assembling.\n", token->Lemexe);
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (token->Class == NumberClass) return token->Value.Number;
|
||||||
|
|
||||||
|
fprintf(stderr, "Failed to find token '%d' while assmbling.\n", token->Class);
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IsAtEnd(void){
|
||||||
|
return CurrentIndex >= LIST->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assemble() {
|
||||||
|
while(!IsAtEnd()) {
|
||||||
|
Token* current = LIST->content[CurrentIndex];
|
||||||
|
switch(current->Value.Mnemonic) {
|
||||||
|
case COPYA:
|
||||||
|
case COPYAB:
|
||||||
|
CurrentIndex++;
|
||||||
|
|
||||||
|
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
||||||
|
CurrentIndex++;
|
||||||
|
WriteWord(GetValueFromToken(LIST->content[CurrentIndex]));
|
||||||
|
break;
|
||||||
|
case COPYRA:
|
||||||
|
case COPYRAB:
|
||||||
|
case COPYRARA:
|
||||||
|
case COPYRARAB:
|
||||||
|
case COPY:
|
||||||
|
CurrentIndex++;
|
||||||
|
|
||||||
|
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
||||||
|
CurrentIndex++;
|
||||||
|
WriteByte(((Token*) LIST->content[CurrentIndex])->Value.Register);
|
||||||
|
break;
|
||||||
|
case COPYI: //TODO: should explicitly get number from value I feel
|
||||||
|
CurrentIndex++;
|
||||||
|
|
||||||
|
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
||||||
|
CurrentIndex++;
|
||||||
|
WriteWord(GetValueFromToken(LIST->content[CurrentIndex]));
|
||||||
|
break;
|
||||||
|
case COPYB:
|
||||||
|
CurrentIndex++;
|
||||||
|
|
||||||
|
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
||||||
|
CurrentIndex++;
|
||||||
|
WriteByte((unsigned char)GetValueFromToken(LIST->content[CurrentIndex]));
|
||||||
|
break;
|
||||||
|
case CMP:
|
||||||
|
CurrentIndex++;
|
||||||
|
|
||||||
|
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
||||||
|
CurrentIndex++;
|
||||||
|
WriteByte(((Token*) LIST->content[CurrentIndex])->Value.Register);
|
||||||
|
break;
|
||||||
|
case CMPI:
|
||||||
|
CurrentIndex++;
|
||||||
|
|
||||||
|
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
||||||
|
CurrentIndex++;
|
||||||
|
WriteWord(GetValueFromToken(LIST->content[CurrentIndex]));
|
||||||
|
break;
|
||||||
|
case ADD:
|
||||||
|
case SUB:
|
||||||
|
case AND:
|
||||||
|
case OR:
|
||||||
|
case XOR:
|
||||||
|
CurrentIndex++;
|
||||||
|
|
||||||
|
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
||||||
|
CurrentIndex++;
|
||||||
|
WriteByte(((Token*) LIST->content[CurrentIndex])->Value.Register);
|
||||||
|
break;
|
||||||
|
case SHL:
|
||||||
|
case SHR:
|
||||||
|
CurrentIndex++;
|
||||||
|
|
||||||
|
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
||||||
|
CurrentIndex++;
|
||||||
|
WriteWord(GetValueFromToken(LIST->content[CurrentIndex]));
|
||||||
|
break;
|
||||||
|
case INC:
|
||||||
|
case DEC:
|
||||||
|
case PUSH:
|
||||||
|
case POP:
|
||||||
|
case JMPI:
|
||||||
|
CurrentIndex++;
|
||||||
|
|
||||||
|
WriteByte(current->Value.Mnemonic | ((Token*) LIST->content[CurrentIndex])->Value.Register);
|
||||||
|
break;
|
||||||
|
case JMP:
|
||||||
|
case JZ:
|
||||||
|
case JG:
|
||||||
|
case JL:
|
||||||
|
WriteByte(current->Value.Mnemonic);
|
||||||
|
CurrentIndex++;
|
||||||
|
WriteWord(GetValueFromToken(LIST->content[CurrentIndex]));
|
||||||
|
break;
|
||||||
|
case NOP:
|
||||||
|
case RET:
|
||||||
|
WriteByte(current->Value.Mnemonic);
|
||||||
|
break;
|
||||||
|
case CALL:
|
||||||
|
WriteByte(current->Value.Mnemonic);
|
||||||
|
CurrentIndex++;
|
||||||
|
WriteWord(GetValueFromToken(LIST->content[CurrentIndex]));
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+72
-98
@@ -1,107 +1,76 @@
|
|||||||
#include "../includes/opcodes.h"
|
#include "../includes/opcodes.h"
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
Instruction instructions[OPCODECOUNT] = {
|
#define OPCODECOUNT 34
|
||||||
{ "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},
|
|
||||||
{ "jz", JZ, Address, None}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char GetInstructionMask(TokenType type, TokenClass parameterOneType) {
|
struct _instruction instructions[31] = {
|
||||||
switch (type) {
|
{ "copya", COPYA },
|
||||||
case COPY:
|
{ "copyab", COPYAB },
|
||||||
if (parameterOneType & Reg) return 0x20; //0b00100000;
|
{ "copyra", COPYRA },
|
||||||
|
{ "copyrab", COPYRAB },
|
||||||
return 0xA0;//0b10100000;
|
{ "copyrara", COPYRARA },
|
||||||
case ADD:
|
{ "copyrarab", COPYRARAB },
|
||||||
return 0x40;//0b01000000;
|
{ "copy", COPY },
|
||||||
case SUB:
|
{ "copyi", COPYI },
|
||||||
return 0x60;//0b01100000;
|
{ "copyb", COPYB },
|
||||||
case CMP:
|
{ "cmp", CMP },
|
||||||
return 0x80;//0b10000000;
|
{ "cmpi", CMPI },
|
||||||
case JZ:
|
{ "add", ADD },
|
||||||
return 0x01;//0b00000001;
|
{ "sub", SUB },
|
||||||
case INT:
|
{ "and", AND },
|
||||||
return 0x02; //0b00000010;
|
{ "xor", XOR },
|
||||||
case JMP:
|
{ "or", OR },
|
||||||
return 0x06;//0b00000110;
|
{ "not", NOT },
|
||||||
case IN:
|
{ "shr", SHR },
|
||||||
return 0x07;//0b00000111;
|
{ "shl", SHL },
|
||||||
case OUT:
|
{ "inc", INC },
|
||||||
return 0x08;//0b00001000;
|
{ "dec", DEC },
|
||||||
default:
|
{ "push", PUSH },
|
||||||
return 0x00;
|
{ "pop", POP },
|
||||||
}
|
{ "jmpi", JMPI },
|
||||||
}
|
{ "jmp", JMP },
|
||||||
|
{ "jz", JZ },
|
||||||
/*
|
{ "jg", JG },
|
||||||
NOP - 0000 0000 NOP
|
{ "jl", JL },
|
||||||
JZ - 0000 0001 JZ Address
|
{ "nop", NOP },
|
||||||
INT - 0000 0010 INT Constant
|
{ "call", CALL },
|
||||||
YLD - 0000 0011 YLD
|
{ "ret", RET }
|
||||||
RET - 0000 0100 RET
|
//yld
|
||||||
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)
|
|
||||||
|
|
||||||
Register registers[REGISTERCOUNT] = {
|
|
||||||
{ "r1", R1 },
|
|
||||||
{ "r2", R2 },
|
|
||||||
{ "r3", R3 },
|
|
||||||
{ "r4", R4 },
|
|
||||||
{ "r5", R5 },
|
|
||||||
{ "r6", R6 },
|
|
||||||
{ "r7", R7 },
|
|
||||||
{ "r8", R8 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Instruction* GetOpcodeDetails(TokenType type) {
|
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]) {
|
||||||
|
memset(buffer, '\0', 12);
|
||||||
|
|
||||||
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].Mnemonic == mnemonic) {
|
||||||
|
strncpy(buffer, instructions[i].Name, 11);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int IsOpcode(const char* text, TokenType* opcode) {
|
void GetRegisterText(Registers reg, char buffer[3]) {
|
||||||
|
memset(buffer, '\0', 3);
|
||||||
|
|
||||||
|
if (reg < R1 || reg > R8) return;
|
||||||
|
|
||||||
|
buffer[0] = 'r';
|
||||||
|
buffer[1] = reg + 49;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IsOpcode(const char* text, Mnemonic* opcode) {
|
||||||
if (!text) return 0;
|
if (!text) return 0;
|
||||||
|
|
||||||
for(int i = 0; i < OPCODECOUNT; i++) {
|
for(unsigned long i = 0; i < sizeof(instructions) / sizeof(struct _instruction); 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,15 +78,20 @@ 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;
|
||||||
|
|
||||||
|
if (!isdigit(text[1])) return 0;
|
||||||
|
|
||||||
|
r = text[1] - 0x31;
|
||||||
|
|
||||||
|
if (reg) *reg = r;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
+508
-306
@@ -1,376 +1,507 @@
|
|||||||
#include "../includes/parser.h"
|
#include "../includes/parser.h"
|
||||||
#include <string.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef enum {
|
||||||
Token* token;
|
NoOptions = 0, ForwardParser = 1, RemoveExpected = 2
|
||||||
int address;
|
} ExpectOptions;
|
||||||
} Symbol;
|
|
||||||
|
|
||||||
struct intr {
|
TokenList* TokensList;
|
||||||
TokenType struction;
|
|
||||||
unsigned int parameter1;
|
|
||||||
unsigned int parameter2;
|
|
||||||
};
|
|
||||||
|
|
||||||
Symbol* CreateSymbol(Token* token, int address);
|
|
||||||
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);
|
void RemoveCurrentToken(void);
|
||||||
void HandleAssemblerDirective(void);
|
void HandleAssemblerDirective(void);
|
||||||
|
Token* ExpectMnemonic(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, ...);
|
|
||||||
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) {
|
void ExpectPuncuation(TokenPunctuation punctuation, ExpectOptions options);
|
||||||
if (!tokens) return NULL;
|
void ExpectRegister(void);
|
||||||
|
Symbol* ExpectIdentifier(ExpectOptions options, int expectUnresolved);
|
||||||
|
void ExpectCharacterClass(Symbol* symbol);
|
||||||
|
Token* ExpectLineEndOrFileEnd(ExpectOptions options);
|
||||||
|
Token* ExpectMathOperator(ExpectOptions options);
|
||||||
|
Token* ExpectMathOperand(ExpectOptions options);
|
||||||
|
|
||||||
memset(Memory, 0, sizeof(Memory));
|
SymbolTable* SymbolsTable;
|
||||||
memset(Heap, 0, sizeof(Heap));
|
TokenNode* ParseSymbolExpression(void);
|
||||||
|
|
||||||
|
//int HeapSize = 0;
|
||||||
|
int PC = 0;
|
||||||
|
|
||||||
|
void ParseTokens(TokenList* tokens, SymbolTable** symbols) {
|
||||||
|
if (!tokens) return;
|
||||||
|
if (!symbols) return;
|
||||||
|
|
||||||
TokensList = tokens;
|
TokensList = tokens;
|
||||||
|
|
||||||
SymbolsTable = CreateList();
|
if (!*symbols) *symbols = CreateSymbolTable();
|
||||||
|
|
||||||
|
SymbolsTable = *symbols;
|
||||||
|
|
||||||
while(!ParserAtEnd()) {
|
while(!ParserAtEnd()) {
|
||||||
Token* t = PeekToken();
|
Token* t = PeekToken();
|
||||||
|
if (!t || t->EndOfFile) break;
|
||||||
|
|
||||||
switch(t->token_class) {
|
switch(t->Class) {
|
||||||
case Directive:
|
case DirectiveClass:
|
||||||
HandleAssemblerDirective();
|
HandleAssemblerDirective();
|
||||||
break;
|
break;
|
||||||
case Opcode:
|
case MnemonicClass:
|
||||||
HandleOperation();
|
ExpectMnemonic();
|
||||||
break;
|
break;
|
||||||
case Address:
|
case LabelClass:
|
||||||
if (t->type == LABEL) {
|
{
|
||||||
printf("%s: \n", t->lexeme);
|
Symbol* symbol;
|
||||||
AddSymbol(t, ProgramCounter);
|
int found = TryGetSymbol(t->Lemexe, SymbolsTable, &symbol);
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
AdvanceParser();
|
if (found && SymbolResolved(symbol, SymbolsTable)) {
|
||||||
}
|
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.
|
if (!found) symbol = AddSymbolToTable(t->Lemexe, PC, SymbolsTable);
|
||||||
//Memory[ProgramCounter] = '\0';
|
|
||||||
Heap[HeapTop] = '\0';
|
symbol->Address = PC;
|
||||||
//ProgramCounter++;
|
|
||||||
HeapTop++;
|
RemoveCurrentToken(); //label
|
||||||
return;
|
|
||||||
}
|
ExpectLineEndOrFileEnd(RemoveExpected);
|
||||||
|
|
||||||
|
symbol->Token = ExpectMnemonic();
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrintSymbols();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleRegisterBasedOpcode(unsigned char instruction, unsigned char mask) {
|
void HandleAssemblerDirective() {
|
||||||
Memory[ProgramCounter] = mask;
|
Token* directive = PeekToken();
|
||||||
|
|
||||||
ProgramCounter++;
|
switch(directive->Value.Directive){
|
||||||
|
case DB:
|
||||||
|
{
|
||||||
|
RemoveCurrentToken();
|
||||||
|
|
||||||
const Token* token = PeekToken();
|
Symbol* symbol = ExpectIdentifier(RemoveExpected, 1);
|
||||||
|
|
||||||
if (token->token_class == Reg) {
|
if (PeekToken()->Class == CharacterClass) {
|
||||||
Memory[ProgramCounter - 1] |= (PeekToken()->type - R1) & 0x07;
|
ExpectCharacterClass(symbol);
|
||||||
|
}
|
||||||
AdvanceParser();
|
else if (PeekToken()->Class == NumberClass || PeekToken()->Class == IdentifierClass) {
|
||||||
}
|
symbol->Length = 2;
|
||||||
else {
|
|
||||||
fprintf(stderr, "[Error] Line %d: Expected register operand.\n", token->line);
|
symbol->ValueExpression = ParseSymbolExpression();
|
||||||
exit(1);
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
token = PeekToken();
|
default:
|
||||||
|
fprintf(stderr, "Synatx error on line %d, %s.\n", directive->LineNumber, directive->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);
|
exit(1);
|
||||||
}
|
|
||||||
|
|
||||||
Memory[ProgramCounter - 1] |= 0x10;//0b00010000;
|
|
||||||
|
|
||||||
Memory[ProgramCounter] = 2 >> symbol->address & 0xFF;
|
|
||||||
Memory[ProgramCounter + 1] = symbol->address & 0xFF;
|
|
||||||
|
|
||||||
ProgramCounter += 2;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
ProgramCounter += 2;
|
|
||||||
|
|
||||||
AdvanceParser();
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "[Error] Expected operand, got %s\n", token->lexeme);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleOperation(void) {
|
Token* ExpectMnemonic(void) {
|
||||||
const Instruction* inst = GetOpcodeDetails(PeekToken()->type);
|
Token* opcode = PeekToken();
|
||||||
const unsigned char registerBasedOpcodeMask = 0xE0;
|
|
||||||
|
|
||||||
if (!inst) return;
|
if (opcode->Class != MnemonicClass) {
|
||||||
|
fprintf(stderr, "Syntax error on line %d: expected mnemonic.\n", opcode->LineNumber);
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
AdvanceParser();
|
AdvanceParser();
|
||||||
|
|
||||||
//Memory[ProgramCounter] = GetInstructionMask(inst->op, inst->parameter_one);
|
switch(opcode->Value.Mnemonic) {
|
||||||
unsigned char mask = GetInstructionMask(inst->op, inst->parameter_one);
|
case COPY:
|
||||||
|
{
|
||||||
|
Token* arg = PeekToken();
|
||||||
|
int isByte = 0;
|
||||||
|
|
||||||
if (mask & registerBasedOpcodeMask) {
|
if (arg->Class == DirectiveClass) {
|
||||||
HandleRegisterBasedOpcode(Memory[ProgramCounter], mask);
|
if (arg->Value.Directive != Byte) {
|
||||||
return;
|
fprintf(stderr, "Syntax error on line %d: expected keyword 'byte'.\n", opcode->LineNumber);
|
||||||
}
|
|
||||||
|
|
||||||
switch (mask) {
|
exit(1);
|
||||||
case 0: //NOP
|
}
|
||||||
Memory[ProgramCounter] = 0x00;
|
RemoveCurrentToken(); //byte
|
||||||
ProgramCounter++;
|
|
||||||
return;
|
isByte = 1;
|
||||||
case 1: //JZ
|
|
||||||
Memory[ProgramCounter] = 0x01;
|
|
||||||
|
|
||||||
ProgramCounter++;
|
arg = PeekToken();
|
||||||
|
}
|
||||||
|
|
||||||
if (PeekToken()->type == IDENTIFIER || PeekToken()->type == LABEL) {
|
PC++;
|
||||||
const Symbol* symbol = GetSymbol(PeekToken()->lexeme);
|
|
||||||
|
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);
|
||||||
|
|
||||||
if (!symbol) {
|
|
||||||
fprintf(stderr, "[Error] %s is undefined.\n", PeekToken()->lexeme);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory[ProgramCounter] = 2 >> symbol->address & 0xFF;
|
ExpectIdentifier(ForwardParser, 0);
|
||||||
Memory[ProgramCounter + 1] = symbol->address & 0xFF;
|
|
||||||
|
PC += 2;
|
||||||
}
|
}
|
||||||
else if (PeekToken()->type == NUMBER) {
|
break;
|
||||||
int* value = PeekToken()->value;
|
default:
|
||||||
|
break;
|
||||||
Memory[ProgramCounter] = 2 >> *value & 0xFF;
|
|
||||||
Memory[ProgramCounter + 1] = *value & 0xFF;
|
|
||||||
|
|
||||||
ProgramCounter += 2;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
|
|
||||||
ProgramCounter += 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "[Error] Line %d: Expected Interrupt vector.\n", PeekToken()->line);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
ExpectLineEndOrFileEnd(ForwardParser);
|
||||||
|
|
||||||
|
return opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExpectTokenClass(int count, ...) {
|
void ExpectPuncuation(TokenPunctuation punctuation, ExpectOptions options) {
|
||||||
va_list list;
|
|
||||||
Token* token = PeekToken();
|
Token* token = PeekToken();
|
||||||
|
|
||||||
va_start(list, count);
|
if (token->Class != PunctuationClass || token->Value.Punctuation != punctuation) {
|
||||||
|
fprintf(stderr, "[Line %d] Syntac error, expected %c.\n", token->LineNumber, punctuation);
|
||||||
for(int i = 0; i < count; i++) {
|
exit(1);
|
||||||
if (va_arg(list, TokenClass) == token->token_class) {
|
|
||||||
va_end(list);
|
|
||||||
AdvanceParser();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end(list);
|
if (options & RemoveExpected) RemoveCurrentToken();
|
||||||
|
if (options & ForwardParser) AdvanceParser();
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Expect(int count, ...) {
|
void ExpectRegister() {
|
||||||
va_list list;
|
|
||||||
Token* token = PeekToken();
|
Token* token = PeekToken();
|
||||||
|
|
||||||
va_start(list, count);
|
if (token->Class != RegisterClass) {
|
||||||
|
fprintf(stderr, "[Line %d] Syntax error, expected Register.\n", token->LineNumber);
|
||||||
for(int i = 0; i < count; i++) {
|
exit(2);
|
||||||
if (va_arg(list, TokenType) == token->type) {
|
|
||||||
va_end(list);
|
|
||||||
AdvanceParser();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end(list);
|
AdvanceParser();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
Symbol* ExpectIdentifier(ExpectOptions options, int expectUnresolved) {
|
||||||
|
Token* token = PeekToken();
|
||||||
|
|
||||||
|
if (token->Class != IdentifierClass) {
|
||||||
|
fprintf(stderr, "[Line %d] Expected Identifier.\n", token->LineNumber);
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol* symbol;
|
||||||
|
|
||||||
|
int found = TryGetSymbol(token->Lemexe, SymbolsTable, &symbol);
|
||||||
|
|
||||||
|
if (found && TryGetSymbolValue(symbol, SymbolsTable, NULL) && expectUnresolved) {
|
||||||
|
fprintf(stderr, "[Line %d] Redefinition of symbol '%s'.\n", token->LineNumber, token->Lemexe);
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) symbol = AddSymbolToTable(token->Lemexe, PC, SymbolsTable);
|
||||||
|
if (expectUnresolved) symbol->Token = token;
|
||||||
|
|
||||||
|
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);
|
||||||
|
symbol->Token = token;
|
||||||
|
|
||||||
|
RemoveCurrentToken(); //Remove the string declared by this DB command.
|
||||||
|
|
||||||
|
token = PeekToken();
|
||||||
|
|
||||||
|
if (token->EndOfFile) return;
|
||||||
|
|
||||||
|
if (token->Class == PunctuationClass && token->Value.Punctuation == NewLine) {
|
||||||
|
RemoveCurrentToken();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpectPuncuation(Comma, RemoveExpected);
|
||||||
|
|
||||||
|
token = PeekToken();
|
||||||
|
|
||||||
|
if (token->Class != NumberClass) {
|
||||||
|
fprintf(stderr, "[Line %d] Syntax error, expected terminating byte.\n", token->LineNumber);
|
||||||
|
exit(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveCurrentToken(); //Remove terminating byte.
|
||||||
|
//TODO: add the raw value of the byte to the end of the string, but for now just pretend all numbers are zero.
|
||||||
|
symbol->Length++;
|
||||||
|
|
||||||
|
ExpectLineEndOrFileEnd(RemoveExpected);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* ExpectLineEndOrFileEnd(ExpectOptions options) {
|
||||||
|
Token* token = PeekToken();
|
||||||
|
|
||||||
|
if (token->EndOfFile) return token;
|
||||||
|
|
||||||
|
if (token->Class != PunctuationClass || token->Value.Punctuation != NewLine) {
|
||||||
|
fprintf(stderr, "[Line %d] Syntax error, expected line break.\n", token->LineNumber);
|
||||||
|
exit(9);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options & RemoveExpected) RemoveCurrentToken();
|
||||||
|
if (options & ForwardParser) AdvanceParser();
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 < SymbolsTable->Size; i++) {
|
||||||
Symbol* symbol = SymbolsTable->content[i];
|
Symbol* symbol = SymbolsTable->Symbols[i];
|
||||||
printf("[%#06X] %s\n", symbol->address, symbol->token->lexeme);
|
unsigned short value = 0;
|
||||||
|
int resolved = SymbolResolved(symbol, SymbolsTable);
|
||||||
|
|
||||||
|
if (resolved) TryGetSymbolValue(symbol, SymbolsTable, &value);
|
||||||
|
|
||||||
|
printf("[%s] %s [Value: %d]", resolved == 0 ? "Unresolved" : "Resolved", symbol->Name, value);
|
||||||
|
|
||||||
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Symbol* CreateSymbol(Token* token, int address) {
|
|
||||||
Symbol* symbol = calloc(1, sizeof(Symbol));
|
|
||||||
|
|
||||||
if (!symbol) return NULL;
|
|
||||||
|
|
||||||
symbol->token = token;
|
|
||||||
symbol->address = address;
|
|
||||||
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvanceParser(void) {
|
void AdvanceParser(void) {
|
||||||
if (ParserAtEnd()) return;
|
if (ParserAtEnd()) return;
|
||||||
|
|
||||||
@@ -387,20 +518,91 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
Memory[location] = value;
|
if (PeekToken()->EndOfFile) break;
|
||||||
|
|
||||||
|
AdvanceParser();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteMemoryORMask(unsigned char mask, int location) {
|
void RemoveCurrentToken(void) {
|
||||||
if (location > HIGHMEMORY) {
|
RemoveToken(CurrentToken, TokensList);
|
||||||
fprintf(stderr, "[Error] Exceeded memmory size\n");
|
}
|
||||||
exit(1);
|
|
||||||
|
TokenNode* ParseSymbolExpression(void) {
|
||||||
|
TokenNode* root = CreateTokenNode(ExpectMathOperand(RemoveExpected));
|
||||||
|
|
||||||
|
while(!ParserAtEnd()) {
|
||||||
|
if (PeekToken()->Class == PunctuationClass && PeekToken()->Value.Punctuation == NewLine) {
|
||||||
|
|
||||||
|
ExpectPuncuation(NewLine, RemoveExpected);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenNode* value = CreateTokenNode(ExpectMathOperand(RemoveExpected));
|
||||||
|
TokenNode* operation = CreateTokenNode(ExpectMathOperator(RemoveExpected));
|
||||||
|
|
||||||
|
operation->Left = root;
|
||||||
|
operation->Right = value;
|
||||||
|
root = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* ExpectMathOperator(ExpectOptions options) {
|
||||||
|
if (ParserAtEnd()) {
|
||||||
|
fprintf(stderr, "Syntax error, expected math operator but found unexpected end of file.\n");
|
||||||
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory[location] |= mask;
|
Token* current = PeekToken();
|
||||||
|
|
||||||
|
if (current->Class != PunctuationClass) {
|
||||||
|
fprintf(stderr, "[Line %d] Syntax error, expected math operator.\n", current->LineNumber);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (current->Value.Punctuation) {
|
||||||
|
case Plus:
|
||||||
|
case Minus:
|
||||||
|
case Star:
|
||||||
|
case Slash:
|
||||||
|
case Power:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "[Line %d] Syntax error, expected math operator 2.\n", current->LineNumber);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options & RemoveExpected) RemoveCurrentToken();
|
||||||
|
if (options & ForwardParser) AdvanceParser();
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* ExpectMathOperand(ExpectOptions options) {
|
||||||
|
if (ParserAtEnd()) {
|
||||||
|
fprintf(stderr, "Syntax error, expected math operand but found unexpected end of file.\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* token = PeekToken();
|
||||||
|
|
||||||
|
if (token->Class != NumberClass && token->Class != IdentifierClass) {
|
||||||
|
fprintf(stderr, "[Line %d] Syntax error, expected a number or identifier.\n", token->LineNumber);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options & RemoveExpected) RemoveCurrentToken();
|
||||||
|
if (options & ForwardParser) AdvanceParser();
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
+167
-41
@@ -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);
|
||||||
@@ -18,8 +21,8 @@ Token* ParseNumber(void);
|
|||||||
Token* ParsePunctuation(char);
|
Token* ParsePunctuation(char);
|
||||||
void IgnoreLine(void);
|
void IgnoreLine(void);
|
||||||
|
|
||||||
List* GenerateTokenList(const char* source) {
|
TokenList* GenerateTokenList(const char* source) {
|
||||||
List* tokens = CreateList();
|
TokenList* tokens = CreateTokenList();
|
||||||
Token* token = NULL;
|
Token* token = NULL;
|
||||||
|
|
||||||
if (!tokens) return NULL;
|
if (!tokens) return NULL;
|
||||||
@@ -34,41 +37,60 @@ 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) {
|
||||||
AddListItem(token, sizeof(Token), tokens);
|
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;
|
||||||
|
AddToken(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 ".include" or ".db"
|
||||||
token = ParseDirective();
|
token = ParseDirective();
|
||||||
if (token) AddListItem(token, sizeof(Token), tokens);
|
if (token) AddToken(token, tokens);
|
||||||
break;
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
token = ParseString();
|
token = ParseString();
|
||||||
if (token) AddListItem(token, sizeof(Token), tokens);
|
if (token) AddToken(token, tokens);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (isdigit(c)) {
|
if (isdigit(c)) {
|
||||||
AddListItem(ParseNumber(), sizeof(Token), tokens);
|
AddToken(ParseNumber(), tokens);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsPunctuation(c)) {
|
if (IsPunctuation(c)) {
|
||||||
AdvanceScanner();
|
AdvanceScanner();
|
||||||
AddListItem(ParsePunctuation(c), sizeof(Token), tokens);
|
AddToken(ParsePunctuation(c), tokens);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
token = ParseIdentifier();
|
token = ParseIdentifier();
|
||||||
|
|
||||||
if (token) AddListItem(token, sizeof(Token), tokens);
|
if (token) AddToken(token, tokens);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
AddToken(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()) && 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,19 +184,23 @@ 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, ".include") == 0) {
|
||||||
fprintf(stderr, "[Warning] Org is not a supported directive.\n");
|
token->Value.Directive = Include;
|
||||||
free(directive);
|
|
||||||
IgnoreLine();
|
return token;
|
||||||
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();
|
||||||
|
|
||||||
@@ -178,7 +233,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;
|
||||||
}
|
}
|
||||||
@@ -186,7 +243,7 @@ Token* ParseString(void) {
|
|||||||
Token* ParseIdentifier(void) {
|
Token* ParseIdentifier(void) {
|
||||||
int start = Position;
|
int start = Position;
|
||||||
|
|
||||||
while(!ScannerAtEnd() && !IsPunctuation(PeekScanner()) && PeekScanner() != ' ' && PeekScanner() != '\n') {
|
while(!ScannerAtEnd() && !IsPunctuation(PeekScanner()) && PeekScanner() != ' ' && PeekScanner() != '\n' && PeekScanner() != ';') {
|
||||||
AdvanceScanner();
|
AdvanceScanner();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +251,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 +262,41 @@ 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, ®)) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (strcmp(lexeme, "byte") == 0) {
|
||||||
|
Token* token = CreateToken(Line, DirectiveClass);
|
||||||
|
|
||||||
|
token->Lemexe = lexeme;
|
||||||
|
token->Value.Directive = Byte;
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateToken(lexeme, lexeme, Line, IDENTIFIER);
|
Token* token = CreateToken(Line, IdentifierClass);
|
||||||
|
|
||||||
|
token->Lemexe = lexeme;
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
char PeekScanner(void) {
|
char PeekScanner(void) {
|
||||||
@@ -243,6 +328,23 @@ int IsPunctuation(char c) {
|
|||||||
case '(':
|
case '(':
|
||||||
case ')':
|
case ')':
|
||||||
case ',':
|
case ',':
|
||||||
|
case '-':
|
||||||
|
case '+':
|
||||||
|
case '*':
|
||||||
|
case '/':
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int IsWhiteSpace(char c) {
|
||||||
|
switch(c) {
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\v':
|
||||||
|
case '\f':
|
||||||
|
case '\r':
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -250,18 +352,42 @@ int IsPunctuation(char c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
case '-':
|
||||||
|
punctuation = Minus;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
punctuation = Plus;
|
||||||
|
break;
|
||||||
|
case '*':
|
||||||
|
punctuation = Star;
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
punctuation = Slash;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Token* token = CreateToken(Line, PunctuationClass);
|
||||||
|
token->Value.Punctuation = punctuation;
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
#include "../includes/symbols_table.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int SymbolResolved(const Symbol* symbol, const SymbolTable* table) {
|
||||||
|
if (!symbol) return 0;
|
||||||
|
|
||||||
|
const Token* token = symbol->Token;
|
||||||
|
|
||||||
|
if (!token) return 0;
|
||||||
|
|
||||||
|
if (token->Class == LabelClass || token->Class == CharacterClass || token->Class == MnemonicClass) return 1;
|
||||||
|
|
||||||
|
return TryGetSymbolValue(symbol, table, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(const char* name, int address) {
|
||||||
|
Symbol* symbol = calloc(1, sizeof(Symbol));
|
||||||
|
|
||||||
|
if (!symbol) {
|
||||||
|
fprintf(stderr, "Failed to create Symbol '%s'. %s.\n", name, strerror(errno));
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol->Address = address;
|
||||||
|
symbol->Name = name;
|
||||||
|
//symbol->Type = RefUnknown;
|
||||||
|
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TryGetSymbol(const char* name, const SymbolTable* table, Symbol** outSymbol) {
|
||||||
|
*outSymbol = NULL;
|
||||||
|
|
||||||
|
if (!name || !table) return 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < table->Size; i++) {
|
||||||
|
if (strcmp(table->Symbols[i]->Name, name) == 0) {
|
||||||
|
*outSymbol = table->Symbols[i];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol* AddSymbolToTable(const char* name, int address, 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);
|
||||||
|
|
||||||
|
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, address);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int TryGetTokenNodeValue(const TokenNode* node, const SymbolTable* table, unsigned short* value);
|
||||||
|
unsigned short DoOp(unsigned short left, unsigned short right, TokenPunctuation op);
|
||||||
|
|
||||||
|
int TryGetSymbolValue(const Symbol* symbol, const SymbolTable* table, unsigned short* value) {
|
||||||
|
if (!symbol || !symbol->Token || !table) return 0;
|
||||||
|
|
||||||
|
TokenNode* root = symbol->ValueExpression;
|
||||||
|
Symbol* s = NULL;
|
||||||
|
if (value) *value = 0;
|
||||||
|
|
||||||
|
if (!root || !root->Token) return 0;
|
||||||
|
|
||||||
|
switch (root->Token->Class) {
|
||||||
|
case NumberClass:
|
||||||
|
if (value) *value = root->Token->Value.Number;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
case IdentifierClass:
|
||||||
|
if (!TryGetSymbol(root->Token->Lemexe, table, &s)) return 0;
|
||||||
|
|
||||||
|
return TryGetTokenNodeValue(s->ValueExpression, table, value);
|
||||||
|
case PunctuationClass:
|
||||||
|
return TryGetTokenNodeValue(root, table, value);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int TryGetTokenNodeValue(const TokenNode* node, const SymbolTable* table, unsigned short* value) {
|
||||||
|
const Token* token = node->Token;
|
||||||
|
Symbol* symbol = { 0 };
|
||||||
|
|
||||||
|
if (token->Class == NumberClass) {
|
||||||
|
if (value) *value = token->Value.Number;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token->Class == IdentifierClass) {
|
||||||
|
if (!TryGetSymbol(token->Lemexe, table, &symbol)) return 0;
|
||||||
|
|
||||||
|
return TryGetTokenNodeValue(symbol->ValueExpression, table, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token->Class != PunctuationClass) return 0;
|
||||||
|
|
||||||
|
unsigned short left = 0;
|
||||||
|
unsigned short right = 0;
|
||||||
|
|
||||||
|
if (!TryGetTokenNodeValue(node->Left, table, &left)) return 0;
|
||||||
|
if (!TryGetTokenNodeValue(node->Right, table, &right)) return 0;
|
||||||
|
|
||||||
|
if (value) *value = DoOp(left, right, token->Value.Punctuation);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenNode* CreateTokenNode(const Token* token){
|
||||||
|
TokenNode* node = calloc(1, sizeof(TokenNode));
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
fprintf(stderr, "Failed to calloc memory for a TokenNode. %s.\n", strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->Token = token;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned short DoOp(unsigned short left, unsigned short right, TokenPunctuation op) {
|
||||||
|
switch (op) {
|
||||||
|
case Plus:
|
||||||
|
return left + right;
|
||||||
|
case Minus:
|
||||||
|
return left - right;
|
||||||
|
case Star:
|
||||||
|
return left * right;
|
||||||
|
case Slash:
|
||||||
|
return left / right;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+67
-26
@@ -1,8 +1,8 @@
|
|||||||
#include "../includes/token.h"
|
#include "../includes/token.h"
|
||||||
|
|
||||||
TokenClass GetTokenClass(TokenType);
|
#define LISTDEFAULTSIZE 32
|
||||||
|
|
||||||
Token* CreateToken(char* lexeme, void* value, int lineNumber, TokenType type) {
|
Token* CreateToken(int lineNumber, TokenClass tokenClass) {
|
||||||
Token* token = calloc(1, sizeof(Token));
|
Token* token = calloc(1, sizeof(Token));
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@@ -10,36 +10,77 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user