Lots of changes and too much dragging my feet on this. But I think this is going in the right direction now.
This commit is contained in:
@@ -35,7 +35,7 @@ clean:
|
||||
rm -rf $(BINDIR)/* $(OBJDIR)/*
|
||||
|
||||
test:
|
||||
$(BIN) misc/another_test.asm
|
||||
$(BIN) examples/strlen.asm
|
||||
|
||||
disass:
|
||||
objdump -S --disassemble $(OBJDIR)/$(FILE).o > $(OBJDIR)/$(FILE).s
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace string 67; my string namespace here
|
||||
|
||||
word FRAMEBUFFER 0x00200500
|
||||
|
||||
asciiz Msg "Hello World!"
|
||||
; fn effectively is an "Append to Namespace" command, ie string + "." + _start
|
||||
fn _start:
|
||||
mov FRAMEBUFFER, r32 ; imm, r
|
||||
mov msg, r1 ; imm, r
|
||||
call strlen ; result into r2
|
||||
mov 0, r4 ; counter
|
||||
loop:
|
||||
mov byte [r1], r3 ; read char into r3
|
||||
cmp r3, 0 ; NUL byte?
|
||||
je end
|
||||
mov byte r3, [r32] ; Write char to frame buffer
|
||||
inc r32 ; Next space in framebuffer
|
||||
inc r4 ; inc counter
|
||||
inc r1 ; inc pointer to msg
|
||||
jmp loop
|
||||
end: ;At the moment this just writes Msg to the framebuffer.
|
||||
ret
|
||||
|
||||
; Clobbers r2, r3
|
||||
; Params: r1 - string pointer
|
||||
; Returns: r2, string length
|
||||
fn strlen:
|
||||
mov 0, r2 ; Set the length to zero
|
||||
loop:
|
||||
mov byte [r1], r3 ; mov char into r3
|
||||
cmp r3, 0 ; NUL byte?
|
||||
je end
|
||||
inc r1 ; next char
|
||||
inc r2 ; length++
|
||||
jmp loop
|
||||
end:
|
||||
ret
|
||||
+4
-2
@@ -2,15 +2,17 @@
|
||||
#define ARRAY_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct _array {
|
||||
int Capacity;
|
||||
int Size;
|
||||
size_t Capacity;
|
||||
size_t Size;
|
||||
void** Items;
|
||||
} Array;
|
||||
|
||||
Array* ArrayCreate(void);
|
||||
bool ArrayAdd(Array* array, void* item);
|
||||
void* ArrayPeek(Array* array);
|
||||
void* ArrayIndex(Array* array, size_t index);
|
||||
|
||||
#endif
|
||||
@@ -1,4 +0,0 @@
|
||||
#ifndef AST_H
|
||||
#define AST_H
|
||||
|
||||
#endif
|
||||
+4
-4
@@ -2,10 +2,10 @@
|
||||
#define KEYWORDS_H
|
||||
|
||||
typedef enum {
|
||||
FN, ORG, NAMESPACE, DB, CONST
|
||||
} Keyword;
|
||||
FUNCTION, NAMESPACE, ASCIIZ, ASCII, WORD, SHORT, BYTE
|
||||
} Keywords;
|
||||
|
||||
int IsKeyword(const char* text, Keyword* keyword);
|
||||
void GetKeywordText(Keyword keyword, char buffer[16]);
|
||||
int IsKeyword(const char* text, Keywords* keyword);
|
||||
void GetKeywordText(Keywords keyword, char buffer[16]);
|
||||
|
||||
#endif
|
||||
+6
-5
@@ -6,17 +6,18 @@
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum {
|
||||
R1 = 0, R2, R3, R4, R5, R6, R7, R8 = 7
|
||||
R1 = 1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19,
|
||||
R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, R30, R31, R32, RBP, RSP, RIP
|
||||
} Registers;
|
||||
|
||||
typedef enum {
|
||||
ADD = 0x01, SUB, MUL, DIV, MOV, AND, OR, XOR, NOT, SHL, SHR, NOP, CMP, JMP, JZ, JG, JL,
|
||||
OUTB, INB, HLT, CLI, ENI, INT, LIVT, PUSHA, POPA, CALL, RET, PUSH, POP
|
||||
} Mnemonic;
|
||||
} Mnemonics;
|
||||
|
||||
int IsOpcode(const char*, Mnemonic*);
|
||||
int IsOpcode(const char*, Mnemonics*);
|
||||
int IsRegister(const char*, Registers*);
|
||||
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]);
|
||||
void GetRegisterText(Registers reg, char buffer[4]);
|
||||
void GetMnemonicText(Mnemonics mnemonic, char buffer[12]);
|
||||
void GetRegisterText(Registers reg, char buffer[5]);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef PARSER_H
|
||||
#define PARSER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "dictionary.h"
|
||||
#include "opcodes.h"
|
||||
#include "token.h"
|
||||
#include "array.h"
|
||||
#include "keywords.h"
|
||||
|
||||
typedef struct _instruction Instruction;
|
||||
typedef Array Instructions;
|
||||
|
||||
Instructions* ParseTokens(Array* tokens);
|
||||
|
||||
#endif
|
||||
@@ -5,12 +5,17 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "opcodes.h"
|
||||
#include "keywords.h"
|
||||
|
||||
typedef enum {
|
||||
Empty,
|
||||
String,
|
||||
Number,
|
||||
Symbol,
|
||||
Register,
|
||||
Mnemonic,
|
||||
Keyword,
|
||||
LineEnd = '\n',
|
||||
Colon = ':',
|
||||
Comma = ',',
|
||||
@@ -32,6 +37,9 @@ typedef struct _token {
|
||||
char Operator[8];
|
||||
char* String;
|
||||
int Number;
|
||||
Mnemonics Mnemonic;
|
||||
Registers Register;
|
||||
Keywords Keyword;
|
||||
} Value;
|
||||
int LineNumber;
|
||||
int ColumnNumber;
|
||||
|
||||
@@ -34,3 +34,10 @@ void* ArrayPeek(struct _array* array) {
|
||||
|
||||
return array->Items[array->Size - 1];
|
||||
}
|
||||
|
||||
void* ArrayIndex(Array* array, size_t index) {
|
||||
if (!array) return NULL;
|
||||
if (index >= array->Size) return NULL;
|
||||
|
||||
return array->Items[index];
|
||||
}
|
||||
+13
-8
@@ -1,22 +1,27 @@
|
||||
#include "../includes/keywords.h"
|
||||
#include <string.h>
|
||||
|
||||
#define KEYWORD_COUNT 5
|
||||
#define KEYWORD_COUNT 7
|
||||
|
||||
struct _keyword {
|
||||
char* Name;
|
||||
Keyword Word;
|
||||
Keywords Word;
|
||||
};
|
||||
|
||||
struct _keyword keywords[KEYWORD_COUNT] = {
|
||||
{ "fn", FN },
|
||||
{ "org", ORG },
|
||||
{ "fn", FUNCTION },
|
||||
//{ "org", ORG },
|
||||
{ "namespace", NAMESPACE },
|
||||
{ "db", DB },
|
||||
{ "cosnt", CONST }
|
||||
{ "asciiz", ASCIIZ },
|
||||
{ "ascii", ASCII },
|
||||
{ "word", WORD },
|
||||
{ "short", SHORT },
|
||||
{ "byte", BYTE }
|
||||
//{ "db", DB },
|
||||
//{ "cosnt", CONST }
|
||||
};
|
||||
|
||||
int IsKeyword(const char* text, Keyword* keyword) {
|
||||
int IsKeyword(const char* text, Keywords* keyword) {
|
||||
if (!text) return 0;
|
||||
|
||||
for(unsigned long i = 0; i < KEYWORD_COUNT; i++) {
|
||||
@@ -30,7 +35,7 @@ int IsKeyword(const char* text, Keyword* keyword) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GetKeywordText(Keyword keyword, char buffer[16]) {
|
||||
void GetKeywordText(Keywords keyword, char buffer[16]) {
|
||||
if (!buffer) return;
|
||||
|
||||
memset(buffer, '\0', 16);
|
||||
|
||||
+7
-1
@@ -1,6 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include "../includes/futil.h"
|
||||
#include "../includes/tokenizer.h"
|
||||
#include "../includes/opcodes.h"
|
||||
#include "../includes/parser.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char* file;
|
||||
@@ -29,8 +31,9 @@ int main(int argc, char** argv) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
char* buffer;
|
||||
char type[32];
|
||||
|
||||
for(int i = 0; i < tokens->Size; i++) {
|
||||
Token* token = tokens->Items[i];
|
||||
@@ -41,6 +44,7 @@ int main(int argc, char** argv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//StringifyTokenType(token->Type, type);
|
||||
buffer = TokenStringify(token);
|
||||
|
||||
if (buffer) {
|
||||
@@ -51,4 +55,6 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
*/
|
||||
(void) ParseTokens(tokens);
|
||||
}
|
||||
+29
-16
@@ -3,14 +3,14 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define OPCODE_COUNT 34
|
||||
#define OPCODE_COUNT 29
|
||||
|
||||
struct _instruction {
|
||||
char* Name;
|
||||
Mnemonic Mnemonic;
|
||||
Mnemonics Mnemonic;
|
||||
};
|
||||
|
||||
struct _instruction instructions[OPCODE_COUNT] = {
|
||||
struct _instruction Instructions[OPCODE_COUNT] = {
|
||||
{ "add", ADD },
|
||||
{ "sub", SUB },
|
||||
{ "mul", MUL },
|
||||
@@ -42,32 +42,32 @@ struct _instruction instructions[OPCODE_COUNT] = {
|
||||
{ "pop", POP }
|
||||
};
|
||||
|
||||
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]) {
|
||||
void GetMnemonicText(Mnemonics mnemonic, char buffer[12]) {
|
||||
memset(buffer, '\0', 12);
|
||||
|
||||
for(int i = 0; i < OPCODE_COUNT; i++) {
|
||||
if (instructions[i].Mnemonic == mnemonic) {
|
||||
strncpy(buffer, instructions[i].Name, 11);
|
||||
if (Instructions[i].Mnemonic == mnemonic) {
|
||||
strncpy(buffer, Instructions[i].Name, 11);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GetRegisterText(Registers reg, char buffer[4]) {
|
||||
memset(buffer, '\0', 4);
|
||||
void GetRegisterText(Registers reg, char buffer[5]) {
|
||||
memset(buffer, '\0', 5);
|
||||
|
||||
if (reg < R1 || reg > R8) return;
|
||||
if (reg < R1 || reg > R32) return;
|
||||
|
||||
buffer[0] = 'r';
|
||||
buffer[1] = reg + 49;
|
||||
}
|
||||
|
||||
int IsOpcode(const char* text, Mnemonic* opcode) {
|
||||
int IsOpcode(const char* text, Mnemonics* opcode) {
|
||||
if (!text) return 0;
|
||||
|
||||
for(unsigned long i = 0; i < sizeof(instructions) / sizeof(struct _instruction); i++) {
|
||||
if (strcmp(instructions[i].Name, text) == 0) {
|
||||
if (opcode) *opcode = instructions[i].Mnemonic;
|
||||
for(unsigned long i = 0; i < OPCODE_COUNT; i++) {
|
||||
if (strcmp(Instructions[i].Name, text) == 0) {
|
||||
if (opcode) *opcode = Instructions[i].Mnemonic;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -79,14 +79,27 @@ int IsRegister(const char* text, Registers* reg) {
|
||||
if (!text) return 0;
|
||||
|
||||
int length = strlen(text);
|
||||
Registers r = R8;
|
||||
Registers r;
|
||||
|
||||
if (length != 2) return 0;
|
||||
if (length < 2 || length > 3) return 0;
|
||||
if (text[0] != 'r') return 0;
|
||||
|
||||
if (length == 2) {
|
||||
if (!isdigit(text[1])) return 0;
|
||||
|
||||
r = text[1] - 0x31;
|
||||
r = text[1] - 0x30;
|
||||
}
|
||||
else if (strcmp(text, "rbp") == 0)
|
||||
r = RBP;
|
||||
else if (strcmp(text, "rsp") == 0)
|
||||
r = RSP;
|
||||
else if (strcmp(text, "rip") == 0)
|
||||
r = RIP;
|
||||
else {
|
||||
r = (text[1] - 0x30) * 10;
|
||||
if (!isdigit(text[2])) return 0;
|
||||
r += text[2] - 0x30;
|
||||
}
|
||||
|
||||
if (reg) *reg = r;
|
||||
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
#include "../includes/parser.h"
|
||||
|
||||
#define KEYWORD_COUNT 7
|
||||
|
||||
static Array* Tokens;
|
||||
|
||||
struct _instruction {
|
||||
char* Name;
|
||||
bool IsDirective;
|
||||
union {
|
||||
Mnemonics Mnemonic;
|
||||
Keywords Keyword;
|
||||
} Value;
|
||||
};
|
||||
|
||||
typedef struct parameter {
|
||||
bool IsRegister;
|
||||
Registers Register;
|
||||
unsigned char Width;
|
||||
uint32_t Offset;
|
||||
} Parameter;
|
||||
|
||||
size_t ParserIndex = 0;
|
||||
|
||||
Token* ParserAdvance(void);
|
||||
void ParserIgnoreLine(void);
|
||||
bool ParserAtEnd(void);
|
||||
Parameter* ParserExpectParameter(void);
|
||||
void ParserHandleKeyword(Keywords keyword);
|
||||
Token* ParserExpect(TokenType type);
|
||||
Token* ParserWant(TokenType type);
|
||||
void ParserExpectLineEnd(void);
|
||||
|
||||
Instructions* ParseTokens(Array* tokens) {
|
||||
Tokens = tokens;
|
||||
Keywords keyword;
|
||||
|
||||
while(!ParserAtEnd()) {
|
||||
Token* token = ParserAdvance();
|
||||
|
||||
switch(token->Type) {
|
||||
case Keyword:
|
||||
ParserHandleKeyword(token->Value.Keyword);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParserHandleKeyword(Keywords keyword) {
|
||||
Token* namespace = NULL;
|
||||
|
||||
switch(keyword) {
|
||||
case NAMESPACE:
|
||||
namespace = ParserExpect(Symbol);
|
||||
|
||||
ParserExpectLineEnd();
|
||||
|
||||
printf("Namespace `%s` seen\n", namespace->Value.String);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Token* ParserExpect(TokenType type) {
|
||||
if (ParserAtEnd()) return NULL;
|
||||
|
||||
Token* token = ParserAdvance();
|
||||
|
||||
if (!token || token->Type != type) return NULL;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
Token* ParserWant(TokenType type) {
|
||||
if (ParserAtEnd()) return NULL;
|
||||
|
||||
Token* token = ParserAdvance();
|
||||
|
||||
if (!token || token->Type != type) return NULL;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
void ParserExpectLineEnd(void) {
|
||||
if (ParserAtEnd()) return;
|
||||
|
||||
Token* token = ParserAdvance();
|
||||
|
||||
if (token->Type != LineEnd && token->Type != FileEnd) {
|
||||
//Error / sync
|
||||
printf("Expected end of line on line %d.\n", token->LineNumber);
|
||||
|
||||
ParserIgnoreLine();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void ParserIgnoreLine(void) {
|
||||
while(!ParserAtEnd()) {
|
||||
Token* token = ParserAdvance();
|
||||
|
||||
if (token->Type == LineEnd || token->Type == FileEnd)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Token* ParserAdvance() {
|
||||
if (ParserAtEnd()) return (Token*) ArrayPeek(Tokens);
|
||||
if (ParserIndex == Tokens->Size) return (Token*) ArrayPeek(Tokens);
|
||||
|
||||
Token* next = ArrayIndex(Tokens, ParserIndex);
|
||||
ParserIndex++;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
bool ParserAtEnd() {
|
||||
return ParserIndex >= Tokens->Size;
|
||||
}
|
||||
+34
@@ -14,9 +14,34 @@ struct _token* TokenCreate(TokenType type, int lineNumber, int columnNumber, boo
|
||||
char* TokenStringify(const struct _token* token) {
|
||||
if (!token) return false;
|
||||
|
||||
char word[32];
|
||||
char* buffer = NULL;
|
||||
|
||||
switch(token->Type) {
|
||||
case Register:
|
||||
GetRegisterText(token->Value.Register, word);
|
||||
|
||||
buffer = calloc(sizeof(word), sizeof(char));
|
||||
|
||||
strncpy(buffer, word, sizeof(word));
|
||||
|
||||
break;
|
||||
case Mnemonic:
|
||||
GetMnemonicText(token->Value.Mnemonic, word);
|
||||
|
||||
buffer = calloc(sizeof(word), sizeof(char));
|
||||
|
||||
strncpy(buffer, word, sizeof(word));
|
||||
|
||||
break;
|
||||
case Keyword:
|
||||
GetKeywordText(token->Value.Keyword, word);
|
||||
|
||||
buffer = calloc(sizeof(word), sizeof(char));
|
||||
|
||||
strncpy(buffer, word, sizeof(word));
|
||||
|
||||
break;
|
||||
case String:
|
||||
case Symbol:
|
||||
buffer = calloc(strlen(token->Value.String) + 1, sizeof(char));
|
||||
@@ -64,6 +89,15 @@ int StringifyTokenType(TokenType type, char buffer[32]) {
|
||||
case Empty:
|
||||
strncpy(buffer, "<empty >", 8);
|
||||
break;
|
||||
case Register:
|
||||
strncpy(buffer, "<Reg >", 8);
|
||||
break;
|
||||
case Mnemonic:
|
||||
strncpy(buffer, "<Mnemon>", 8);
|
||||
break;
|
||||
case Keyword:
|
||||
strncpy(buffer, "<Key >", 8);
|
||||
break;
|
||||
case String:
|
||||
strncpy(buffer, "<string>", 8);
|
||||
break;
|
||||
|
||||
+26
-6
@@ -1,14 +1,12 @@
|
||||
#include "../includes/tokenizer.h"
|
||||
#include "../includes/keywords.h"
|
||||
#include "../includes/string_builder.h"
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MAXWORDLENGTH 1024
|
||||
|
||||
//char Word[MAXWORDLENGTH] = { 0 };
|
||||
Array* Tokens;
|
||||
static Array* Tokens;
|
||||
|
||||
const char* SourceCode;
|
||||
size_t SourceCodeLength = 0;
|
||||
@@ -174,16 +172,38 @@ void TokenizerExpectWord() {
|
||||
wordLength++;
|
||||
}
|
||||
|
||||
if (wordLength > 0) {
|
||||
Token* token = TokenCreate(Symbol, SourceLineNumber, SourceColumnNumber, false);
|
||||
if (wordLength == 0) return;
|
||||
|
||||
Token* token;
|
||||
Mnemonics mnemonic;
|
||||
Registers reg;
|
||||
Keywords keyword;
|
||||
|
||||
if (IsOpcode(word, &mnemonic)) {
|
||||
token = TokenCreate(Mnemonic, SourceLineNumber, SourceColumnNumber, true);
|
||||
|
||||
token->Value.Mnemonic = mnemonic;
|
||||
}
|
||||
else if (IsRegister(word, ®)) {
|
||||
token = TokenCreate(Register, SourceLineNumber, SourceColumnNumber, true);
|
||||
|
||||
token->Value.Register = reg;
|
||||
}
|
||||
else if (IsKeyword(word, &keyword)) {
|
||||
token = TokenCreate(Keyword, SourceLineNumber, SourceColumnNumber, true);
|
||||
|
||||
token->Value.Keyword = keyword;
|
||||
}
|
||||
else {
|
||||
token = TokenCreate(Symbol, SourceLineNumber, SourceColumnNumber, false);
|
||||
|
||||
token->Value.String = calloc(wordLength + 1, sizeof(char));
|
||||
|
||||
strncpy(token->Value.String, word, wordLength);
|
||||
}
|
||||
|
||||
ArrayAdd(Tokens, token);
|
||||
}
|
||||
}
|
||||
|
||||
void TokenizerExpectString(void) {
|
||||
char word[256] = { 0 };
|
||||
|
||||
Reference in New Issue
Block a user