Compare commits

..
55 Commits
Author SHA1 Message Date
glm94 f38da9cc74 A bit of cleanup. 2022-10-04 21:05:15 +00:00
glm94 33309a2759 Updated the Instruction's structure and updated the Parser accordingly. 2022-10-04 20:37:47 +00:00
glm94 1f7989533b Fixed a bug in the SymbolsTable where it wouldn't update its size. 2022-10-03 20:11:04 -05:00
glm94 cd1258a724 Fixed various Parser bugs. 2022-10-03 19:58:44 -05:00
glm94 be91e3c112 Updated the parser to better handle parameters, sort of and including a string length assembly program to use as a test for the whole assembler. 2022-10-03 21:26:28 +00:00
glm94 706f480e31 The Scanner will now check for empty lines (is the previous token and the current token a new line?) and simply not emit a NewLine Token. 2022-10-03 19:40:00 +00:00
glm94 a949007c75 Updated the ISA so the program will correctly see things like 'load', 'inc' and 'dec'. 2022-10-03 16:56:39 +00:00
glm94 a0d5d62a34 Fixed a bug in the Scanner when parsing a hex number, still not super robust but it'll work. 2022-10-03 15:20:31 +00:00
glm94 f7cd87f13f Started reworking the Parser to simplify how instructions will be represented. It will act like a 'first pass' that will do grammar checks but not verify the parameters of the opcodes. 2022-10-02 22:54:18 -05:00
glm94 55f4c32764 Missed this for the Scanner fix. 2022-10-02 22:12:16 -05:00
glm94 097eca383b Fixed a bug with the Scanner adding a blank line via a single NewLine Token when a file starts with a block of comments. 2022-10-01 20:43:55 -05:00
glm94 984683bfc5 Minor adjustment to Figure 1.1 2022-09-29 22:57:12 -05:00
glm94 0f42ad2997 Updated the ISA and added links in the table of contents. 2022-09-29 22:11:19 -05:00
glm94 63438b551b Got the scanner running again. Seems to be picking up punctuation, labels, identifiers and strings as expected. 2022-09-29 21:32:08 -05:00
glm94 e94e486e18 More refinements to the loading data instructions. I am truly bad at this whole thing... 2022-09-29 20:42:37 +00:00
glm94 2b71ac05a0 Added a note about a proposal regarding assembly language design. 2022-09-27 17:46:50 +00:00
glm94 02cf72902e Updated the load instructions. 2022-09-26 22:13:48 -05:00
glm94 afa84076c8 Added a command to make generating an opcode table a one liner. Updated the ISA. 2022-09-23 19:36:27 +00:00
glm94 925f7703d6 Updated the ISA, hopefully I can get this all put together in a thought out way. 2022-09-22 20:49:20 +00:00
glm94 a82a4c23ad Updated the docs. 2022-09-21 21:44:38 -05:00
glm94 f5c82d1c36 Added a LaTex document to put in writing how the machine should behave. 2022-09-21 16:23:11 +00:00
glm94 0b58e0124f Some refactoring to update everything to use the new structures and some new considerations for how Symbols and Instructions shoudl be represented. 2022-09-15 22:14:38 -05:00
glm94 2ae60a607c Incomplete, but I want to make sure the ideas I have here don't get wiped. Sadly this commit won't compile. 2022-09-15 21:29:27 +00:00
glm94 6d17dffcdf Added a SymbolTable object (untested at the moment) and redefined the Symbol object. I think when a Symbol is made only the size of it should matter to the code that will assemble the final binary. 2022-09-08 20:56:02 +00:00
glm94 2518214585 Added a length attribute to the symbol. 2022-09-06 14:15:45 +00:00
glm94 7004fff659 This feels like a trainwreck but eh. Changed the way the opcodes are managed. Hopefully this is the right direction when I add support for multiple ASM files. 2022-09-01 18:46:59 +00:00
glm94 13f8ff194b Smoothbrain indeed... 2022-08-30 22:48:49 -05:00
glm94 dac01ffd0c Changed the TokenClass from opcode to nomic, a less smoothbrain name IMO and also frees up Opcode for a better use later on. 2022-08-30 22:06:50 -05:00
glm94 3c7056c5e6 The main function will now write out the output of the parser. 2022-08-29 21:23:02 +00:00
glm94 6c7b8d5356 Fixed a bug where CMP REG, REG wouldn't get encoded and a disassembler bug related to said CMP bug. 2022-08-29 19:29:34 +00:00
glm94 5f437b6869 Both the assembler and the disassembler should now support all the instructions I've layed out thus far. 2022-08-29 18:51:48 +00:00
glm94 e3b4293314 Fixed a bug in the parser where the size of the binary was too big. 2022-08-29 18:02:11 +00:00
glm94 ae1e73e00f Fixed a bug to correct the location of symbols in the heap. 2022-08-29 16:00:02 +00:00
glm94 7385a807a5 Created a basic binary format to help guide the disassembler. 2022-08-29 15:57:14 +00:00
glm94 0d3f8a460e Added more instructions for the parser to emit and refactored the code in doing so. 2022-08-28 15:37:56 -05:00
glm94 c2111e2b88 Added support for the ADD and SUB opcodes to the disassembler. 2022-08-28 13:08:18 -05:00
glm94 8e9d1aefe8 Fixed some disassembler issues. At least some instuctions are being disassembled correctly. 2022-08-26 21:43:03 -05:00
glm94 0785f21805 Added a disassembler which is still very buggy. Also fixed some bugs with the opcode mask getting function. 2022-08-26 21:41:02 +00:00
glm94 e4a191a17e Refined the encoding some more. 2022-08-26 19:00:37 +00:00
glm94 eb5e2c506e Got the start of encoding opcodes. 2022-08-26 18:27:41 +00:00
glm94 0d060248cb Forgot about the bloody IN instruction... 2022-08-25 21:01:35 -05:00
glm94 80bea6f1a8 I'm dumb, fixed the CMP opcode overlap.. 2022-08-25 20:57:33 -05:00
glm94 a96f485da6 I believe I have the bit patterns for my opcodes worked out. 2022-08-25 20:45:46 -05:00
glm94 88d550f344 Added unconditional jump opcode to my comment section. 2022-08-25 20:27:25 -05:00
glm94 0e53f9798f Added a distinction between constant numbers and what are effectively memory addresses (i.e. strings and labels). 2022-08-25 19:47:16 -05:00
glm94 03d5660677 Seems I fixed the memory offset bugs, so far anyway... 2022-08-25 19:54:47 +00:00
glm94 4f6d5f652e Made use of the Symbols Table, and started the proccess of determining the memory location of opcodes and variables. 2022-08-25 19:06:05 +00:00
glm94 64326937b1 Added a LineEnd token type. 2022-08-25 18:37:25 +00:00
glm94 89ab951c6a Refactored the parsing code just a touch. 2022-08-24 21:23:14 +00:00
glm94 947de1d14c Added support for declaring a variable with the '.db' directive. Address calculations still need to be done, but at the very least the variable's name is showing up in the symbols table. 2022-05-16 15:17:19 +00:00
glm94 3c4cce0883 Added assembler directives as a class of token. 2022-05-16 14:27:49 +00:00
glm94 5265666178 Got the Parser to, so far, correctly (minus memory leaks) parse out and report errors with opcodes and their parameters. 2022-05-12 23:16:02 -05:00
glm94 2de3538d80 Parser is now mostly setup for the 'peek and advance' pattern. Still having infinite loop issues somewhere though. 2022-05-12 21:30:02 +00:00
glm94 72525959f6 Reworked the tokens to include a broad class to make parameter matching a bit easier, and removed the hexadecimal distinction. 2022-05-12 20:26:14 +00:00
glm94 72abf6c4ab Started work on rewriting the Parser. 2022-05-10 21:03:09 +00:00
15 changed files with 1166 additions and 225 deletions
+3
View File
@@ -1,3 +1,6 @@
assm
obj/
bin/
*.bin
docs/*
!docs/*.tex
+144
View File
@@ -0,0 +1,144 @@
\documentclass[a4paper,12pt]{book}
\usepackage{tikz}
\usepackage{hyperref}
\hypersetup{
linktoc=all
}
\title{Unnamed Machine}
\author{A Very Terrible 16-bit Machine}
\newcommand{\OpcodeTable}[4] {
\begin{tabular}{ c c c c }
\hline
Opcode & Mnemonic & Operand 1 & Operand 2 \\
\hline\hline
#1 & #2 & #3 & #4 \\
\hline
\end{tabular}
}
\begin{document}
\maketitle
\tableofcontents
\chapter{Overview}
\section{Introduction}
This is a very poorly thought out 16-bit machine, but you've got to start somewhere. Currently debating between a CPU status register, 80x86 style, or just placing arithmetic results into a predetermined register. This is more of a loadstore architecture to try and keep the instruction set simple. The machine will be big-endian.
\section{Registers}
The following are the general purpose registers that can be used.
\begin{itemize}
\item[] R1
\item[] ...
\item[] R8
\end{itemize}
Additionally, there will be a special status register that will be a signed 16 bit register that the compare and jump instructions will read or write to when determining what action, if any, they'll take.
\section{Memory Model}
Memory will be implicitly mapped I/O. The bottom 3201 bytes of memory will be reserved for the keyboard input and graphics.
A single byte is reserved for the keyboard's input. The current key will be stored in byte 0xF37E, with the most significant bit being a flag indicating that the keyboard
is ready to be read from. This means that the character encoding is actually 7 bits.
Video memory starts at 0xF37F (62335 decimal), and every byte represents an ASCII character in monochrome.
\begin{figure}[!htb]
\centering
\begin{tikzpicture}
\fill[gray!5] (0,0)rectangle(5,10);
%\draw (0,10) .. controls (-2,6) and (-2,4) .. (0,1);
%\draw (0,10) arc (0:180:3cm);
\draw (0,10) -- (5,10);
\draw (0,1) -- node[above] {Video 0xF37F} (5,1);
\draw (0,0) -- (5,0);
\node[label=right:Top 0x0000] at (5,10) {};
\node[label=right:Bottom 0xFFFF] at (5,0) {};
\end{tikzpicture}
\caption{Memory Layout}
\end{figure}
\chapter{Instruction Set Architecture}
\section{Instruction Encoding}
Instructions are fixed to exactly one byte (8 bits).
Instructions that work with two operands the register for operand one will be encoded in the three least significant bits. So an instruction with format XXXX X000 will use Register 1 and so forth all the way to XXXX X111, which will be Register 8.
%https://tex.stackexchange.com/questions/32598/force-latex-image-to-appear-in-the-section-in-which-its-declared
\begin{figure}[!htb]
\centering
\begin{tabular}{ c c }
\hline
Instruction & Register \\
\hline\hline
0000 0 & 000 \\
\hline
\end{tabular}
\caption{Encoding Layout}
\end{figure}
\section{Notes}
For the opcodes that load or store data at the assembly language level we could have the mnemonics
"store" and "load" and have the assembler pick the opcode based on the inclusion of the word "byte"
or "word" for two bytes. That would make the assembly easier to read but put a bit more work on the
assembler.
\section{STOB (Store Byte)}
\OpcodeTable{0x20}{stob}{Register}{Address}\\[6pt]
Stores a single byte (the lower nibble) from a register to a memory address.
\section{STOW (Store Machine Word)}
\OpcodeTable{0x20}{stow}{Register}{Address}\\[6pt]
Stores a machine word from a register to a memory address.
\section{LAA (Load Absolute Address)}
\OpcodeTable{0x00}{laa}{Register}{Address}\\[6pt]
Loads an address (2 bytes) into the register.
\section{LODB (Load Byte)}
\OpcodeTable{0x20}{lodb}{Register}{Register}\\[6pt]
Loads a single byte into a register from a memory address in the second operand register, zeroing out the high nibble.
\section{LODW (Load Machine Word)}
\OpcodeTable{0x20}{lodw}{Register}{Register}\\[6pt]
Loads a word into a register from a memory address in the second operand register.
\section{LODWI (Load Immediate Word)}
\OpcodeTable{0x00}{lodwi}{Register}{Constant}\\[6pt]
Loads an immediate machine word into the register clearing the high nibble if the value is less then 256.
\section{CMP (Compare)}
\OpcodeTable{0x20}{cmp}{Register}{Register}\\[6pt]
Compares two registers and somewhere sets a result in the status register.
\section{CMPI (Compare Immediate)}
\OpcodeTable{0x00}{cmpi}{Register}{Constant}\\[6pt]
Compares an immediate 2 byte value to the contents of a register setting the status register accordingly.
\section{ADD (Add)}
\OpcodeTable{0x20}{add}{Register}{Register}\\[6pt]
Performs addition on a register with a value from another (or the same) register.
\section{SUB (Subtract)}
\OpcodeTable{0x20}{sub}{Register}{Register}\\[6pt]
Performs subtraction on a register with a value from another (or the same) register.
\section{JMP (Jump)}
\OpcodeTable{0x20}{jmp}{Address}{None}\\[6pt]
Jumps unconditionally to a memory address.
\section{JZ (Jump if Zero)}
\OpcodeTable{0x20}{jz}{Register}{None}\\[6pt]
Jumps to a memory address if the status flag is zero.
\section{JG (Jump if Greater Than)}
\OpcodeTable{0x70}{jg}{Address}{None}\\[6pt]
Jump to the Address if the status flag is greater than zero.
\section{JL (Jump if Less Than)}
\OpcodeTable{0x00}{jl}{Address}{None}\\[6pt]
Jumps to the address if the status flag is less than zero.
\section{AND (Logical AND)}
\OpcodeTable{0x00}{and}{Register}{Register}\\[6pt]
Logical ANDs the two registers together storing the result in operand 1.
\section{XOR (Logical Exclusive OR)}
\OpcodeTable{0x00}{xor}{Register}{Register}\\[6pt]
Logical XORs the two registers together storing the result in operand 1.
\section{OR (Logical OR)}
\OpcodeTable{0x00}{or}{Register}{Register}\\[6pt]
Logical ORs the two registers together storing the result in operand 1.
\section{NOT (Logical Negation)}
\OpcodeTable{0x00}{not}{Register}{None}\\[6pt]
Inverts the bits of the target register.
\section{SHR (Shift Right)}
\OpcodeTable{0x00}{shr}{Register}{Constant}\\[6pt]
Bit-wise shifts the contents of the register right Constant number of times.
\section{SHL (Shift Left)}
\OpcodeTable{0x00}{shl}{Register}{Constant}\\[6pt]
Bit-wise shifts the contents of the register left Constant number of times.
\section{INC (Increment)}
\OpcodeTable{0x00}{inc}{Register}{None}\\[6pt]
Increments the contents of the register by one. Over-flows will not be reported.
\section{DEC (Decrement)}
\OpcodeTable{0x00}{dec}{Register}{None}\\[6pt]
Decrements the contents of the register by one. Under-flows will not be reported.
\section{NOP (No Operation)}
\OpcodeTable{0x00}{nop}{None}{None}\\[6pt]
Skips a clock cycle, incrementing the program counter.
\end{document}
+9
View File
@@ -0,0 +1,9 @@
#ifndef DIASSEMBLER_H
#define DIASSEMBLER_H
#include "parser.h"
//void Disassemble(unsigned char image[HIGHMEMORY]);
#endif
+35 -22
View File
@@ -2,34 +2,47 @@
#define OPCODES_H
#include <string.h>
#include "token.h"
#define OPCODECOUNT 10
#define REGISTERCOUNT 8
#include "symbols_table.h"
typedef enum {
None = 0,
Reg,
Imm8,
Imm16
} ParameterType;
R1, R2, R3, R4, R5, R6, R7, R8
} Registers;
typedef enum {
ADD, SUB, JZ, INT, YLD, RET,
CMP, NOP, JMP, CALL, LOAD, JE, INC, DEC, LOADB
} Mnemonic;
typedef enum {
NoParameter,
ConstantParameter,
AddressParameter,
RegisterParameter
} OpcodeParameter;
typedef struct {
char* lexeme;
TokenType op;
ParameterType parameter_one;
ParameterType parameter_two;
} OpCode;
OpcodeParameter ParameterType;
OpcodeParameter InterpretedAs;
union {
int Number; //ConstanrParam
Registers Register; //Register param
Symbol* Symbol; //Address param
} Value;
} Parameter;
typedef struct {
char* lexeme;
TokenType type;
} Register;
Mnemonic Mnemonic;
Parameter* ParameterOne;
Parameter* ParameterTwo;
} Instruction;
extern OpCode opcodes[OPCODECOUNT];
extern Register registers[REGISTERCOUNT];
int IsOpcode(const char*, TokenType*);
int IsRegister(const char*, TokenType*);
Instruction* CreateInstruction(Mnemonic mnemonic);
Parameter* CreateParameter(OpcodeParameter parameterType);
void FreeInstruction(Instruction* instruction);
int IsOpcode(const char*, Mnemonic*);
int IsRegister(const char*, Registers*);
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]);
unsigned char GetInstructionMask(Mnemonic type);
#endif
+13 -1
View File
@@ -1,11 +1,23 @@
#ifndef PARSER_H
#define PARSER_H
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "list.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
+40
View File
@@ -0,0 +1,40 @@
#ifndef SYMBOLSTABLE_H
#define SYMBOLSTABLE_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* Name;
int Length;
int Resolved;
union {
char* Text;
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, void* value, int length, SymbolTable* table);
void FreeSymbolTable(SymbolTable* table);
void FreeSymbol(Symbol* symbol);
#endif
+45 -29
View File
@@ -5,40 +5,56 @@
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include "opcodes.h"
typedef enum {
PLUS,
MINUS,
STAR,
SLASH,
POWER,
LPARAM,
RPARAM,
LBRACKET,
RBracket,
COMMA,
STRING,
IDENTIFIER,
LABEL,
NUMBER,
HEX,
//Keywords
DB, ORG,
//Opcodes
COPY, ADD, SUB, JZ, INT, YLD, RET,
CMP, IN, OUT,
//Registers
R1, R2, R3, R4, R5, R6, R7, R8
} TokenType;
Plus = '+',
Minus = '-',
Star = '*',
Slash = '/',
Power = '^',
LParan = '(',
RParan = ')',
LBracket = '[',
RBracket = ']',
Comma = ',',
NewLine = '\n'
} TokenPunctuation;
typedef enum {
DB,
Origin,
Byte
} Directive;
typedef enum {
RegisterClass = 0,
NumberClass = 1,
CharacterClass = 2,
MnemonicClass = 4,
DirectiveClass = 8,
PunctuationClass = 16,
IdentifierClass = 32,
LabelClass = 64,
AddressClass = LabelClass | IdentifierClass
} TokenClass;
typedef struct {
TokenType type;
char* lexeme;
void* value;
int line;
char* Lemexe;
TokenClass Class;
int LineNumber;
int EndOfFile;
union {
TokenPunctuation Punctuation;
Registers Register;
Mnemonic Mnemonic;
Directive Directive;
int Number;
} Value;
} Token;
Token* CreateToken(char*, void*, int, TokenType);
void FreeToken(Token*);
Token* CreateToken(int lineNumber, TokenClass tokenClass);
void FreeToken(Token* token);
#endif
+24 -42
View File
@@ -1,45 +1,27 @@
.org 0x100
.db video_start 0xF37F
.db msg "Hello, world!", 0
.db more_stuff "And yet another string!", 0
copy r1, msg
copy r2, 0
loop:
cmp r1, 0
jz loop
add r1, 1
mov r1, 5 ; move the immediate value 5 into r1
add r1,5 ; add 5 into r1
int 21 ; maybe that will call some string drawing BIOS-like routine
load r1, [msg] ; Because the lod* instructions can't load an address
; from anything but a register, this becomes laa r1, [msg]
;Routine: string_length
;In: String address in r1
;Out: Length in R2
string_length:
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
; 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
View File
@@ -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
View File
@@ -1,3 +1,4 @@
#include <bits/types/FILE.h>
#include <stdlib.h>
#include <stdio.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;
List* list = GenerateTokenList(source_code);
char mnemonic[12];
// for(int i = 0; i < list->size; i++) {
// Token* t = (Token*) list->content[i];
for(int i = 0; i < list->size; i++) {
Token* t = (Token*) list->content[i];
// printf("[%i] '%s'", t->type, t->lexeme);
// if (t->type == LABEL) printf("*");
// printf("\n");
// }
if (t->EndOfFile) {
printf("EOF\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);
}
+181 -31
View File
@@ -2,36 +2,167 @@
#include <stdlib.h>
#include <string.h>
OpCode opcodes[OPCODECOUNT] = {
{ "copy", COPY, Reg, Reg | Imm8 | Imm16 },
{ "add", ADD, Reg, Reg | Imm8 | Imm16 },
{ "sub", SUB, Reg, Reg | Imm8 | Imm16 },
{ "jz", JZ, Imm8 | Imm16, None },
{ "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}
#define OPCODECOUNT 15
struct _instruction {
char* Name;
Mnemonic Mnemonic;
};
Register registers[REGISTERCOUNT] = {
{ "r1", R1 },
{ "r2", R2 },
{ "r3", R3 },
{ "r4", R4 },
{ "r5", R5 },
{ "r6", R6 },
{ "r7", R7 },
{ "r8", R8 }
struct _instruction instructions[OPCODECOUNT] = {
{ "add", ADD },//, Reg, Reg | Constant },
{ "sub", SUB },//, Reg, Reg | Constant },
{ "jz", JZ },//, Address, None },
{ "int", INT },//, Constant, None },
{ "yld", YLD },//, None, None },
{ "ret", RET },//, None, None },
{ "cmp", CMP },//, Reg, Reg | Constant },
{ "inc", INC },//, Constant | Reg, None},
{ "dec", DEC },//, None, None},
{ "nop", NOP },//, None, None},
{ "jmp", JMP },//, Address, None},
{ "call", CALL },//, Address, None}
{ "load", LOAD },
{ "je", JE },
{ "loadb", LOADB}
};
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;
for(int i = 0; i < OPCODECOUNT; i++) {
if (strcmp(opcodes[i].lexeme, text) == 0) {
*opcode = opcodes[i].op;
if (strcmp(instructions[i].Name, text) == 0) {
if (opcode) *opcode = instructions[i].Mnemonic;
return 1;
}
}
@@ -39,15 +170,34 @@ int IsOpcode(const char* text, TokenType* opcode) {
return 0;
}
int IsRegister(const char* text, TokenType* reg) {
int IsRegister(const char* text, Registers* reg) {
if (!text) return 0;
for(int i = 0; i < REGISTERCOUNT; i++) {
if (strcmp(registers[i].lexeme, text) == 0) {
*reg = registers[i].type;
return 1;
}
}
int length = strlen(text);
Registers r = R8;
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;
}
}
+215 -62
View File
@@ -1,89 +1,242 @@
#include "../includes/parser.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
Token* token;
int address;
} Symbol;
const List* TokensList;
int CurrentToken = 0;
Symbol* CreateSymbol(Token*, int);
void AddSymbol(Token*);
void PrintSymbols(void);
Token* GetSymbol(char*);
List* SymbolsTable;
unsigned int ProgramCounter = 0;
void HandleOperation(void);
void HandleAssemblerDirective(void);
void AdvanceParser(void);
void IgnoreParserLine(void);
Token* PeekToken(void);
int ParserAtEnd(void);
IRState MachineState;
void ParseTokens(List* tokens) {
SymbolsTable = CreateList();
IRState* ParseTokens(List* tokens) {
if (!tokens) return NULL;
for(int i = 0; i < tokens->size; i++){
Token* t = tokens->content[i];
TokensList = tokens;
switch(t->type) {
case IDENTIFIER:
case LABEL:
AddSymbol(t);
MachineState.SymbolsTable = CreateSymbolTable();
MachineState.Instructions = CreateList();
while(!ParserAtEnd()) {
Token* t = PeekToken();
switch(t->Class) {
case DirectiveClass: //Maybe these should be ignored, let another process handle that.
IgnoreParserLine();
break;
case STRING:
ProgramCounter += strlen(t->lexeme);
case MnemonicClass:
HandleOperation();
break;
case NUMBER:
case HEX:
if ((long) t->value < 256) ProgramCounter += 1;
else ProgramCounter += 2;
case LabelClass:
AdvanceParser();
AddSymbolToTable(t->Lemexe, NULL, strlen(t->Lemexe), MachineState.SymbolsTable)->Resolved = 1;
AdvanceParser(); //Consume the NewLine
break;
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;
}
}
PrintSymbols();
DestroyList(SymbolsTable);
printf("Program Counter: %d\n", ProgramCounter);
if (MachineState.SymbolsTable->Size > 0) PrintSymbols();
for(int i = 0; i < MachineState.Instructions->size; i++) {
char mn[12];
Instruction* ins = MachineState.Instructions->content[i];
GetMnemonicText(ins->Mnemonic, mn);
printf("%s\n", mn);
}
return &MachineState;
}
Parameter* GetParameterType() {
Token* token = PeekToken();
Symbol* symbol = NULL;
Parameter* param = CreateParameter(NoParameter);
switch(token->Class) {
case RegisterClass:
param->ParameterType = RegisterParameter;
param->InterpretedAs = RegisterParameter;
param->Value.Register = token->Value.Register;
AdvanceParser();
return param;
case LabelClass:
case IdentifierClass:
param->ParameterType = AddressParameter;
param->InterpretedAs = AddressParameter;
symbol = TryGetSymbol(token->Lemexe, MachineState.SymbolsTable);
if (!symbol) symbol = AddSymbolToTable(token->Lemexe, token->Lemexe, strlen(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, NULL, strlen(token->Lemexe), MachineState.SymbolsTable);
param->Value.Symbol = symbol;
}
else {
fprintf(stderr, "[Error] Line %d: Expected identifier, constant number or register.\n", token->LineNumber);
IgnoreParserLine();
//return NULL;
exit(1);
}
AdvanceParser(); //Consume the parameter it self.
token = PeekToken();
if (token->Class != PunctuationClass || token->Value.Punctuation != RBracket) {
fprintf(stderr, "[Error] Line %d: Expected closing bracket.\n", token->LineNumber);
exit(1);
}
AdvanceParser(); // ]
return param;
case NumberClass:
param->ParameterType = ConstantParameter;
param->InterpretedAs = ConstantParameter;
param->Value.Number = token->Value.Number;
AdvanceParser();
return param;
default:
break;
}
return param;
}
void HandleOperation() {
Token* token = PeekToken();
char mn[12];
Instruction* ins = CreateInstruction(token->Value.Mnemonic);
GetMnemonicText(ins->Mnemonic, mn);
AdvanceParser();
//No parameters here, we have a line break.
if (PeekToken()->EndOfFile || (PeekToken()->Class == PunctuationClass && PeekToken()->Value.Punctuation == NewLine)) {
goto InsertInstruction;
}
ins->ParameterOne = GetParameterType();
if (ins->ParameterOne->ParameterType == NoParameter) {
//This would be an error if the next token isn't a line break.
if (PeekToken()->Class != PunctuationClass || PeekToken()->Value.Punctuation != NewLine) {
fprintf(stderr, "[Error] Line %d: Syntax error, expected line break but got %s.\n", token->LineNumber, token->Lemexe);
exit(1);
}
goto InsertInstruction;
}
if (PeekToken()->Class == PunctuationClass && PeekToken()->Value.Punctuation == NewLine) {
goto InsertInstruction;
}
if (PeekToken()->Class != PunctuationClass || PeekToken()->Value.Punctuation != Comma) {
//Syntax error
fprintf(stderr, "[Error] Line %d: Expected comma.\n", token->LineNumber);
exit(1);
}
AdvanceParser(); //Consume the comma
ins->ParameterTwo = GetParameterType();
InsertInstruction:
AddListItem(ins, sizeof(Instruction), MachineState.Instructions);
AdvanceParser(); //Consume the line break
free(ins);
}
void PrintSymbols(void) {
printf("-----SYMBOLS-----\n");
for(int i = 0; i < SymbolsTable->size; i++) {
Symbol* symbol = SymbolsTable->content[i];
printf("[%#08X] %s\n", symbol->address, symbol->token->lexeme);
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 AddSymbol(Token* token) {
if (!token) return;
if (token->type != IDENTIFIER && token->type != LABEL) return;
void AdvanceParser(void) {
if (ParserAtEnd()) return;
for(int i = 0; i < SymbolsTable->size; i++) {
Symbol* s = SymbolsTable->content[i];
CurrentToken++;
}
if (strcmp(s->token->lexeme, token->lexeme) == 0) return;
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();
}
Symbol* symbol = CreateSymbol(token, ProgramCounter);
AddListItem(symbol, sizeof(Symbol), SymbolsTable);
}
Token* GetSymbol(char* name) {
if (!name) return NULL;
return NULL;
}
Symbol* CreateSymbol(Token* token, int offset) {
Symbol* symbol = calloc(1, sizeof(Symbol));
if (!symbol) {
return NULL;
}
symbol->token = token;
symbol->address = offset;
return symbol;
}
+129 -28
View File
@@ -1,13 +1,16 @@
#include "../includes/scanner.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
const char* SourceCode;
int Line = 0;
int Line = 1;
int Position = 0;
int SourceLength = 0;
int ScannerAtEnd(void);
int IsPunctuation(char);
int IsWhiteSpace(char);
char PeekScanner(void);
char PeekAheadScanner(void);
void AdvanceScanner(void);
@@ -34,14 +37,35 @@ List* GenerateTokenList(const char* source) {
case ' ':
case '\r':
case '\t':
case '\v':
case '\f':
AdvanceScanner();
break; //Ignore whitespace
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();
Line++;
break;
case ';':
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;
case '.': //directive like ".org" or ".db"
token = ParseDirective();
@@ -74,20 +98,45 @@ List* GenerateTokenList(const char* source) {
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;
}
Token* ParseNumber(void) {
int start = Position;
int base = 10;
while(!ScannerAtEnd() && isdigit(PeekScanner()))
AdvanceScanner();
if (PeekScanner() == 'x' && isdigit(PeekAheadScanner())) {
base = 16;
AdvanceScanner(); //Consume the 'x'
while(!ScannerAtEnd() && isdigit(PeekScanner())) AdvanceScanner();
if (tolower(PeekScanner()) == 'x') {
char ahead = tolower(PeekAheadScanner());
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;
@@ -95,26 +144,26 @@ Token* ParseNumber(void) {
if (length == 0) return NULL;
char* lexeme = calloc(sizeof(char), length + 1);
long* value = calloc(1, sizeof(long));
if (!lexeme) {
fprintf(stderr, "Failed to calloc space for number. %s.\n", strerror(errno));
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);
*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) {
@@ -135,12 +184,17 @@ Token* ParseDirective(void) {
memcpy(directive, &SourceCode[start], length);
Token* token = CreateToken(Line, DirectiveClass);
if (strcmp(directive, ".db") == 0) {
return CreateToken(directive, directive, Line, DB);
token->Value.Directive = DB;
return token;
}
else if (strcmp(directive, ".org") == 0) {
fprintf(stderr, "[Warning] Org is not a supported directive.\n");
free(directive);
free(token);
IgnoreLine();
return NULL;
}
@@ -180,7 +234,9 @@ Token* ParseString(void) {
AdvanceScanner(); //Consume the trailing double quote.
Token* token = CreateToken(lexeme, lexeme, Line, STRING);
Token* token = CreateToken(Line, CharacterClass);
token->Lemexe = lexeme;
return token;
}
@@ -196,7 +252,8 @@ Token* ParseIdentifier(void) {
if (length == 0) return NULL;
TokenType type;
Mnemonic mnemonics;
Registers reg;
char* lexeme = calloc(sizeof(char), length + 1);
if (!lexeme) {
@@ -206,14 +263,33 @@ Token* ParseIdentifier(void) {
memcpy(lexeme, &SourceCode[start], length);
if (IsOpcode(lexeme, &type)) return CreateToken(lexeme, lexeme, Line, type);
if (IsRegister(lexeme, &type)) return CreateToken(lexeme, lexeme, Line, type);
if (IsOpcode(lexeme, &mnemonics)) {
Token* token = CreateToken(Line, MnemonicClass);
token->Value.Mnemonic = mnemonics;
return token;
}
if (IsRegister(lexeme, &reg)) {
Token* token = CreateToken(Line, RegisterClass);
token->Value.Register = reg;
return token;
}
if (lexeme[length - 1] == ':') {
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) {
@@ -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) {
TokenPunctuation punctuation;
switch(c) {
case '[':
return CreateToken("[", NULL, Line, LBRACKET);
punctuation = LBracket;
break;
case ']':
return CreateToken("]", NULL, Line, RBracket);
punctuation = RBracket;
break;
case '(':
return CreateToken("(", NULL, Line, LPARAM);
punctuation = LParan;
break;
case ')':
return CreateToken(")", NULL, Line, RPARAM);
punctuation = RParan;
break;
case ',':
return CreateToken(",", NULL, Line, COMMA);
punctuation = Comma;
break;
default:
return NULL;
}
Token* token = CreateToken(Line, PunctuationClass);
token->Value.Punctuation = punctuation;
return token;
}
+98
View File
@@ -0,0 +1,98 @@
#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, void* value, int length) {
Symbol* symbol = calloc(1, sizeof(Symbol));
if (!symbol) {
fprintf(stderr, "Failed to create Symbol '%s'. %s.\n", name, strerror(errno));
return NULL;
}
symbol->Length = length;
symbol->Name = name;
//symbol->Value = value;
return symbol;
}
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, void* value, int length, 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, value, length);
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
View File
@@ -1,6 +1,6 @@
#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));
if (!token) {
@@ -8,10 +8,8 @@ Token* CreateToken(char* lexeme, void* value, int lineNumber, TokenType type) {
return NULL;
}
token->type = type;
token->line = lineNumber;
token->lexeme = lexeme;
token->value = value;
token->Class = tokenClass;
token->LineNumber = lineNumber;
return token;
}
@@ -19,7 +17,5 @@ Token* CreateToken(char* lexeme, void* value, int lineNumber, TokenType type) {
void FreeToken(Token* token) {
if (!token) return;
if (token->value && token->type >= STRING) free(token->value);
free(token);
}