Created a tokenizer and the supporting code, currently processes text that is not a string literal.
This commit is contained in:
@@ -0,0 +1,41 @@
|
|||||||
|
CC = gcc
|
||||||
|
CFLAGS=-g -Wall -DDEBUG -Wpedantic -Wextra -Wunused-result -std=c99 -pedantic-errors
|
||||||
|
SRCDIR=src
|
||||||
|
OBJDIR=obj
|
||||||
|
SRCS=$(wildcard $(SRCDIR)/*.c)
|
||||||
|
# Substitute all .c with .o from SRCS
|
||||||
|
OBJS=$(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SRCS))
|
||||||
|
|
||||||
|
BINDIR=bin
|
||||||
|
BIN=$(BINDIR)/assm
|
||||||
|
|
||||||
|
all: $(BIN)
|
||||||
|
|
||||||
|
release: CFLAGS=-Wall -Wpedantic -std=c99 -pedantic-errors -O2
|
||||||
|
release: clean
|
||||||
|
release: $(BIN)
|
||||||
|
|
||||||
|
$(BIN): $(OBJS) $(BINDIR)
|
||||||
|
$(CC) $(CFLAGS) $(OBJS) -o $@
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o: $(SRCDIR)/%.c $(OBJDIR)
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(BINDIR):
|
||||||
|
mkdir $@
|
||||||
|
|
||||||
|
$(OBJDIR):
|
||||||
|
mkdir $@
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
.PHONY: test
|
||||||
|
.PHONY: disass
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BINDIR)/* $(OBJDIR)/*
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(BIN) misc/another_test.asm
|
||||||
|
|
||||||
|
disass:
|
||||||
|
objdump -S --disassemble $(OBJDIR)/$(FILE).o > $(OBJDIR)/$(FILE).s
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef ARRAY_H
|
||||||
|
#define ARRAY_H
|
||||||
|
|
||||||
|
typedef struct _array {
|
||||||
|
int Capacity;
|
||||||
|
int Size;
|
||||||
|
void** Items;
|
||||||
|
} Array;
|
||||||
|
|
||||||
|
Array* ArrayCreate(void);
|
||||||
|
int ArrayAdd(Array* array, void* item);
|
||||||
|
|
||||||
|
#endif
|
||||||
+3
-3
@@ -10,13 +10,13 @@ typedef enum {
|
|||||||
} Registers;
|
} Registers;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ADD = 0x01, SUB, MUL, DIV, MOV, AND, OR, XOR, NOT, SHL, SHR, NOP, CMP, JMP, JG, JL,
|
ADD = 0x01, SUB, MUL, DIV, MOV, AND, OR, XOR, NOT, SHL, SHR, NOP, CMP, JMP, JZ, JG, JL,
|
||||||
OUTB, INB, HLT, ENI, INT, LIVT, PUSHA, POPA, CALL, RET, PUSH, POP
|
OUTB, INB, HLT, CLI, ENI, INT, LIVT, PUSHA, POPA, CALL, RET, PUSH, POP
|
||||||
} Mnemonic;
|
} Mnemonic;
|
||||||
|
|
||||||
int IsOpcode(const char*, Mnemonic*);
|
int IsOpcode(const char*, Mnemonic*);
|
||||||
int IsRegister(const char*, Registers*);
|
int IsRegister(const char*, Registers*);
|
||||||
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]);
|
void GetMnemonicText(Mnemonic mnemonic, char buffer[12]);
|
||||||
void GetRegisterText(Registers reg, char buffer[3]);
|
void GetRegisterText(Registers reg, char buffer[4]);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+15
-7
@@ -1,11 +1,17 @@
|
|||||||
#ifndef TOKEN_H
|
#ifndef TOKEN_H
|
||||||
#define TOKEN_H
|
#define TOKEN_H
|
||||||
|
|
||||||
enum TokenType {
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
Empty,
|
Empty,
|
||||||
String,
|
String,
|
||||||
Number,
|
Number,
|
||||||
Symbol,
|
Symbol,
|
||||||
|
LineEnd = '\n',
|
||||||
Plus = '+',
|
Plus = '+',
|
||||||
Minus = '-',
|
Minus = '-',
|
||||||
Star = '*',
|
Star = '*',
|
||||||
@@ -13,23 +19,25 @@ enum TokenType {
|
|||||||
Carot = '^',
|
Carot = '^',
|
||||||
OpenParen = '(',
|
OpenParen = '(',
|
||||||
CloseParen = ')',
|
CloseParen = ')',
|
||||||
|
OpenBracket = '[',
|
||||||
|
CloseBracket = ']',
|
||||||
FileEnd
|
FileEnd
|
||||||
};
|
} TokenType;
|
||||||
|
|
||||||
typedef struct _token {
|
typedef struct _token {
|
||||||
TokenType Type;
|
TokenType Type;
|
||||||
char* Name;
|
|
||||||
union {
|
union {
|
||||||
|
char Operator[8];
|
||||||
char* String;
|
char* String;
|
||||||
int Number;
|
int Number;
|
||||||
} Value;
|
} Value;
|
||||||
int LineNumber;
|
int LineNumber;
|
||||||
int ColumnNumber;
|
int ColumnNumber;
|
||||||
int Index;
|
bool Resolved;
|
||||||
int Length;
|
|
||||||
int Resolved;
|
|
||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
Token* TokenCreate(char* name, TokenType type, int lineNumber, int columnNumber, int index, int length, int resolved);
|
Token* TokenCreate(TokenType type, int lineNumber, int columnNumber, bool resolved);
|
||||||
|
char* TokenStringify(const Token* token, bool valueOnly);
|
||||||
|
int StringifyTokenType(TokenType type, char buffer[32]);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef TOKENIZER_H
|
||||||
|
#define TOKENIZER_H
|
||||||
|
|
||||||
|
#include "array.h"
|
||||||
|
#include "dictionary.h"
|
||||||
|
#include "token.h"
|
||||||
|
|
||||||
|
Array* Tokenize(const char* text, Dictionary** variables);
|
||||||
|
|
||||||
|
#endif
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
#include "../includes/array.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define ARRAY_DEFAULT_CAPACITY 32
|
||||||
|
|
||||||
|
struct _array* ArrayCreate(void) {
|
||||||
|
struct _array* array = calloc(1, sizeof(Array));
|
||||||
|
|
||||||
|
array->Items = calloc(ARRAY_DEFAULT_CAPACITY, sizeof(void*));
|
||||||
|
array->Capacity = ARRAY_DEFAULT_CAPACITY;
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ArrayAdd(struct _array* array, void* item) {
|
||||||
|
if (!array) return 0;
|
||||||
|
|
||||||
|
if (array->Size == array->Capacity) {
|
||||||
|
array->Items = realloc(array->Items, array->Capacity * 2 * sizeof(void*));
|
||||||
|
|
||||||
|
array->Capacity *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
array->Items[array->Size] = item;
|
||||||
|
array->Size++;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
+3
-1
@@ -32,8 +32,10 @@ KeyValPair* KeyValPairCreate(const char* key, void* value) {
|
|||||||
int DictionaryAdd(struct _dictionary* dict, const char* key, void* value) {
|
int DictionaryAdd(struct _dictionary* dict, const char* key, void* value) {
|
||||||
if (!dict) return 0;
|
if (!dict) return 0;
|
||||||
|
|
||||||
if (dict->Size = dict->Capacity) {
|
if (dict->Size == dict->Capacity) {
|
||||||
dict->Pairs = realloc(dict->Pairs, sizeof(KeyValPair*) * dict->Capacity * 2);
|
dict->Pairs = realloc(dict->Pairs, sizeof(KeyValPair*) * dict->Capacity * 2);
|
||||||
|
|
||||||
|
dict->Capacity *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
dict->Pairs[dict->Size] = KeyValPairCreate(key, value);
|
dict->Pairs[dict->Size] = KeyValPairCreate(key, value);
|
||||||
|
|||||||
+19
-1
@@ -1,10 +1,13 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "../includes/futil.h"
|
#include "../includes/futil.h"
|
||||||
|
#include "../includes/tokenizer.h"
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
char* file;
|
char* file;
|
||||||
size_t count;
|
size_t count;
|
||||||
|
|
||||||
|
//gcc -o test src/main.c src/futil.c src/dictionary.c src/tokenizer.c src/token.c src/array.c -g
|
||||||
|
|
||||||
if (argc <= 1) {
|
if (argc <= 1) {
|
||||||
printf("Usage: assm <file.asm>\n");
|
printf("Usage: assm <file.asm>\n");
|
||||||
|
|
||||||
@@ -17,5 +20,20 @@ int main(int argc, char** argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(file);
|
Dictionary* variables = DictionaryCreate();
|
||||||
|
|
||||||
|
Array* tokens = Tokenize(file, &variables);
|
||||||
|
|
||||||
|
if (tokens->Size == 0) {
|
||||||
|
printf("No tokens\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else printf("Found %d tokens.", tokens->Size);
|
||||||
|
|
||||||
|
for(int i = 0; i < tokens->Size; i++) {
|
||||||
|
Token* token = tokens->Items[i];
|
||||||
|
|
||||||
|
printf(TokenStringify(token, false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
#include "../includes/token.h"
|
||||||
|
|
||||||
|
struct _token* TokenCreate(TokenType type, int lineNumber, int columnNumber, bool resolved) {
|
||||||
|
struct _token* token = calloc(1, sizeof(Token));
|
||||||
|
|
||||||
|
token->Type = type;
|
||||||
|
token->LineNumber = lineNumber;
|
||||||
|
token->ColumnNumber = columnNumber;
|
||||||
|
token->Resolved = resolved;
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* TokenStringify(const struct _token* token, bool valueOnly) {
|
||||||
|
if (!token) return NULL;
|
||||||
|
char type[32];
|
||||||
|
char number[32];
|
||||||
|
|
||||||
|
int length = StringifyTokenType(token->Type, type);
|
||||||
|
|
||||||
|
char* result = calloc(512, sizeof(char));
|
||||||
|
#ifdef DEBUG
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch(token->Type) {
|
||||||
|
case Empty:
|
||||||
|
snprintf(result, length + 1, "%s ", type);
|
||||||
|
break;
|
||||||
|
case String:
|
||||||
|
snprintf(result, 511, "%s \"%s\" ", type, token->Value.String);
|
||||||
|
break;
|
||||||
|
case Number:
|
||||||
|
snprintf(number, 32, "%d", token->Value.Number);
|
||||||
|
snprintf(result, 511, "%s %s", type, number);
|
||||||
|
break;
|
||||||
|
case Symbol:
|
||||||
|
snprintf(result, 511, "%s %s", type, token->Value.String);
|
||||||
|
break;
|
||||||
|
case LineEnd:
|
||||||
|
snprintf(result, 511, "%s\n", type);
|
||||||
|
break;
|
||||||
|
case FileEnd:
|
||||||
|
snprintf(result, length + 1, "%s ", type);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//snprintf(buffer, length, "<%c>", type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int StringifyTokenType(TokenType type, char buffer[32]) {
|
||||||
|
if (!buffer) return 0;
|
||||||
|
|
||||||
|
memset(buffer, '\0', 32);
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case Empty:
|
||||||
|
strncpy(buffer, "<empty >", 8);
|
||||||
|
break;
|
||||||
|
case String:
|
||||||
|
strncpy(buffer, "<string>", 8);
|
||||||
|
break;
|
||||||
|
case Number:
|
||||||
|
strncpy(buffer, "<number>", 8);
|
||||||
|
break;
|
||||||
|
case Symbol:
|
||||||
|
strncpy(buffer, "<symbol>", 8);
|
||||||
|
break;
|
||||||
|
case LineEnd:
|
||||||
|
strncpy(buffer, "<LnEnd >", 8);
|
||||||
|
break;
|
||||||
|
case FileEnd:
|
||||||
|
strncpy(buffer, "<filend>", 8);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(buffer, 8, "<%c >", type);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
+134
@@ -0,0 +1,134 @@
|
|||||||
|
#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;
|
||||||
|
|
||||||
|
const char* SourceCode;
|
||||||
|
size_t SourceCodeLength = 0;
|
||||||
|
size_t SourceCodeIndex = 0;
|
||||||
|
int SourceLineNumber = 0;
|
||||||
|
int SourceColumnNumber = 0;
|
||||||
|
|
||||||
|
bool TryPeekTokenizer(char* c);
|
||||||
|
bool TryPopTokenizer(char* c);
|
||||||
|
bool TokenizerAtEnd(void);
|
||||||
|
char AdvanceTokenizer(void);
|
||||||
|
bool BackTokenzier(void);
|
||||||
|
char TokenizerLookAhead(void);
|
||||||
|
|
||||||
|
void TokenizerExpectWord(void);
|
||||||
|
void TokenizerIgnoreLine(void);
|
||||||
|
|
||||||
|
Array* Tokenize(const char* sourceCode, Dictionary** variables) {
|
||||||
|
Tokens = ArrayCreate();
|
||||||
|
|
||||||
|
SourceCodeLength = strlen(sourceCode) - 1;
|
||||||
|
SourceCode = sourceCode;
|
||||||
|
|
||||||
|
while(!TokenizerAtEnd()) {
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if (!TryPeekTokenizer(&c)) break;
|
||||||
|
|
||||||
|
if (isalpha(c)) {
|
||||||
|
TokenizerExpectWord();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == ';') {
|
||||||
|
TokenizerIgnoreLine();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvanceTokenizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayAdd(Tokens, TokenCreate(FileEnd, SourceLineNumber + 1, 0, true));
|
||||||
|
|
||||||
|
return Tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TokenizerExpectWord() {
|
||||||
|
char word[256] = { 0 };
|
||||||
|
int wordLength = 0;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
while(TryPopTokenizer(&c)) {
|
||||||
|
if (isspace(c)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ispunct(c)) {
|
||||||
|
BackTokenzier();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wordLength == 255) break; //Sync, error etc here at some point.
|
||||||
|
|
||||||
|
word[wordLength] = c;
|
||||||
|
wordLength++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wordLength > 0) {
|
||||||
|
Token* token = TokenCreate(Symbol, SourceLineNumber, SourceColumnNumber, false);
|
||||||
|
|
||||||
|
token->Value.String = calloc(wordLength + 1, sizeof(char));
|
||||||
|
|
||||||
|
strncpy(token->Value.String, word, wordLength);
|
||||||
|
|
||||||
|
ArrayAdd(Tokens, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TokenizerIgnoreLine(void) {
|
||||||
|
char c;
|
||||||
|
|
||||||
|
while(TryPopTokenizer(&c)) {
|
||||||
|
if (c == '\n') break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryPeekTokenizer(char* c) {
|
||||||
|
*c = SourceCode[SourceCodeIndex];
|
||||||
|
|
||||||
|
return *c != '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryPopTokenizer(char* c) {
|
||||||
|
*c = AdvanceTokenizer();
|
||||||
|
|
||||||
|
return *c != '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
char AdvanceTokenizer() {
|
||||||
|
if (TokenizerAtEnd()) return '\0';
|
||||||
|
if (SourceCodeIndex + 1 > SourceCodeLength) return '\0';
|
||||||
|
|
||||||
|
char c = SourceCode[SourceCodeIndex];
|
||||||
|
|
||||||
|
SourceCodeIndex++;
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BackTokenzier(void) {
|
||||||
|
if (SourceCodeIndex == 0) return false;
|
||||||
|
|
||||||
|
SourceCodeIndex--;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TokenizerAtEnd() {
|
||||||
|
return SourceCodeLength == SourceCodeIndex;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user