Compare commits
57
Commits
fbef044905
..
parser
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
307519a2b1 | ||
|
|
d3d2b06dbd | ||
|
|
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 | ||
|
|
ae1e73e00f | ||
|
|
7385a807a5 | ||
|
|
0d3f8a460e | ||
|
|
c2111e2b88 | ||
|
|
8e9d1aefe8 | ||
|
|
0785f21805 | ||
|
|
e4a191a17e | ||
|
|
eb5e2c506e | ||
|
|
0d060248cb | ||
|
|
80bea6f1a8 | ||
|
|
a96f485da6 | ||
|
|
88d550f344 | ||
|
|
0e53f9798f | ||
|
|
03d5660677 | ||
|
|
4f6d5f652e | ||
|
|
64326937b1 | ||
|
|
89ab951c6a | ||
|
|
947de1d14c | ||
|
|
3c4cce0883 | ||
|
|
5265666178 | ||
|
|
2de3538d80 | ||
|
|
72525959f6 | ||
|
|
72abf6c4ab |
+4
-1
@@ -1,3 +1,6 @@
|
|||||||
assm
|
assm
|
||||||
obj/
|
obj/
|
||||||
bin/
|
bin/
|
||||||
|
*.bin
|
||||||
|
docs/*
|
||||||
|
!docs/*.tex
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
\documentclass[a4paper,12pt]{book}
|
||||||
|
\usepackage{tikz}
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\hypersetup{
|
||||||
|
linktoc=all
|
||||||
|
}
|
||||||
|
|
||||||
|
\title{Unnamed Machine}
|
||||||
|
\author{A Very Terrible 16-bit Machine}
|
||||||
|
|
||||||
|
\newcommand{\OpcodeTable}[4] {
|
||||||
|
\begin{tabular}{ c c c c }
|
||||||
|
\hline
|
||||||
|
Opcode & Mnemonic & Operand 1 & Operand 2 \\
|
||||||
|
\hline\hline
|
||||||
|
#1 & #2 & #3 & #4 \\
|
||||||
|
\hline
|
||||||
|
\end{tabular}
|
||||||
|
}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
\maketitle
|
||||||
|
\tableofcontents
|
||||||
|
\chapter{Overview}
|
||||||
|
\section{Introduction}
|
||||||
|
This is a very poorly thought out 16-bit machine, but you've got to start somewhere. Currently debating between a CPU status register, 80x86 style, or just placing arithmetic results into a predetermined register. This is more of a 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}
|
||||||
|
Instructions are fixed to exactly one byte (8 bits).
|
||||||
|
Instructions that work with two operands the register for operand one will be encoded in the three least significant bits. So an instruction with format XXXX X000 will use Register 1 and so forth all the way to XXXX X111, which will be Register 8.
|
||||||
|
%https://tex.stackexchange.com/questions/32598/force-latex-image-to-appear-in-the-section-in-which-its-declared
|
||||||
|
\begin{figure}[!htb]
|
||||||
|
\centering
|
||||||
|
\begin{tabular}{ c c }
|
||||||
|
\hline
|
||||||
|
Instruction & Register \\
|
||||||
|
\hline\hline
|
||||||
|
0000 0 & 000 \\
|
||||||
|
\hline
|
||||||
|
\end{tabular}
|
||||||
|
\caption{Encoding Layout}
|
||||||
|
\end{figure}
|
||||||
|
\section{Notes}
|
||||||
|
For the opcodes that load or store data at the assembly language level we could have the mnemonics
|
||||||
|
"store" and "load" and have the assembler pick the opcode based on the inclusion of the word "byte"
|
||||||
|
or "word" for two bytes. That would make the assembly easier to read but put a bit more work on the
|
||||||
|
assembler.
|
||||||
|
\section{STOB (Store Byte)}
|
||||||
|
\OpcodeTable{0x20}{stob}{Register}{Address}\\[6pt]
|
||||||
|
Stores a single byte (the lower nibble) from a register to a memory address.
|
||||||
|
\section{STOW (Store Machine Word)}
|
||||||
|
\OpcodeTable{0x20}{stow}{Register}{Address}\\[6pt]
|
||||||
|
Stores a machine word from a register to a memory address.
|
||||||
|
\section{LAA (Load Absolute Address)}
|
||||||
|
\OpcodeTable{0x00}{laa}{Register}{Address}\\[6pt]
|
||||||
|
Loads an address (2 bytes) into the register.
|
||||||
|
\section{LODB (Load Byte)}
|
||||||
|
\OpcodeTable{0x20}{lodb}{Register}{Register}\\[6pt]
|
||||||
|
Loads a single byte into a register from a memory address in the second operand register, zeroing out the high nibble.
|
||||||
|
\section{LODW (Load Machine Word)}
|
||||||
|
\OpcodeTable{0x20}{lodw}{Register}{Register}\\[6pt]
|
||||||
|
Loads a word into a register from a memory address in the second operand register.
|
||||||
|
\section{LODWI (Load Immediate Word)}
|
||||||
|
\OpcodeTable{0x00}{lodwi}{Register}{Constant}\\[6pt]
|
||||||
|
Loads an immediate machine word into the register clearing the high nibble if the value is less then 256.
|
||||||
|
\section{CMP (Compare)}
|
||||||
|
\OpcodeTable{0x20}{cmp}{Register}{Register}\\[6pt]
|
||||||
|
Compares two registers and somewhere sets a result in the status register.
|
||||||
|
\section{CMPI (Compare Immediate)}
|
||||||
|
\OpcodeTable{0x00}{cmpi}{Register}{Constant}\\[6pt]
|
||||||
|
Compares an immediate 2 byte value to the contents of a register setting the status register accordingly.
|
||||||
|
\section{ADD (Add)}
|
||||||
|
\OpcodeTable{0x20}{add}{Register}{Register}\\[6pt]
|
||||||
|
Performs addition on a register with a value from another (or the same) register.
|
||||||
|
\section{SUB (Subtract)}
|
||||||
|
\OpcodeTable{0x20}{sub}{Register}{Register}\\[6pt]
|
||||||
|
Performs subtraction on a register with a value from another (or the same) register.
|
||||||
|
\section{JMP (Jump)}
|
||||||
|
\OpcodeTable{0x20}{jmp}{Address}{None}\\[6pt]
|
||||||
|
Jumps unconditionally to a memory address.
|
||||||
|
\section{JZ (Jump if Zero)}
|
||||||
|
\OpcodeTable{0x20}{jz}{Register}{None}\\[6pt]
|
||||||
|
Jumps to a memory address if the status flag is zero.
|
||||||
|
\section{JG (Jump if Greater Than)}
|
||||||
|
\OpcodeTable{0x70}{jg}{Address}{None}\\[6pt]
|
||||||
|
Jump to the Address if the status flag is greater than zero.
|
||||||
|
\section{JL (Jump if Less Than)}
|
||||||
|
\OpcodeTable{0x00}{jl}{Address}{None}\\[6pt]
|
||||||
|
Jumps to the address if the status flag is less than zero.
|
||||||
|
\section{AND (Logical AND)}
|
||||||
|
\OpcodeTable{0x00}{and}{Register}{Register}\\[6pt]
|
||||||
|
Logical ANDs the two registers together storing the result in operand 1.
|
||||||
|
\section{XOR (Logical Exclusive OR)}
|
||||||
|
\OpcodeTable{0x00}{xor}{Register}{Register}\\[6pt]
|
||||||
|
Logical XORs the two registers together storing the result in operand 1.
|
||||||
|
\section{OR (Logical OR)}
|
||||||
|
\OpcodeTable{0x00}{or}{Register}{Register}\\[6pt]
|
||||||
|
Logical ORs the two registers together storing the result in operand 1.
|
||||||
|
\section{NOT (Logical Negation)}
|
||||||
|
\OpcodeTable{0x00}{not}{Register}{None}\\[6pt]
|
||||||
|
Inverts the bits of the target register.
|
||||||
|
\section{SHR (Shift Right)}
|
||||||
|
\OpcodeTable{0x00}{shr}{Register}{Constant}\\[6pt]
|
||||||
|
Bit-wise shifts the contents of the register right Constant number of times.
|
||||||
|
\section{SHL (Shift Left)}
|
||||||
|
\OpcodeTable{0x00}{shl}{Register}{Constant}\\[6pt]
|
||||||
|
Bit-wise shifts the contents of the register left Constant number of times.
|
||||||
|
\section{INC (Increment)}
|
||||||
|
\OpcodeTable{0x00}{inc}{Register}{None}\\[6pt]
|
||||||
|
Increments the contents of the register by one. Over-flows will not be reported.
|
||||||
|
\section{DEC (Decrement)}
|
||||||
|
\OpcodeTable{0x00}{dec}{Register}{None}\\[6pt]
|
||||||
|
Decrements the contents of the register by one. Under-flows will not be reported.
|
||||||
|
\section{NOP (No Operation)}
|
||||||
|
\OpcodeTable{0x00}{nop}{None}{None}\\[6pt]
|
||||||
|
Skips a clock cycle, incrementing the program counter.
|
||||||
|
\end{document}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef DIASSEMBLER_H
|
||||||
|
#define DIASSEMBLER_H
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
//void Disassemble(unsigned char image[HIGHMEMORY]);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+35
-22
@@ -2,34 +2,47 @@
|
|||||||
#define OPCODES_H
|
#define OPCODES_H
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "token.h"
|
#include "symbols_table.h"
|
||||||
|
|
||||||
#define OPCODECOUNT 10
|
|
||||||
#define REGISTERCOUNT 8
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
None = 0,
|
R1, R2, R3, R4, R5, R6, R7, R8
|
||||||
Reg,
|
} Registers;
|
||||||
Imm8,
|
|
||||||
Imm16
|
typedef enum {
|
||||||
} ParameterType;
|
ADD, SUB, JZ, INT, YLD, RET,
|
||||||
|
CMP, NOP, JMP, CALL, LOAD, JE, INC, DEC, LOADB
|
||||||
|
} Mnemonic;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NoParameter,
|
||||||
|
ConstantParameter,
|
||||||
|
AddressParameter,
|
||||||
|
RegisterParameter
|
||||||
|
} OpcodeParameter;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* lexeme;
|
OpcodeParameter ParameterType;
|
||||||
TokenType op;
|
OpcodeParameter InterpretedAs;
|
||||||
ParameterType parameter_one;
|
|
||||||
ParameterType parameter_two;
|
union {
|
||||||
} OpCode;
|
int Number; //ConstanrParam
|
||||||
|
Registers Register; //Register param
|
||||||
|
Symbol* Symbol; //Address param
|
||||||
|
} Value;
|
||||||
|
} Parameter;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* lexeme;
|
Mnemonic Mnemonic;
|
||||||
TokenType type;
|
Parameter* ParameterOne;
|
||||||
} Register;
|
Parameter* ParameterTwo;
|
||||||
|
} Instruction;
|
||||||
|
|
||||||
extern OpCode opcodes[OPCODECOUNT];
|
Instruction* CreateInstruction(Mnemonic mnemonic);
|
||||||
extern Register registers[REGISTERCOUNT];
|
Parameter* CreateParameter(OpcodeParameter parameterType);
|
||||||
|
void FreeInstruction(Instruction* instruction);
|
||||||
int IsOpcode(const char*, TokenType*);
|
int IsOpcode(const char*, Mnemonic*);
|
||||||
int IsRegister(const char*, TokenType*);
|
int IsRegister(const char*, Registers*);
|
||||||
|
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]);
|
||||||
|
unsigned char GetInstructionMask(Mnemonic type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+13
-1
@@ -1,11 +1,23 @@
|
|||||||
#ifndef PARSER_H
|
#ifndef PARSER_H
|
||||||
#define PARSER_H
|
#define PARSER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
|
#include "opcodes.h"
|
||||||
|
#include "symbols_table.h"
|
||||||
|
|
||||||
void ParseTokens(List*);
|
//#define HIGHMEMORY 65535 //64KiB - 1 AKA 0xFFFF
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
List* Instructions;
|
||||||
|
SymbolTable* SymbolsTable;
|
||||||
|
} IRState;
|
||||||
|
|
||||||
|
IRState* ParseTokens(List*);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef SYMBOLSTABLE_H
|
||||||
|
#define SYMBOLSTABLE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define SYMBOLSTABLE_DEFAULT_CAPACITY 128
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ValueAt,
|
||||||
|
Address
|
||||||
|
} SymbolType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* String;
|
||||||
|
uint8_t TerminatorByte;
|
||||||
|
int HasTerminatorByte;
|
||||||
|
} SymbolString;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* Name;
|
||||||
|
int Length;
|
||||||
|
int Resolved;
|
||||||
|
|
||||||
|
union {
|
||||||
|
SymbolString String;
|
||||||
|
int Number;
|
||||||
|
//Instruction Instruction;
|
||||||
|
} Value;
|
||||||
|
} Symbol;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Symbol** Symbols;
|
||||||
|
int Size;
|
||||||
|
int Capacity;
|
||||||
|
} SymbolTable;
|
||||||
|
|
||||||
|
SymbolTable* CreateSymbolTable(void);
|
||||||
|
Symbol* TryGetSymbol(char* name, SymbolTable* table);
|
||||||
|
Symbol* AddSymbolToTable(char* name, SymbolTable* table);
|
||||||
|
SymbolString* CreateSymbolString(char* text);
|
||||||
|
void FreeSymbolTable(SymbolTable* table);
|
||||||
|
void FreeSymbol(Symbol* symbol);
|
||||||
|
|
||||||
|
#endif
|
||||||
+45
-29
@@ -5,40 +5,56 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "opcodes.h"
|
||||||
|
|
||||||
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,
|
typedef enum {
|
||||||
HEX,
|
DB,
|
||||||
//Keywords
|
Origin,
|
||||||
DB, ORG,
|
Byte
|
||||||
//Opcodes
|
} Directive;
|
||||||
COPY, ADD, SUB, JZ, INT, YLD, RET,
|
|
||||||
CMP, IN, OUT,
|
typedef enum {
|
||||||
//Registers
|
RegisterClass = 0,
|
||||||
R1, R2, R3, R4, R5, R6, R7, R8
|
NumberClass = 1,
|
||||||
} TokenType;
|
CharacterClass = 2,
|
||||||
|
MnemonicClass = 4,
|
||||||
|
DirectiveClass = 8,
|
||||||
|
PunctuationClass = 16,
|
||||||
|
IdentifierClass = 32,
|
||||||
|
LabelClass = 64,
|
||||||
|
AddressClass = LabelClass | IdentifierClass
|
||||||
|
} TokenClass;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
TokenType type;
|
char* Lemexe;
|
||||||
char* lexeme;
|
TokenClass Class;
|
||||||
void* value;
|
int LineNumber;
|
||||||
int line;
|
int EndOfFile;
|
||||||
|
|
||||||
|
union {
|
||||||
|
TokenPunctuation Punctuation;
|
||||||
|
Registers Register;
|
||||||
|
Mnemonic Mnemonic;
|
||||||
|
Directive Directive;
|
||||||
|
int Number;
|
||||||
|
} Value;
|
||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
Token* CreateToken(char*, void*, int, TokenType);
|
Token* CreateToken(int lineNumber, TokenClass tokenClass);
|
||||||
void FreeToken(Token*);
|
void FreeToken(Token* token);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+24
-42
@@ -1,45 +1,27 @@
|
|||||||
.org 0x100
|
.db video_start 0xF37F
|
||||||
.db msg "Hello, world!", 0
|
.db msg "Hello, world!", 0
|
||||||
.db more_stuff "And yet another string!", 0
|
|
||||||
|
|
||||||
copy r1, msg
|
load r1, msg ; Because the lod* instructions can't load an address
|
||||||
copy r2, 0
|
; from anything but a register, this becomes laa r1, msg
|
||||||
loop:
|
load r8, [15]
|
||||||
cmp r1, 0
|
;Routine: string_length
|
||||||
jz loop
|
;In: String address in r1
|
||||||
add r1, 1
|
;Out: Length in R2
|
||||||
mov r1, 5 ; move the immediate value 5 into r1
|
|
||||||
add r1,5 ; add 5 into r1
|
string_length:
|
||||||
int 21 ; maybe that will call some string drawing BIOS-like routine
|
loadb r3, [r1] ; Load the byte from the address in R1, into R3
|
||||||
|
load r2, 0 ; String length
|
||||||
|
cmp r3, 0 ; Is R3 a null byte?
|
||||||
|
je end
|
||||||
|
inc r2
|
||||||
|
|
||||||
|
start:
|
||||||
|
inc r1 ; next char
|
||||||
|
loadb r3, [r1] ; Load the next character byte into R3
|
||||||
|
cmp r3, 0 ; Null byte?
|
||||||
|
je end
|
||||||
|
inc r2 ; Nope, increment the length counter
|
||||||
|
jmp start
|
||||||
|
|
||||||
|
end:
|
||||||
ret
|
ret
|
||||||
; form YYYY YYXX - Y opcode, X modifier
|
|
||||||
; nop: 0000 0000
|
|
||||||
; copy: 0000 01XX
|
|
||||||
; add: 0000 10XX - | Perhaps running these will clear any overflow
|
|
||||||
; addc: 0000 11XX - | or under flow flags if no errors occur.
|
|
||||||
; sub: 0001 00XX - | jz should clear the zero flag.
|
|
||||||
; subb: 0001 01XX - |
|
|
||||||
; call: 0001 1100 - Always call [imm16]
|
|
||||||
; jmp: 0010 0000 - Always jmp [imm16] (No short jumps)
|
|
||||||
; jz: 0010 0100 - Always jz [imm16] (no short jumps)
|
|
||||||
; cmp: 0010 11XX
|
|
||||||
; push: 0011 11XX -| pop / push imm16/imm8 | reg
|
|
||||||
; pop: 0100 00XX -|
|
|
||||||
|
|
||||||
;
|
|
||||||
; imm8 imm16 reg
|
|
||||||
; mov reg, imm16|reg
|
|
||||||
; add reg, imm16|reg
|
|
||||||
; int imm16
|
|
||||||
; db [label] 'String data here' (Null byte is added implicatly by the assemblier)
|
|
||||||
;
|
|
||||||
; enum Type {
|
|
||||||
; Op,
|
|
||||||
; Reg,
|
|
||||||
; Imm16,
|
|
||||||
; Imm8
|
|
||||||
; }
|
|
||||||
; struct Token {
|
|
||||||
; enum Type type;
|
|
||||||
; char *value;
|
|
||||||
; }
|
|
||||||
+161
@@ -0,0 +1,161 @@
|
|||||||
|
#include "../includes/disass.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
const unsigned char* Image;
|
||||||
|
const unsigned char COPYMASKREG = 0x20;
|
||||||
|
const unsigned char COPYMASKADD = 0xA0;
|
||||||
|
const unsigned char ADDMASK = 0x40;
|
||||||
|
const unsigned char SUBMASK = 0x60;
|
||||||
|
const unsigned char CMPMASK = 0x80;
|
||||||
|
|
||||||
|
const unsigned char REGMASK = 0x00;//0x18; //0001 1000
|
||||||
|
const unsigned char CONSTMASK = 0x08; //0000 1000
|
||||||
|
const unsigned char ADDRESSMASK = 0x10; //0001 0000
|
||||||
|
|
||||||
|
int IsRegisterPattern(unsigned char pattern, char* lexeme);
|
||||||
|
void GetParameter(unsigned char instruction, char* text);
|
||||||
|
/*
|
||||||
|
void Disassemble(unsigned char image[HIGHMEMORY]) {
|
||||||
|
Image = image;
|
||||||
|
int position = image[0] + image[1];
|
||||||
|
int end = image[2] + image[3];
|
||||||
|
|
||||||
|
char* parameter1 = calloc(32, sizeof(char));
|
||||||
|
char* parameter2 = calloc(32, sizeof(char));
|
||||||
|
|
||||||
|
unsigned char instruction = image[position];
|
||||||
|
|
||||||
|
while(end > position) {
|
||||||
|
unsigned char masked = instruction & 0xE0;
|
||||||
|
|
||||||
|
if (masked) {
|
||||||
|
IsRegisterPattern(instruction & 0x07, parameter1);
|
||||||
|
unsigned char parameterType = instruction & 0x18;
|
||||||
|
|
||||||
|
if (parameterType == REGMASK) {
|
||||||
|
IsRegisterPattern(Image[position + 1], parameter2);
|
||||||
|
position += 2;
|
||||||
|
} else if (parameterType == CONSTMASK) {
|
||||||
|
snprintf(parameter2, sizeof(char) * 31, "%d", Image[position + 1] + Image[position + 2]);
|
||||||
|
position += 3;
|
||||||
|
}
|
||||||
|
else if (parameterType == ADDRESSMASK) {
|
||||||
|
snprintf(parameter2, sizeof(char) * 31, "[%#04X]", Image[position + 1] + Image[position + 2]);
|
||||||
|
position += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
//If the top bits are set
|
||||||
|
if (masked == COPYMASKREG) {
|
||||||
|
printf("COPY %s, %s\n", parameter1, parameter2);
|
||||||
|
}
|
||||||
|
else if (masked == COPYMASKADD) {
|
||||||
|
printf("COPY %s, %s\n", parameter2, parameter1);
|
||||||
|
}
|
||||||
|
else if (masked == ADDMASK) {
|
||||||
|
printf("ADD %s, %s\n", parameter1, parameter2);
|
||||||
|
}
|
||||||
|
else if (masked == SUBMASK) {
|
||||||
|
printf("SUB %s, %s\n", parameter1, parameter2);
|
||||||
|
}
|
||||||
|
else if (masked == CMPMASK) {
|
||||||
|
printf("CMP %s, %s\n", parameter1, parameter2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "[Error] Unknown opcode %#02X\n", masked);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int parameter = Image[position + 1] + Image[position + 2];
|
||||||
|
|
||||||
|
switch(instruction) {
|
||||||
|
case 0:
|
||||||
|
printf("NOP\n");
|
||||||
|
position++;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
printf("JZ [%#04X]\n", parameter);
|
||||||
|
position += 3;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
printf("INT %d\n", parameter);
|
||||||
|
position += 3;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
printf("YLD\n");
|
||||||
|
position++;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
printf("RET\n");
|
||||||
|
position++;
|
||||||
|
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:
|
||||||
|
position++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction = Image[position];
|
||||||
|
|
||||||
|
memset(parameter1, '\0', sizeof(char) * 32);
|
||||||
|
memset(parameter2, '\0', sizeof(char) * 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
int IsRegisterPattern(unsigned char pattern, char* lexeme) {
|
||||||
|
if (pattern > 8) {
|
||||||
|
lexeme[0] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//The registers' bit patterns are zero indexed, so 'r1' is '000'
|
||||||
|
//but 'r8' is '111' and so forth.
|
||||||
|
pattern++;
|
||||||
|
|
||||||
|
lexeme[0] = 'r';
|
||||||
|
lexeme[1] = pattern | 0x30;
|
||||||
|
lexeme[2] = '\0';
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
//REG XXX0 0XXX
|
||||||
|
//Constant XXX0 1XXX
|
||||||
|
//Address XXX1 0XXX
|
||||||
|
NOP - 0000 0000 NOP
|
||||||
|
JZ - 0000 0001 JZ Address
|
||||||
|
INT - 0000 0010 INT Constant
|
||||||
|
YLD - 0000 0011 YLD
|
||||||
|
RET - 0000 0100 RET
|
||||||
|
CALL - 0000 0101 CALL Address
|
||||||
|
JMP - 0000 0110 JMP Address
|
||||||
|
IN - 0000 0111 IN Constant
|
||||||
|
OUT - 0000 1000 OUT Constant
|
||||||
|
COPY - 0010 0XXX COPY REG, REG
|
||||||
|
- 0010 1XXX COPY REG, Constant
|
||||||
|
- 0011 0XXX COPY REG, Address
|
||||||
|
- 1010 0XXX COPY Address, REG
|
||||||
|
- 1010 1XXX COPY Address, Constant
|
||||||
|
- 1011 0XXX COPY Address, Address
|
||||||
|
ADD - 0100 0XXX ADD REG, REG
|
||||||
|
- 0100 1XXX ADD REG, Constant
|
||||||
|
SUB - 0110 0XXX SUB REG, REG
|
||||||
|
- 0110 1XXX SUB REG, Constant
|
||||||
|
CMP - 1000 0XXX CMP REG, REG
|
||||||
|
- 1000 1XXX CMP REG, Constant
|
||||||
|
- 1001 0XXX CMP REG, Address */
|
||||||
+70
-7
@@ -1,3 +1,4 @@
|
|||||||
|
#include <bits/types/FILE.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -19,16 +20,78 @@ int main(int argc, char* args[]) {
|
|||||||
if (!ReadAllString(args[1], &source_code, &bytes_read)) return EX_IOERR;
|
if (!ReadAllString(args[1], &source_code, &bytes_read)) return EX_IOERR;
|
||||||
|
|
||||||
List* list = GenerateTokenList(source_code);
|
List* list = GenerateTokenList(source_code);
|
||||||
|
char mnemonic[12];
|
||||||
|
|
||||||
// for(int i = 0; i < list->size; i++) {
|
for(int i = 0; i < list->size; i++) {
|
||||||
// Token* t = (Token*) list->content[i];
|
Token* t = (Token*) list->content[i];
|
||||||
|
|
||||||
// printf("[%i] '%s'", t->type, t->lexeme);
|
if (t->EndOfFile) {
|
||||||
// if (t->type == LABEL) printf("*");
|
printf("EOF\n");
|
||||||
// printf("\n");
|
break;
|
||||||
// }
|
}
|
||||||
|
|
||||||
ParseTokens(list);
|
if (t->Class == PunctuationClass){
|
||||||
|
if(t->Value.Punctuation == NewLine) {
|
||||||
|
printf("\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("<%d>", t->LineNumber);
|
||||||
|
|
||||||
|
printf("%c ", t->Value.Punctuation);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("<%d>", t->LineNumber);
|
||||||
|
|
||||||
|
if (t->Class == LabelClass) {
|
||||||
|
printf("[L]%s* ", t->Lemexe);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->Class == IdentifierClass) {
|
||||||
|
printf("[I]%s ", t->Lemexe);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->Class == RegisterClass) {
|
||||||
|
printf("[R]%d", t->Value.Register);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->Class == NumberClass) {
|
||||||
|
printf("[N]%d ", t->Value.Number);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->Class == MnemonicClass) {
|
||||||
|
GetMnemonicText(t->Value.Mnemonic, mnemonic);
|
||||||
|
printf("[M]%s ", mnemonic);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->Class == DirectiveClass) {
|
||||||
|
printf("[D]%d ", t->Value.Directive);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->Class == CharacterClass) {
|
||||||
|
printf("%s ", t->Lemexe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IRState* image = ParseTokens(list);
|
||||||
|
//free(image);
|
||||||
|
//Disassemble(image);
|
||||||
|
//for(int i = 0; i < image->Opcodes->size; i++) {
|
||||||
|
// printf("%d\n", ((IROpcode*) image->Opcodes->content[i])->Mnemonic);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//FILE* program = fopen("program.bin", "w+b");
|
||||||
|
|
||||||
|
//fwrite(image, 1, image[2] + image[3], program);
|
||||||
|
|
||||||
|
//fclose(program);
|
||||||
|
|
||||||
free(source_code);
|
free(source_code);
|
||||||
}
|
}
|
||||||
+181
-31
@@ -2,36 +2,167 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
OpCode opcodes[OPCODECOUNT] = {
|
#define OPCODECOUNT 15
|
||||||
{ "copy", COPY, Reg, Reg | Imm8 | Imm16 },
|
|
||||||
{ "add", ADD, Reg, Reg | Imm8 | Imm16 },
|
struct _instruction {
|
||||||
{ "sub", SUB, Reg, Reg | Imm8 | Imm16 },
|
char* Name;
|
||||||
{ "jz", JZ, Imm8 | Imm16, None },
|
Mnemonic Mnemonic;
|
||||||
{ "int", INT, Imm8, None },
|
|
||||||
{ "yld", YLD, None, None },
|
|
||||||
{ "ret", RET, None, None },
|
|
||||||
{ "cmp", CMP, Reg | Imm8 | Imm16, Reg | Imm8 | Imm16 },
|
|
||||||
{ "in", IN, None, None},
|
|
||||||
{ "out", OUT, None, None}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Register registers[REGISTERCOUNT] = {
|
struct _instruction instructions[OPCODECOUNT] = {
|
||||||
{ "r1", R1 },
|
{ "add", ADD },//, Reg, Reg | Constant },
|
||||||
{ "r2", R2 },
|
{ "sub", SUB },//, Reg, Reg | Constant },
|
||||||
{ "r3", R3 },
|
{ "jz", JZ },//, Address, None },
|
||||||
{ "r4", R4 },
|
{ "int", INT },//, Constant, None },
|
||||||
{ "r5", R5 },
|
{ "yld", YLD },//, None, None },
|
||||||
{ "r6", R6 },
|
{ "ret", RET },//, None, None },
|
||||||
{ "r7", R7 },
|
{ "cmp", CMP },//, Reg, Reg | Constant },
|
||||||
{ "r8", R8 }
|
{ "inc", INC },//, Constant | Reg, None},
|
||||||
|
{ "dec", DEC },//, None, None},
|
||||||
|
{ "nop", NOP },//, None, None},
|
||||||
|
{ "jmp", JMP },//, Address, None},
|
||||||
|
{ "call", CALL },//, Address, None}
|
||||||
|
{ "load", LOAD },
|
||||||
|
{ "je", JE },
|
||||||
|
{ "loadb", LOADB}
|
||||||
};
|
};
|
||||||
|
|
||||||
int IsOpcode(const char* text, TokenType* opcode) {
|
Instruction* CreateInstruction(Mnemonic mnemonic) {
|
||||||
|
Instruction* instruction = calloc(1, sizeof(Instruction));
|
||||||
|
|
||||||
|
if (!instruction) {
|
||||||
|
fprintf(stderr, "Failed to calloc room for an Instruction. %s.\n", strerror(errno));
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction->Mnemonic = mnemonic;
|
||||||
|
// instruction->ParameterOne = CreateParameter(NoParameter);
|
||||||
|
// instruction->ParameterTwo = CreateParameter(NoParameter);
|
||||||
|
|
||||||
|
return instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter* CreateParameter(OpcodeParameter parameterType) {
|
||||||
|
Parameter* param = calloc(1, sizeof(Parameter));
|
||||||
|
|
||||||
|
if (!param) {
|
||||||
|
fprintf(stderr, "Failed to calloc room for a Parameter. %s,\n", strerror(errno));
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
param->ParameterType = parameterType;
|
||||||
|
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeInstruction(Instruction* instruction) {
|
||||||
|
if (!instruction) return;
|
||||||
|
|
||||||
|
free(instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char GetInstructionMask(Mnemonic type) {
|
||||||
|
switch (type) {
|
||||||
|
case LOAD:
|
||||||
|
return 0x20; //0b00100000; ORing 0x80 marks the first parameter as an address
|
||||||
|
case ADD:
|
||||||
|
return 0x40;//0b01000000;
|
||||||
|
case SUB:
|
||||||
|
return 0x60;//0b01100000;
|
||||||
|
case CMP:
|
||||||
|
return 0x80;//0b10000000;
|
||||||
|
case JZ:
|
||||||
|
return 0x01;//0b00000001;
|
||||||
|
case INT:
|
||||||
|
return 0x02; //0b00000010;
|
||||||
|
case YLD:
|
||||||
|
return 0x03;
|
||||||
|
case RET:
|
||||||
|
return 0x04;
|
||||||
|
case CALL:
|
||||||
|
return 0x05;
|
||||||
|
case JMP:
|
||||||
|
return 0x06;//0b00000110;
|
||||||
|
case INC:
|
||||||
|
return 0x07;//0b00000111;
|
||||||
|
case DEC:
|
||||||
|
return 0x08;//0b00001000;
|
||||||
|
default:
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]) {
|
||||||
|
memset(buffer, '\0', 12);
|
||||||
|
|
||||||
|
for(int i = 0; i < OPCODECOUNT; i++) {
|
||||||
|
if (instructions[i].Mnemonic == mnemonic) {
|
||||||
|
strncpy(buffer, instructions[i].Name, 11);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOP - 0000 0000 NOP
|
||||||
|
JZ - 0000 0001 JZ Address
|
||||||
|
INT - 0000 0010 INT Constant
|
||||||
|
YLD - 0000 0011 YLD
|
||||||
|
RET - 0000 0100 RET
|
||||||
|
CALL - 0000 0101 CALL Address
|
||||||
|
JMP - 0000 0110 JMP Address
|
||||||
|
IN - 0000 0111 IN Constant
|
||||||
|
OUT - 0000 1000 OUT Constant
|
||||||
|
COPY - 0010 0XXX COPY REG, REG
|
||||||
|
- 0010 1XXX COPY REG, Constant
|
||||||
|
- 0011 0XXX COPY REG, Address
|
||||||
|
- 1010 0XXX COPY Address, REG
|
||||||
|
- 1010 1XXX COPY Address, Constant
|
||||||
|
- 1011 0XXX COPY Address, Address
|
||||||
|
ADD - 0100 0XXX ADD REG, REG
|
||||||
|
- 0100 1XXX ADD REG, Constant
|
||||||
|
SUB - 0110 0XXX SUB REG, REG
|
||||||
|
- 0110 1XXX SUB REG, Constant
|
||||||
|
CMP - 1000 0XXX CMP REG, REG
|
||||||
|
- 1000 1XXX CMP REG, Constant
|
||||||
|
- 1001 0XXX CMP REG, Address
|
||||||
|
*/
|
||||||
|
//COPY X01X XXXX
|
||||||
|
//ADD 010X XXXX
|
||||||
|
//SUB 011X XXXX
|
||||||
|
//CMP 100X XXXX
|
||||||
|
//REG XXX0 0XXX
|
||||||
|
//Constant XXX0 1XXX
|
||||||
|
//Address XXX1 0XXX
|
||||||
|
//R1 XXXX X000 -> XXXX X111 (R1 to R8)
|
||||||
|
|
||||||
|
// Register registers[REGISTERCOUNT] = {
|
||||||
|
// { "r1", R1 },
|
||||||
|
// { "r2", R2 },
|
||||||
|
// { "r3", R3 },
|
||||||
|
// { "r4", R4 },
|
||||||
|
// { "r5", R5 },
|
||||||
|
// { "r6", R6 },
|
||||||
|
// { "r7", R7 },
|
||||||
|
// { "r8", R8 }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const Instruction* GetOpcodeDetails(Mnemonic type) {
|
||||||
|
// for(int i = 0; i < OPCODECOUNT; i++) {
|
||||||
|
// if (instructions[i].op == type) return &instructions[i];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return NULL;
|
||||||
|
// }
|
||||||
|
|
||||||
|
int IsOpcode(const char* text, Mnemonic* opcode) {
|
||||||
if (!text) return 0;
|
if (!text) return 0;
|
||||||
|
|
||||||
for(int i = 0; i < OPCODECOUNT; i++) {
|
for(int i = 0; i < OPCODECOUNT; i++) {
|
||||||
if (strcmp(opcodes[i].lexeme, text) == 0) {
|
if (strcmp(instructions[i].Name, text) == 0) {
|
||||||
*opcode = opcodes[i].op;
|
if (opcode) *opcode = instructions[i].Mnemonic;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,15 +170,34 @@ int IsOpcode(const char* text, TokenType* opcode) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int IsRegister(const char* text, TokenType* reg) {
|
int IsRegister(const char* text, Registers* reg) {
|
||||||
if (!text) return 0;
|
if (!text) return 0;
|
||||||
|
|
||||||
for(int i = 0; i < REGISTERCOUNT; i++) {
|
int length = strlen(text);
|
||||||
if (strcmp(registers[i].lexeme, text) == 0) {
|
Registers r = R8;
|
||||||
*reg = registers[i].type;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
if (length != 2) return 0;
|
||||||
|
if (text[0] != 'r') return 0;
|
||||||
|
|
||||||
|
switch(text[1]) {
|
||||||
|
case '1':
|
||||||
|
r--;
|
||||||
|
case '2':
|
||||||
|
r--;
|
||||||
|
case '3':
|
||||||
|
r--;
|
||||||
|
case '4':
|
||||||
|
r--;
|
||||||
|
case '5':
|
||||||
|
r--;
|
||||||
|
case '6':
|
||||||
|
r--;
|
||||||
|
case '7':
|
||||||
|
r--;
|
||||||
|
case '8':
|
||||||
|
if (reg) *reg = r;
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+266
-57
@@ -1,89 +1,298 @@
|
|||||||
#include "../includes/parser.h"
|
#include "../includes/parser.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
typedef struct {
|
const List* TokensList;
|
||||||
Token* token;
|
int CurrentToken = 0;
|
||||||
int address;
|
|
||||||
} Symbol;
|
|
||||||
|
|
||||||
Symbol* CreateSymbol(Token*, int);
|
|
||||||
void AddSymbol(Token*);
|
|
||||||
void PrintSymbols(void);
|
void PrintSymbols(void);
|
||||||
Token* GetSymbol(char*);
|
SymbolString* ParseIdentifierParameter(void);
|
||||||
List* SymbolsTable;
|
Instruction* HandleOperation(void);
|
||||||
unsigned int ProgramCounter = 0;
|
void HandleAssemblerDirective(void);
|
||||||
|
void AdvanceParser(void);
|
||||||
|
void IgnoreParserLine(void);
|
||||||
|
Token* PeekToken(void);
|
||||||
|
int ParserAtEnd(void);
|
||||||
|
IRState MachineState;
|
||||||
|
|
||||||
void ParseTokens(List* tokens) {
|
IRState* ParseTokens(List* tokens) {
|
||||||
SymbolsTable = CreateList();
|
if (!tokens) return NULL;
|
||||||
|
|
||||||
for(int i = 0; i < tokens->size; i++){
|
TokensList = tokens;
|
||||||
Token* t = tokens->content[i];
|
|
||||||
|
|
||||||
switch(t->type) {
|
MachineState.SymbolsTable = CreateSymbolTable();
|
||||||
case IDENTIFIER:
|
MachineState.Instructions = CreateList();
|
||||||
case LABEL:
|
|
||||||
AddSymbol(t);
|
while(!ParserAtEnd()) {
|
||||||
|
Token* t = PeekToken();
|
||||||
|
|
||||||
|
switch(t->Class) {
|
||||||
|
case DirectiveClass: //Maybe these should be ignored, let another process handle that.
|
||||||
|
IgnoreParserLine();
|
||||||
break;
|
break;
|
||||||
case STRING:
|
case MnemonicClass:
|
||||||
ProgramCounter += strlen(t->lexeme);
|
HandleOperation();
|
||||||
break;
|
break;
|
||||||
case NUMBER:
|
case LabelClass:
|
||||||
case HEX:
|
{
|
||||||
if ((long) t->value < 256) ProgramCounter += 1;
|
Symbol* symbol = TryGetSymbol(t->Lemexe, MachineState.SymbolsTable);
|
||||||
else ProgramCounter += 2;
|
|
||||||
|
if (symbol && symbol->Resolved) {
|
||||||
|
fprintf(stderr, "[Error] Line %d: Redefinition of symbol '%s'\n", t->LineNumber, t->Lemexe);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvanceParser(); //Consume the label token
|
||||||
|
|
||||||
|
if (!symbol) AddSymbolToTable(t->Lemexe, MachineState.SymbolsTable)->Resolved = 1;
|
||||||
|
else symbol->Resolved = 1;
|
||||||
|
|
||||||
|
AdvanceParser(); //Consume the NewLine
|
||||||
|
|
||||||
|
// Instruction* ins = HandleOperation();
|
||||||
|
|
||||||
|
// if (!ins) continue;
|
||||||
|
|
||||||
|
// symbol->Value.Instruction = ins;
|
||||||
|
// symbol->InstructionPointer = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (t->type > ORG) ProgramCounter += 1;
|
fprintf(stderr, "[Warning] Line %d: Syntax error, expected start of expression, got '%c' [%d].\n", t->LineNumber, t->Value.Punctuation, t->Class);
|
||||||
|
//exit(1);
|
||||||
|
IgnoreParserLine();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintSymbols();
|
if (MachineState.SymbolsTable->Size > 0) PrintSymbols();
|
||||||
DestroyList(SymbolsTable);
|
|
||||||
printf("Program Counter: %d\n", ProgramCounter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintSymbols(void) {
|
for(int i = 0; i < MachineState.Instructions->size; i++) {
|
||||||
printf("-----SYMBOLS-----\n");
|
char mn[12];
|
||||||
for(int i = 0; i < SymbolsTable->size; i++) {
|
|
||||||
Symbol* symbol = SymbolsTable->content[i];
|
|
||||||
printf("[%#08X] %s\n", symbol->address, symbol->token->lexeme);
|
|
||||||
}
|
|
||||||
printf("-----SYMBOLS-----\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddSymbol(Token* token) {
|
Instruction* ins = MachineState.Instructions->content[i];
|
||||||
if (!token) return;
|
|
||||||
if (token->type != IDENTIFIER && token->type != LABEL) return;
|
|
||||||
|
|
||||||
for(int i = 0; i < SymbolsTable->size; i++) {
|
GetMnemonicText(ins->Mnemonic, mn);
|
||||||
Symbol* s = SymbolsTable->content[i];
|
|
||||||
|
|
||||||
if (strcmp(s->token->lexeme, token->lexeme) == 0) return;
|
printf("%s\n", mn);
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol* symbol = CreateSymbol(token, ProgramCounter);
|
return &MachineState;
|
||||||
|
|
||||||
AddListItem(symbol, sizeof(Symbol), SymbolsTable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* GetSymbol(char* name) {
|
SymbolString* ParseIdentifierParameter(void) {
|
||||||
if (!name) return NULL;
|
Token* token = PeekToken();
|
||||||
|
|
||||||
|
if (token->Class != IdentifierClass) {
|
||||||
|
fprintf(stderr, "[Error] Line %d: Expected identifier\n", token->LineNumber);
|
||||||
|
IgnoreParserLine();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolString* string = CreateSymbolString(token->Lemexe);
|
||||||
|
|
||||||
|
AdvanceParser();
|
||||||
|
|
||||||
|
if (token->Class == PunctuationClass && token->Value.Punctuation == NewLine) {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
else if (token->Class == PunctuationClass && token->Value.Punctuation == Comma) {
|
||||||
|
AdvanceParser(); // Comsume the comma
|
||||||
|
|
||||||
|
token = PeekToken();
|
||||||
|
|
||||||
|
if (token->Class != NumberClass) {
|
||||||
|
fprintf(stderr, "[Error] Line %d: Expected string termination number.\n", token->LineNumber);
|
||||||
|
IgnoreParserLine();
|
||||||
|
free(string);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
string->HasTerminatorByte = 1;
|
||||||
|
string->TerminatorByte = token->Value.Number;
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol* CreateSymbol(Token* token, int offset) {
|
Parameter* GetParameterType() {
|
||||||
Symbol* symbol = calloc(1, sizeof(Symbol));
|
Token* token = PeekToken();
|
||||||
|
Symbol* symbol = NULL;
|
||||||
|
Parameter* param = CreateParameter(NoParameter);
|
||||||
|
|
||||||
if (!symbol) {
|
switch(token->Class) {
|
||||||
return NULL;
|
case RegisterClass:
|
||||||
|
param->ParameterType = RegisterParameter;
|
||||||
|
param->InterpretedAs = RegisterParameter;
|
||||||
|
|
||||||
|
param->Value.Register = token->Value.Register;
|
||||||
|
|
||||||
|
AdvanceParser();
|
||||||
|
|
||||||
|
return param;
|
||||||
|
case IdentifierClass:
|
||||||
|
param->ParameterType = AddressParameter;
|
||||||
|
param->InterpretedAs = AddressParameter;
|
||||||
|
|
||||||
|
symbol = TryGetSymbol(token->Lemexe, MachineState.SymbolsTable);
|
||||||
|
|
||||||
|
if (!symbol) symbol = AddSymbolToTable(token->Lemexe, MachineState.SymbolsTable);
|
||||||
|
|
||||||
|
param->Value.Symbol = symbol;
|
||||||
|
|
||||||
|
AdvanceParser();
|
||||||
|
|
||||||
|
return param;
|
||||||
|
case PunctuationClass:
|
||||||
|
if (token->Value.Punctuation != LBracket) {
|
||||||
|
fprintf(stderr, "[Error] Line %d: Expected opening bracket\n", token->LineNumber);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvanceParser(); // [
|
||||||
|
|
||||||
|
token = PeekToken();
|
||||||
|
|
||||||
|
if (token->Class == NumberClass) {
|
||||||
|
param->ParameterType = ConstantParameter;
|
||||||
|
param->InterpretedAs = AddressParameter;
|
||||||
|
param->Value.Number = token->Value.Number;
|
||||||
|
}
|
||||||
|
else if (token->Class == RegisterClass) {
|
||||||
|
param->ParameterType = RegisterParameter;
|
||||||
|
param->InterpretedAs = AddressParameter;
|
||||||
|
param->Value.Register = token->Value.Register;
|
||||||
|
}
|
||||||
|
else if (token->Class & AddressClass) {
|
||||||
|
param->ParameterType = AddressParameter;
|
||||||
|
param->ParameterType = AddressParameter;
|
||||||
|
|
||||||
|
symbol = TryGetSymbol(token->Lemexe, MachineState.SymbolsTable);
|
||||||
|
|
||||||
|
if (!symbol) symbol = AddSymbolToTable(token->Lemexe, MachineState.SymbolsTable);
|
||||||
|
|
||||||
|
param->Value.Symbol = symbol;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "[Error] Line %d: Expected identifier, constant number or register.\n", token->LineNumber);
|
||||||
|
IgnoreParserLine();
|
||||||
|
//return NULL;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvanceParser(); //Consume the parameter it self.
|
||||||
|
|
||||||
|
token = PeekToken();
|
||||||
|
|
||||||
|
if (token->Class != PunctuationClass || token->Value.Punctuation != RBracket) {
|
||||||
|
fprintf(stderr, "[Error] Line %d: Expected closing bracket.\n", token->LineNumber);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvanceParser(); // ]
|
||||||
|
|
||||||
|
return param;
|
||||||
|
case NumberClass:
|
||||||
|
param->ParameterType = ConstantParameter;
|
||||||
|
param->InterpretedAs = ConstantParameter;
|
||||||
|
|
||||||
|
param->Value.Number = token->Value.Number;
|
||||||
|
|
||||||
|
AdvanceParser();
|
||||||
|
|
||||||
|
return param;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol->token = token;
|
return param;
|
||||||
symbol->address = offset;
|
}
|
||||||
|
|
||||||
return symbol;
|
void HandleOperation() {
|
||||||
|
Token* token = PeekToken();
|
||||||
|
char mn[12];
|
||||||
|
|
||||||
|
Instruction* ins = CreateInstruction(token->Value.Mnemonic);
|
||||||
|
|
||||||
|
GetMnemonicText(ins->Mnemonic, mn);
|
||||||
|
|
||||||
|
AdvanceParser();
|
||||||
|
|
||||||
|
//No parameters here, we have a line break.
|
||||||
|
if (PeekToken()->EndOfFile || (PeekToken()->Class == PunctuationClass && PeekToken()->Value.Punctuation == NewLine)) {
|
||||||
|
goto InsertInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
ins->ParameterOne = GetParameterType();
|
||||||
|
|
||||||
|
if (ins->ParameterOne->ParameterType == NoParameter) {
|
||||||
|
//This would be an error if the next token isn't a line break.
|
||||||
|
if (PeekToken()->Class != PunctuationClass || PeekToken()->Value.Punctuation != NewLine) {
|
||||||
|
fprintf(stderr, "[Error] Line %d: Syntax error, expected line break but got %s.\n", token->LineNumber, token->Lemexe);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto InsertInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PeekToken()->Class == PunctuationClass && PeekToken()->Value.Punctuation == NewLine) {
|
||||||
|
goto InsertInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PeekToken()->Class != PunctuationClass || PeekToken()->Value.Punctuation != Comma) {
|
||||||
|
//Syntax error
|
||||||
|
fprintf(stderr, "[Error] Line %d: Expected comma.\n", token->LineNumber);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvanceParser(); //Consume the comma
|
||||||
|
|
||||||
|
ins->ParameterTwo = GetParameterType();
|
||||||
|
|
||||||
|
InsertInstruction:
|
||||||
|
|
||||||
|
AddListItem(ins, sizeof(Instruction), MachineState.Instructions);
|
||||||
|
|
||||||
|
AdvanceParser(); //Consume the line break
|
||||||
|
|
||||||
|
free(ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintSymbols(void) {
|
||||||
|
printf("-----SYMBOLS-----\n");
|
||||||
|
for(int i = 0; i < MachineState.SymbolsTable->Size; i++) {
|
||||||
|
Symbol* symbol = MachineState.SymbolsTable->Symbols[i];
|
||||||
|
|
||||||
|
printf("[Resolved? %d] %s\n", symbol->Resolved, symbol->Name);
|
||||||
|
}
|
||||||
|
printf("-----SYMBOLS-----\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvanceParser(void) {
|
||||||
|
if (ParserAtEnd()) return;
|
||||||
|
|
||||||
|
CurrentToken++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ParserAtEnd(void) {
|
||||||
|
if (CurrentToken >= TokensList->size) return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* PeekToken(void) {
|
||||||
|
return TokensList->content[CurrentToken];
|
||||||
|
}
|
||||||
|
|
||||||
|
void IgnoreParserLine(void) {
|
||||||
|
while(!ParserAtEnd()) {
|
||||||
|
if (PeekToken()->Class == PunctuationClass && PeekToken()->Value.Punctuation == NewLine) {
|
||||||
|
AdvanceParser();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PeekToken()->EndOfFile) break;
|
||||||
|
|
||||||
|
AdvanceParser();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+129
-28
@@ -1,13 +1,16 @@
|
|||||||
#include "../includes/scanner.h"
|
#include "../includes/scanner.h"
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
const char* SourceCode;
|
const char* SourceCode;
|
||||||
int Line = 0;
|
int Line = 1;
|
||||||
int Position = 0;
|
int Position = 0;
|
||||||
int SourceLength = 0;
|
int SourceLength = 0;
|
||||||
int ScannerAtEnd(void);
|
int ScannerAtEnd(void);
|
||||||
int IsPunctuation(char);
|
int IsPunctuation(char);
|
||||||
|
int IsWhiteSpace(char);
|
||||||
char PeekScanner(void);
|
char PeekScanner(void);
|
||||||
char PeekAheadScanner(void);
|
char PeekAheadScanner(void);
|
||||||
void AdvanceScanner(void);
|
void AdvanceScanner(void);
|
||||||
@@ -34,14 +37,35 @@ List* GenerateTokenList(const char* source) {
|
|||||||
case ' ':
|
case ' ':
|
||||||
case '\r':
|
case '\r':
|
||||||
case '\t':
|
case '\t':
|
||||||
|
case '\v':
|
||||||
|
case '\f':
|
||||||
AdvanceScanner();
|
AdvanceScanner();
|
||||||
break; //Ignore whitespace
|
break; //Ignore whitespace
|
||||||
case '\n':
|
case '\n':
|
||||||
|
if (tokens->size > 0) {
|
||||||
|
token = tokens->content[tokens->size - 1];
|
||||||
|
|
||||||
|
if (token->Class == PunctuationClass && token->Value.Punctuation == NewLine) {
|
||||||
|
AdvanceScanner();
|
||||||
|
Line++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token = CreateToken(Line, PunctuationClass);
|
||||||
|
token->Value.Punctuation = NewLine;
|
||||||
|
AddListItem(token, sizeof(Token), tokens);
|
||||||
AdvanceScanner();
|
AdvanceScanner();
|
||||||
Line++;
|
Line++;
|
||||||
break;
|
break;
|
||||||
case ';':
|
case ';':
|
||||||
IgnoreLine();
|
IgnoreLine();
|
||||||
|
|
||||||
|
if (tokens->size == 0) {
|
||||||
|
//There's nothing here so that means this is some comments block at the start of the file.
|
||||||
|
AdvanceScanner(); //Consume the actual new line char.
|
||||||
|
Line++;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case '.': //directive like ".org" or ".db"
|
case '.': //directive like ".org" or ".db"
|
||||||
token = ParseDirective();
|
token = ParseDirective();
|
||||||
@@ -74,20 +98,45 @@ List* GenerateTokenList(const char* source) {
|
|||||||
token = NULL;
|
token = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tokens->size > 0) {
|
||||||
|
token = tokens->content[tokens->size - 1];
|
||||||
|
|
||||||
|
if (token->Class == PunctuationClass && token->Value.Punctuation == NewLine) {
|
||||||
|
//If the last token is a line break, remove it as its not too meaningful.
|
||||||
|
tokens->size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token = CreateToken(Line, PunctuationClass);
|
||||||
|
|
||||||
|
token->EndOfFile = 1;
|
||||||
|
|
||||||
|
AddListItem(token, sizeof(Token), tokens);
|
||||||
|
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* ParseNumber(void) {
|
Token* ParseNumber(void) {
|
||||||
int start = Position;
|
int start = Position;
|
||||||
int base = 10;
|
|
||||||
|
|
||||||
while(!ScannerAtEnd() && isdigit(PeekScanner()))
|
while(!ScannerAtEnd() && isdigit(PeekScanner()))
|
||||||
AdvanceScanner();
|
AdvanceScanner();
|
||||||
|
|
||||||
if (PeekScanner() == 'x' && isdigit(PeekAheadScanner())) {
|
if (tolower(PeekScanner()) == 'x') {
|
||||||
base = 16;
|
char ahead = tolower(PeekAheadScanner());
|
||||||
AdvanceScanner(); //Consume the 'x'
|
|
||||||
while(!ScannerAtEnd() && isdigit(PeekScanner())) AdvanceScanner();
|
if ((ahead >= 'a' && ahead <= 'f') || isdigit(ahead)) {
|
||||||
|
AdvanceScanner(); //Consume the 'x'
|
||||||
|
|
||||||
|
while(!ScannerAtEnd() && PeekScanner() != '\n' && !IsWhiteSpace(PeekScanner())) {
|
||||||
|
if (isdigit(PeekScanner())) {
|
||||||
|
AdvanceScanner();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tolower(PeekScanner()) >= 'a' && tolower(PeekScanner()) <= 'f') AdvanceScanner();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int length = Position - start;
|
int length = Position - start;
|
||||||
@@ -95,26 +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) {
|
|
||||||
free(lexeme);
|
|
||||||
fprintf(stderr, "Failed to calloc space for the raw numeric value of a token. %s.\n", strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(lexeme, &SourceCode[start], length);
|
memcpy(lexeme, &SourceCode[start], length);
|
||||||
|
|
||||||
*value = strtol(lexeme, NULL, base);
|
Token* token = CreateToken(Line, NumberClass);
|
||||||
|
|
||||||
if (base == 10) return CreateToken(lexeme, value, Line, NUMBER);
|
token->Value.Number = strtol(lexeme, NULL, 0);
|
||||||
|
|
||||||
return CreateToken(lexeme, value, Line, HEX);
|
if (errno != 0) {
|
||||||
|
fprintf(stderr, "[Error] Line %d: Invalid number detected. %s.\n", Line, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
token->Lemexe = lexeme;
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* ParseDirective(void) {
|
Token* ParseDirective(void) {
|
||||||
@@ -135,12 +184,17 @@ Token* ParseDirective(void) {
|
|||||||
|
|
||||||
memcpy(directive, &SourceCode[start], length);
|
memcpy(directive, &SourceCode[start], length);
|
||||||
|
|
||||||
|
Token* token = CreateToken(Line, DirectiveClass);
|
||||||
|
|
||||||
if (strcmp(directive, ".db") == 0) {
|
if (strcmp(directive, ".db") == 0) {
|
||||||
return CreateToken(directive, directive, Line, DB);
|
token->Value.Directive = DB;
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
else if (strcmp(directive, ".org") == 0) {
|
else if (strcmp(directive, ".org") == 0) {
|
||||||
fprintf(stderr, "[Warning] Org is not a supported directive.\n");
|
fprintf(stderr, "[Warning] Org is not a supported directive.\n");
|
||||||
free(directive);
|
free(directive);
|
||||||
|
free(token);
|
||||||
IgnoreLine();
|
IgnoreLine();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -180,7 +234,9 @@ Token* ParseString(void) {
|
|||||||
|
|
||||||
AdvanceScanner(); //Consume the trailing double quote.
|
AdvanceScanner(); //Consume the trailing double quote.
|
||||||
|
|
||||||
Token* token = CreateToken(lexeme, lexeme, Line, STRING);
|
Token* token = CreateToken(Line, CharacterClass);
|
||||||
|
|
||||||
|
token->Lemexe = lexeme;
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@@ -196,7 +252,8 @@ Token* ParseIdentifier(void) {
|
|||||||
|
|
||||||
if (length == 0) return NULL;
|
if (length == 0) return NULL;
|
||||||
|
|
||||||
TokenType type;
|
Mnemonic mnemonics;
|
||||||
|
Registers reg;
|
||||||
char* lexeme = calloc(sizeof(char), length + 1);
|
char* lexeme = calloc(sizeof(char), length + 1);
|
||||||
|
|
||||||
if (!lexeme) {
|
if (!lexeme) {
|
||||||
@@ -206,14 +263,33 @@ Token* ParseIdentifier(void) {
|
|||||||
|
|
||||||
memcpy(lexeme, &SourceCode[start], length);
|
memcpy(lexeme, &SourceCode[start], length);
|
||||||
|
|
||||||
if (IsOpcode(lexeme, &type)) return CreateToken(lexeme, lexeme, Line, type);
|
if (IsOpcode(lexeme, &mnemonics)) {
|
||||||
if (IsRegister(lexeme, &type)) return CreateToken(lexeme, lexeme, Line, type);
|
Token* token = CreateToken(Line, MnemonicClass);
|
||||||
|
|
||||||
|
token->Value.Mnemonic = mnemonics;
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
if (IsRegister(lexeme, ®)) {
|
||||||
|
Token* token = CreateToken(Line, RegisterClass);
|
||||||
|
token->Value.Register = reg;
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
if (lexeme[length - 1] == ':') {
|
if (lexeme[length - 1] == ':') {
|
||||||
lexeme[length - 1] = '\0'; //Bit hacky, but this makes the parser's job a bit easier.
|
lexeme[length - 1] = '\0'; //Bit hacky, but this makes the parser's job a bit easier.
|
||||||
return CreateToken(lexeme, lexeme, Line, LABEL);
|
Token* token = CreateToken(Line, LabelClass);
|
||||||
|
|
||||||
|
token->Lemexe = lexeme;
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateToken(lexeme, lexeme, Line, IDENTIFIER);
|
Token* token = CreateToken(Line, IdentifierClass);
|
||||||
|
|
||||||
|
token->Lemexe = lexeme;
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
char PeekScanner(void) {
|
char PeekScanner(void) {
|
||||||
@@ -251,19 +327,44 @@ int IsPunctuation(char c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int IsWhiteSpace(char c) {
|
||||||
|
switch(c) {
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\v':
|
||||||
|
case '\f':
|
||||||
|
case '\r':
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Token* ParsePunctuation(char c) {
|
Token* ParsePunctuation(char c) {
|
||||||
|
TokenPunctuation punctuation;
|
||||||
|
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case '[':
|
case '[':
|
||||||
return CreateToken("[", NULL, Line, LBRACKET);
|
punctuation = LBracket;
|
||||||
|
break;
|
||||||
case ']':
|
case ']':
|
||||||
return CreateToken("]", NULL, Line, RBracket);
|
punctuation = RBracket;
|
||||||
|
break;
|
||||||
case '(':
|
case '(':
|
||||||
return CreateToken("(", NULL, Line, LPARAM);
|
punctuation = LParan;
|
||||||
|
break;
|
||||||
case ')':
|
case ')':
|
||||||
return CreateToken(")", NULL, Line, RPARAM);
|
punctuation = RParan;
|
||||||
|
break;
|
||||||
case ',':
|
case ',':
|
||||||
return CreateToken(",", NULL, Line, COMMA);
|
punctuation = Comma;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Token* token = CreateToken(Line, PunctuationClass);
|
||||||
|
token->Value.Punctuation = punctuation;
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
#include "../includes/symbols_table.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
SymbolTable* CreateSymbolTable(void){
|
||||||
|
SymbolTable* table = calloc(1, sizeof(SymbolTable));
|
||||||
|
|
||||||
|
if (!table) {
|
||||||
|
fprintf(stderr, "Failed to calloc memory for a SymbolTable. %s.\n", strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
table->Symbols = calloc(SYMBOLSTABLE_DEFAULT_CAPACITY, sizeof(Symbol*));
|
||||||
|
|
||||||
|
if (!table->Symbols) {
|
||||||
|
fprintf(stderr, "Failed to calloc Symbol list. %s.\n", strerror(errno));
|
||||||
|
free(table);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
table->Capacity = SYMBOLSTABLE_DEFAULT_CAPACITY;
|
||||||
|
table->Size = 0;
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol* CreateSymbol(char* name) {
|
||||||
|
Symbol* symbol = calloc(1, sizeof(Symbol));
|
||||||
|
|
||||||
|
if (!symbol) {
|
||||||
|
fprintf(stderr, "Failed to create Symbol '%s'. %s.\n", name, strerror(errno));
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol->Name = name;
|
||||||
|
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolString* CreateSymbolString(char* text) {
|
||||||
|
SymbolString* string = calloc(1, sizeof(SymbolString));
|
||||||
|
|
||||||
|
if (!string) {
|
||||||
|
fprintf(stderr, "Failed to create string data for symbol. %s.\n", strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
string->String = text;
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol* TryGetSymbol(char* name, SymbolTable* table) {
|
||||||
|
if (!name || !table) return NULL;
|
||||||
|
|
||||||
|
for(int i = 0; i < table->Size; i++) {
|
||||||
|
if (strcmp(table->Symbols[i]->Name, name) == 0) return table->Symbols[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol* AddSymbolToTable(char* name, SymbolTable* table) {
|
||||||
|
//if (!name || !value || !table || length == 0) return NULL;
|
||||||
|
|
||||||
|
for(int i = 0; i < table->Size; i++) {
|
||||||
|
if (strcmp(table->Symbols[i]->Name, name) == 0) {
|
||||||
|
//TODO: Do we update or throw some kind of an error?
|
||||||
|
|
||||||
|
return table->Symbols[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (table->Capacity < table->Size + 1) {
|
||||||
|
Symbol** newBlock = realloc(table->Symbols, sizeof(Symbol*) * table->Capacity * 2);//calloc(table->Size * 2, sizeof(Symbol*));
|
||||||
|
|
||||||
|
if (!newBlock) {
|
||||||
|
fprintf(stderr, "Failed to realloc space for a new symbol '%s'. %s.\n", name, strerror(errno));
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
table->Capacity *= 2;
|
||||||
|
table->Symbols = newBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol* symbol = CreateSymbol(name);
|
||||||
|
|
||||||
|
table->Symbols[table->Size] = symbol;
|
||||||
|
table->Size++;
|
||||||
|
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeSymbolTable(SymbolTable* table) {
|
||||||
|
if (!table) return;
|
||||||
|
|
||||||
|
for(int i = 0; i < table->Size; i++) FreeSymbol(table->Symbols[i]);
|
||||||
|
|
||||||
|
free(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeSymbol(Symbol* symbol) {
|
||||||
|
if (!symbol) return;
|
||||||
|
|
||||||
|
free(symbol);
|
||||||
|
}
|
||||||
+3
-7
@@ -1,6 +1,6 @@
|
|||||||
#include "../includes/token.h"
|
#include "../includes/token.h"
|
||||||
|
|
||||||
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) {
|
||||||
@@ -8,10 +8,8 @@ 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;
|
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@@ -19,7 +17,5 @@ Token* CreateToken(char* lexeme, void* value, int lineNumber, TokenType type) {
|
|||||||
void FreeToken(Token* token) {
|
void FreeToken(Token* token) {
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
|
|
||||||
if (token->value && token->type >= STRING) free(token->value);
|
|
||||||
|
|
||||||
free(token);
|
free(token);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user