前言
這本書的sparrow(麻雀)語言,基於wren(鷦鷯)語言,是一門面向對象語言!——至於其他特點我忘了,還記得的就是Demo中部分函數命名很簡單、簡單到與其他庫函數產生衝突了。。。。
幾個月前寫(抄)的項目,後面的語法分析、製作C語言的面向對象、設計虛擬機等等內容沒時間看下去了,只能講講廢話了——
加前綴
C語言做的,因爲沒有前綴,所以一是不好看,二是容易衝突。只有一個解決辦法,就是用專有的前綴。所以,我在每個函數、每個結構體、每個枚舉、許多個宏的前面,都加上相同的前綴 hj
詞法分析的Demo
頭文件
//hj_common.h
/*
hj_common.h文件是整個項目的最底層的文件,這個文件裏只有宏
整個項目是C寫的,沒有命名空間,所以很容易發生重命名!
規定:
1.變量、結構體、枚舉、函數等,所有的非宏標識符前都要有前綴 hj
2.特殊宏前後都有兩個下劃線。特殊宏就是那些特別簡單,分不清是枚舉還是宏的
3.所有的前綴都是hj,把整個項目所有的hj都刪除了基本不影響理解
可能影響執行。畢竟不能避免衝突和重命名了!!!
*/
#define _CRT_SECURE_NO_WARNINGS
#ifndef _hj_common_h
#define _hj_common_h
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h> //uint32_t
#include<string.h>
#include<math.h>
#include<ctype.h>
#include<Windows.h>
#include<time.h>
#include<sys/stat.h> //stat 求文件大小
#include<stdarg.h>
#define hjBOOL char
#define hjTRUE 1
#define hjFALSE 0
#define hjPUBLIC
#define hjPRIVATE static
#define UNUSED __attribute__((unused))
/*hjDEBUG 的定義會寫在makefile裏*/
#ifdef hjDEBUG
#define hjASSERT(condition,errMsg)\
{\
if(!condition){\
fprintf(stderr,"hjASSERT failed! %s:%d IN FUNCTION %s(): %s\n",__FILE__,__LINE__,__func__,errMsg);\
abort();\
}\
}
#else
#define hjASSERT(condition,errMsg) ((void)0)
#endif
/*hjNOT_REACHED放在不能抵達的地方*/
#define hjNOT_REACHED \
{\
fprintf(stderr,"hjNOT_REACHED :%s:%d IN FUNCTION %s()\n",__FILE__,__LINE__,__func__);\
abort();\
}
typedef struct hjVM hjVM;
typedef struct hjLexer hjLexer;
typedef struct hjParser hjParser;
typedef struct hjClass hjClass;
#endif
//hj_core.h
/*
hj_core.h文件是整個項目的最核心的文件
1.幾乎所有底層的結構體、枚舉都定義在這裏
2.只有結構體和枚舉和全局變量,沒有函數
*/
#ifndef _hj_core_h
#define _hj_core_h
#include"hj_common.h"
//虛擬機
typedef struct hjVM {
uint32_t allocatedByte; //累加已經分配的字節數
hjLexer* curLexer; //當前詞法分析器
}hjVM;
//單詞類型
typedef enum hjTokenType {
/*未知單詞*/
hjTOKEN_UNKNOWN,
/*數據類型*/
hjTOKEN_NUM, //數字
hjTOKEN_STR, //字符串
hjTOKEN_ID, //標識符
hjTOKEN_EXPR, //內嵌表達式
/*關鍵字*/
hjTOKEN_LET, //let
hjTOKEN_FUNCTION, //function
hjTOKEN_IF, //if
hjTOKEN_ELSE, //else
hjTOKEN_TRUE, //True
hjTOKEN_FALSE, //False
hjTOKEN_WHILE, //while
hjTOKEN_FOR, //for
hjTOKEN_BREAK, //break
hjTOKEN_CONTINUE, //continue
hjTOKEN_RETURN, //return
hjTOKEN_NIL, //Nil
/*關於類及模塊導入*/
hjTOKEN_CLASS, //class
hjTOKEN_SELF, //self
hjTOKEN_STATIC, //static
hjTOKEN_IS, //is
hjTOKEN_SUPER, //super
hjTOKEN_IMPORT, //import
/*分隔符*/
hjTOKEN_AT, //@
hjTOKEN_WELL, //#
hjTOKEN_ACCENT, //' 重音
hjTOKEN_SEMI, //; 分號
hjTOKEN_BASKSLASH, // \ 反斜槓
hjTOKEN_COLON, //: 冒號
hjTOKEN_COMMA, //, 逗號
hjTOKEN_DOT, //. 一個點
hjTOKEN_DOT_DOT, //.. 兩個連續的點
hjTOKEN_LEFT_PAREN, //(
hjTOKEN_RIGHT_PAREN, //)
hjTOKEN_LEFT_BRACKET, //[
hjTOKEN_RIGHT_BRACKET, //]
hjTOKEN_LEFT_BRACE, //{
hjTOKEN_RIGHT_BRACE, //}
//賦值號
hjTOKEN_ASSIGN, //=
/*簡單的二元運算符*/
hjTOKEN_ADD, //+
hjTOKEN_SUB, //-
hjTOKEN_MUL, //*
hjTOKEN_DIV, // /
hjTOKEN_MOD, //%
hjTOKEN_POW, //^ 上面幾個都是左結合的,乘方是右結合的!
/*位運算符*/
hjTOKEN_BIT_AND, //&
hjTOKEN_BIT_OR, //|
hjTOKEN_BIT_NOT, //~
hjTOKEN_BIT_SHIFT_LEFT, //<<
hjTOKEN_BIT_SHIFT_RIGHT, //>>
/*邏輯運算符*/
hjTOKEN_LOGIC_AND, //&&
hjTOKEN_LOGIC_OR, //||
hjTOKEN_LOGIC_NOT, //!
/*關係運算符*/
hjTOKEN_EQ, //==
hjTOKEN_NEQ, //!=
hjTOKEN_GT, //>
hjTOKEN_GE, //>=
hjTOKEN_LT, //<
hjTOKEN_LE, //<=
/*問號,可能是?:三元運算符的一部分*/
hjTOKEN_QUE, //?
hjTOKEN_EOL, //end of line = newline = line feed = line break = line ending = \n = 換行符 ,EOL = LF
hjTOKEN_EOF //end of file = 文件結束符 , EOF = LE
}hjTokenType;
//單詞
typedef struct hjToken {
hjTokenType type; //單詞類型
const char* start; //指向單詞字符串的開始
uint32_t len; //單詞字符串的長度
uint32_t lineNo; //單詞所在的文件行號
}hjToken;
//詞法分析器
typedef struct hjLexer {
const char* file; //文件
const char* srcCode; //源碼
const char* next; //指向下一個字符
char curChar; //當前字符
hjToken preToken; //先前單詞
hjToken curToken; //當前單詞
hjVM* vm; //虛擬機
int Lcounter; //記錄小括號的嵌套,也就是記錄內嵌表達式
}hjLexer;
//字符串
//這個類型的數據將作爲符號表的元素
typedef struct hjString {
uint32_t len; //字符串長度,不包含\0
char* str; //字符串內容
}hjString;
/*
字符串緩衝區
用於存儲字符串對象中的字符串
*/
typedef struct hjCharValue {
uint32_t len; //除\0之外的字符個數!!!
char start[0]; //柔性數組
}hjCharValue;
/*--------------------定義幾種類型的動態數組--------------------*/
//字符串數組
typedef struct hjStringArray {
uint32_t count; //數據個數
uint32_t capacity; //容量
hjString* data; //字符串數據緩衝區
}hjStringArray;
//字節數組
typedef struct hjByteArray {
uint32_t count; //數據個數
uint32_t capacity; //容量
uint8_t* data; //字節數據緩衝區
}hjByteArray;
//字符數組
typedef struct hjCharArray {
uint32_t count; //數據個數
uint32_t capacity; //容量
char* data; //字符數據緩衝區
}hjCharArray;
//int數組
typedef struct hjIntArray {
uint32_t count; //數據個數
uint32_t capacity; //容量
int* data; //int數據緩衝區
}hjIntArray;
//符號表類型就是字符串數組類型
#define hjSymbolTable hjStringArray
#endif
//hj_error.h
/*
hj_error.h文件是錯誤處理模塊
*/
#ifndef _hj_error_h
#define _hj_error_h
#include"hj_core.h"
//錯誤類型
typedef enum hjErrorType {
hjERROR_IO,
hjERROR_MEM,
hjERROR_LEX,
hjERROR_PARSE,
hjERROR_COMPILE,
hjERROR_RUNTIME
}hjErrorType;
//打印錯誤信息
hjPUBLIC void hjError(void* _lexer, hjErrorType _errType, char* _errMsg);
hjPUBLIC void hjError_(void* _lexer, hjErrorType _errType, const char* _format,...);
#define __hjERROR_IO__(...) hjError_(NULL,hjERROR_IO,__VA_ARGS__)
#define __hjERROR_MEM__(...) hjError_(NULL,hjERROR_MEM,__VA_ARGS__)
#define __hjERROR_LEX__(lexer,...) hjError_(lexer,hjERROR_LEX,__VA_ARGS__)
#define __hjERROR_PARSE__(lexer,...) hjError_(lexer,hjERROR_PARSE,__VA_ARGS__)
#define __hjERROR_COMPILE__(lexer,...) hjError_(lexer,hjERROR_COMPILE,__VA_ARGS__)
#define __hjERROR_RUNTIME__(...) hjError_(NULL,hjERROR_RUNTIME,__VA_ARGS__)
#endif
//hj_mem.h
/*
hj_mem.h文件是內存管理模塊
內存管理模塊的功能:
1.申請內存
2.修改空間大小
3.釋放內存
*/
#ifndef _hj_mem_h
#define _hj_mem_h
#include"hj_error.h"
//申請內存
hjPUBLIC void* hjMemManager(hjVM* _vm, void* _ptr, uint32_t _oldSize, uint32_t _newSize);
//找出大於等於_v的最近的2次冪
hjPUBLIC uint32_t hjNumOf2Pow_GE_v(uint32_t _v);
//清理符號表
hjPUBLIC void hjClear_SymbolTable(hjVM* _vm, hjSymbolTable* _table);
/*一組內存管理的宏*/
#define ALLOCATE(vm,type) (type*)hjMemManager(vm,NULL,0,sizeof(type)) //給type類型申請type類型大小的內存
#define ALLOCATE_EXTRA(vm,type,extraSize) (type*)hjMemManager(vm,NULL,0,sizeof(type) + extraSize) //給type類型申請type類型大小+額外大小的內存
#define ALLOCATE_ARRAY(vm,type,count) (type*)hjMemManager(vm,NULL,0,sizeof(type) * count) //申請若干個type類型大小的內存
#define DEALLOCATE(vm,mem) MemManager(vm,mem,0,0) //釋放mem的內存
#define DEALLOCATE_ARRAY(vm,arr,count) MemManager(vm,arr,sizeof(arr[0]) * count,0) //釋放arr數組的內存
/*--------------------字符串數組方法--------------------*/
hjPUBLIC void hjInit_StringArray(hjStringArray* _arr);
hjPUBLIC void hjWrite_StringArray(hjVM* _vm, hjStringArray* _arr, hjString _data, uint32_t _fillCount);
hjPUBLIC void hjAdd_StringArray(hjVM* _vm, hjStringArray* _arr, hjString _data);
hjPUBLIC void hjClear_StringArray(hjVM* _vm, hjStringArray* _arr);
/*--------------------字節數組方法--------------------*/
hjPUBLIC void hjInit_ByteArray(hjByteArray* _arr);
hjPUBLIC void hjWrite_ByteArray(hjVM* _vm, hjByteArray* _arr, uint8_t _data, uint32_t _fillCount);
hjPUBLIC void hjAdd_ByteArray(hjVM* _vm, hjByteArray* _arr, uint8_t _data);
hjPUBLIC void hjClear_ByteArray(hjVM* _vm, hjByteArray* _arr);
/*--------------------字符數組方法--------------------*/
hjPUBLIC void hjInit_CharArray(hjCharArray* _arr);
hjPUBLIC void hjWrite_CharArray(hjVM* _vm, hjCharArray* _arr, char _data, uint32_t _fillCount);
hjPUBLIC void hjAdd_CharArray(hjVM* _vm, hjCharArray* _arr, char _data);
hjPUBLIC void hjClear_CharArray(hjVM* _vm, hjCharArray* _arr);
/*--------------------int數組方法--------------------*/
hjPUBLIC void hjInit_IntArray(hjIntArray* _arr);
hjPUBLIC void hjWrite_IntArray(hjVM* _vm, hjIntArray* _arr, int _data, uint32_t _fillCount);
hjPUBLIC void hjAdd_IntArray(hjVM* _vm, hjIntArray* _arr, int _data);
hjPUBLIC void hjClear_IntgArray(hjVM* _vm, hjIntArray* _arr);
#endif
//hj_lexer.h
/*
hj_lexer.h文件是詞法分析器
*/
#ifndef _hj_lexer_h
#define _hj_lexer_h
#include"hj_vm.h"
#include"hj_mem.h"
#include"hj_utf8.h"
/*定義全局變量*/
//文件根目錄
extern char* hj_rootDir;
//讀取腳本
hjPUBLIC char* hjReadScript(const char* _path);
//初始化詞法分析器
hjPUBLIC hjInit_Lexer(hjVM* _vm, hjLexer* _lexer, const char* _file, const char* _srcCode);
//查看下一個字符
hjPUBLIC char hjPeek_NextChar(hjLexer* _lexer);
//獲取下一個單詞
hjPUBLIC void hjGet_NextToken(hjLexer* _lexer);
//匹配單詞
hjPUBLIC hjBOOL hjMatch_Token(hjLexer* _lexer, hjTokenType _expectedToken);
//吸收當前單詞
hjPUBLIC void hjConsume_CurToken(hjLexer* _lexer, hjTokenType _expectedToken, const char* _errMsg);
//吸收下一個單詞
hjPUBLIC void hjConsume_NextToken(hjLexer* _lexer, hjTokenType _expectedToken, const char* _errMsg);
//判斷是否是數字
hjPRIVATE hjBOOL hjJudge_Num(char _c);
//判斷是否是字母
hjPRIVATE hjBOOL hjJudge_Alpha(char _c);
//判斷是標識符還是關鍵字
hjPRIVATE hjTokenType hjJudge_IdOrKey(const char* _start, uint32_t _len);
//獲取下一個字符
hjPRIVATE void hjGet_NextChar(hjLexer* _lexer);
//匹配下一個字符
hjPRIVATE hjBOOL hjMatch_NextChar(hjLexer* _lexer, char _expectedChar);
//跳過連續的空字符
hjPRIVATE void hjSkip_Blanks(hjLexer* _lexer);
//跳過單行註釋
hjPRIVATE void hjSkip_CommentALine(hjLexer* _lexer);
//跳過多行註釋
hjPRIVATE void hjSkip_Comment(hjLexer* _lexer);
//跳過一行
hjPRIVATE void hjSkip_ALine(hjLexer* _lexer);
//解析標識符
hjPRIVATE void hjLex_Id(hjLexer* _lexer, hjTokenType _token);
//解析字符串
hjPRIVATE void hjLex_Str(hjLexer* _lexer);
//解析UTF8碼點
hjPRIVATE void hjLex_CodePointOfUTF8(hjLexer* _lexer, hjByteArray* _buf);
#endif
//hj_utf8.h
/*
hj_utf8.h文件是unicode utf8編碼模塊
*/
#ifndef _hj_utf8_h
#define _hj_utf8_h
#include"hj_common.h"
//獲取編碼UTF8後的字節數
hjPUBLIC uint32_t hjGet_ByteNumOfEncodedUTF8(int _value);
//獲取解碼UTF8後的字節數
hjPUBLIC uint32_t hjGet_ByteNumOfDecodedUTF8(uint8_t _byte);
//編碼UTF8
hjPUBLIC uint8_t hjEncodeUTF8(uint8_t* _buf, int _value);
//解碼UTF8
hjPUBLIC int hjDecodeUTF8(const uint8_t* _bytePtr, uint32_t _len);
#endif
//hj_vm.h
/*
hj_vm.h文件是虛擬機
*/
#ifndef _hj_vm_h
#define _hj_vm_h
#include"hj_error.h"
//初始化虛擬機
hjPUBLIC void hjInit_VM(hjVM* _vm);
//創建虛擬機
hjPUBLIC hjVM* hjNew_VM();
#endif
源文件
//hj_error.h
#include "hj_error.h"
/*
打印錯誤信息
*/
hjPUBLIC void hjError(void* _lexer, hjErrorType _errType, char* _errMsg) {
//設置異常信息的字體顏色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED); //高亮紅色
switch (_errType) {
case hjERROR_IO:
printf("[Error_io]");
break;
case hjERROR_MEM:
printf("[Error_mem]");
break;
case hjERROR_LEX:
printf("[Error_lex]");
break;
case hjERROR_PARSE:
printf("[Error_parse]");
break;
case hjERROR_RUNTIME:
printf("[Error_runtime]");
break;
case hjERROR_COMPILE:
printf("[Error_compile]");
break;
default:
break;
}
if (_lexer != NULL) {
hjLexer* myLexer = (hjLexer*)_lexer;
printf("file \"%s\",line %d,at \"%s\"=>", myLexer->file, myLexer->curToken.lineNo, myLexer->curToken.start);
}
printf("%s\n", _errMsg);
//恢復字體顏色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN);//白色
}
/*
打印錯誤信息
*/
hjPUBLIC void hjError_(void* _lexer, hjErrorType _errType, const char* _format, ...) {
char buf[512] = { '\0' };
va_list myVa;
va_start(myVa, _format);
vsnprintf(buf, 512, _format, myVa); //把可變參數列表按照_format的格式放入buf中
va_end(myVa);
//設置異常信息的字體顏色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED); //高亮紅色
switch (_errType) {
case hjERROR_IO:
case hjERROR_MEM:
fprintf(stderr, "%s:%d IN FUNCTION %s():%s\n", __FILE__, __LINE__, __func__, buf);
break;
case hjERROR_LEX:
case hjERROR_PARSE:
case hjERROR_COMPILE:
hjASSERT(_lexer != NULL, "lexer is null");
fprintf(stderr, "%s:%d \"%s\"\n",
((hjLexer*)_lexer)->file,
((hjLexer*)_lexer)->preToken.lineNo,
buf
);
break;
case hjERROR_RUNTIME:
fprintf(stderr, "%s\n", buf);
break;
default:
hjNOT_REACHED;
break;
}
//恢復字體顏色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN);//白色
//退出程序
exit(1);
}
//hj_mem.cpp
#include"hj_mem.h"
//申請內存
hjPUBLIC void* hjMemManager(hjVM* _vm, void* _ptr, uint32_t _oldSize, uint32_t _newSize) {
if (_newSize < 0 || _oldSize < 0)return NULL;//做個檢查
//累計系統分配的總內存
_vm->allocatedByte += _newSize - _oldSize;
/*
避免realloc(NULL,0)定義的新地址,此地址不能被釋放
realloc(NULL,0)會返回無法使用,也無法置空的非空指針
*/
if(_newSize==0){
free(_ptr);
_ptr = NULL;
return NULL;
}
//p變量是爲了避免返回空指針,把原來不爲空的指針置空了
void* p = realloc(_ptr, _newSize);
if (p == NULL) {
__hjERROR_MEM__("memory allocate failed!");
}
return p;
}
/*
找出大於等於_v的最近的2次冪
1U<<(log(v-1)+1)
向下找離2最近的2的次冪,然後再乘以一個2
*/
hjPUBLIC uint32_t hjNumOf2Pow_GE_v(uint32_t _v) {
//修復_v==0時結果爲0的情況,在_v==0時給_v設置爲1
_v += (_v == 0);
--_v;
//給_v開31次方
_v |= (_v >> 1);//除以2
_v |= (_v >> 2);//除以4
_v |= (_v >> 4);//除以16
_v |= (_v >>8);//除以64
_v |= (_v >> 16);//除以2^16
//
++_v;
return _v;
}
//清理符號表
hjPUBLIC void hjClear_SymbolTable(hjVM* _vm, hjSymbolTable* _table) {
uint32_t i = 0;
for (; i < _table->count;++i) {
hjMemManager(_vm, _table->data[i].str, 0, 0);
}
hjClear_StringArray(_vm, _table);
}
/*--------------------字符串數組方法--------------------*/
hjPUBLIC void hjInit_StringArray(hjStringArray* _arr) {
_arr->data = NULL;
_arr->capacity = _arr->count = 0;
}
hjPUBLIC void hjWrite_StringArray(hjVM* _vm, hjStringArray* _arr, hjString _data, uint32_t _fillCount) {
//當前已經存在的元素個數加上要添加的元素個數
uint32_t newCount = _arr->count + _fillCount;
if (newCount > _arr->capacity) { //要擴容了
size_t oldSize = _arr->capacity * sizeof(hjString);
_arr->capacity = hjNumOf2Pow_GE_v(newCount);//找出大於newCount的2次冪,做新的容量
size_t newSize = _arr->capacity * sizeof(hjString);
//新的尺寸還不如舊的尺寸的話,就報錯!
hjASSERT(newSize > oldSize, "faint ... memory allocate!");
//申請新的內存空間
_arr->data = (hjString*)hjMemManager(_vm, _arr->data, oldSize, newSize);
}
//添加數據
uint32_t i = 0;
for (; i < _fillCount; ++i, ++_arr->count) {
_arr->data[_arr->count] = _data;
}
}
hjPUBLIC void hjAdd_StringArray(hjVM* _vm, hjStringArray* _arr, hjString _data) {
hjWrite_StringArray(_vm, _arr, _data, 1);
}
hjPUBLIC void hjClear_StringArray(hjVM* _vm, hjStringArray* _arr) {
uint32_t size = _arr->capacity * sizeof(_arr->data[0]);
hjMemManager(_vm, _arr->data, size, 0);//size => 0
hjInit_StringArray(_arr);
}
/*--------------------字節數組方法--------------------*/
hjPUBLIC void hjInit_ByteArray(hjByteArray* _arr) {
_arr->data = NULL;
_arr->capacity = _arr->count = 0;
}
hjPUBLIC void hjWrite_ByteArray(hjVM* _vm, hjByteArray* _arr, uint8_t _data, uint32_t _fillCount) {
//當前已經存在的元素個數加上要添加的元素個數
uint32_t newCount = _arr->count + _fillCount;
if (newCount > _arr->capacity) { //要擴容了
size_t oldSize = _arr->capacity * sizeof(uint8_t);
_arr->capacity = hjNumOf2Pow_GE_v(newCount);//找出大於等於newCount的2次冪,做新的容量
size_t newSize = _arr->capacity * sizeof(uint8_t);
//新的尺寸還不如舊的尺寸的話,就報錯!
hjASSERT(newSize > oldSize, "faint ... memory allocate!");
//申請新的內存空間
_arr->data = (uint8_t*)hjMemManager(_vm, _arr->data, oldSize, newSize);
}
//添加數據
uint32_t i = 0;
for (; i < _fillCount; ++i, ++_arr->count) {
_arr->data[_arr->count] = _data;
}
}
hjPUBLIC void hjAdd_ByteArray(hjVM* _vm, hjByteArray* _arr, uint8_t _data) {
hjWrite_ByteArray(_vm, _arr, _data, 1);
}
hjPUBLIC void hjClear_ByteArray(hjVM* _vm, hjByteArray* _arr) {
uint32_t size = _arr->capacity * sizeof(_arr->data[0]);
hjMemManager(_vm, _arr->data, size, 0);//size => 0
hjInit_ByteArray(_arr);
}
/*--------------------字符數組方法--------------------*/
hjPUBLIC void hjInit_CharArray(hjCharArray* _arr) {
_arr->data = NULL;
_arr->capacity = _arr->count = 0;
}
hjPUBLIC void hjWrite_CharArray(hjVM* _vm, hjCharArray* _arr, char _data, uint32_t _fillCount) {
//當前已經存在的元素個數加上要添加的元素個數
uint32_t newCount = _arr->count + _fillCount;
if (newCount > _arr->capacity) { //要擴容了
size_t oldSize = _arr->capacity * sizeof(char);
_arr->capacity = hjNumOf2Pow_GE_v(newCount);//找出大於newCount的2次冪,做新的容量
size_t newSize = _arr->capacity * sizeof(char);
//新的尺寸還不如舊的尺寸的話,就報錯!
hjASSERT(newSize > oldSize, "faint ... memory allocate!");
//申請新的內存空間
_arr->data = (char*)hjMemManager(_vm, _arr->data, oldSize, newSize);
}
//添加數據
uint32_t i = 0;
for (; i < _fillCount; ++i, ++_arr->count) {
_arr->data[_arr->count] = _data;
}
}
hjPUBLIC void hjAdd_CharArray(hjVM* _vm, hjCharArray* _arr, char _data) {
hjWrite_CharArray(_vm, _arr, _data, 1);
}
hjPUBLIC void hjClear_CharArray(hjVM* _vm, hjCharArray* _arr) {
uint32_t size = _arr->capacity * sizeof(_arr->data[0]);
hjMemManager(_vm, _arr->data, size, 0);//size => 0
hjInit_CharArray(_arr);
}
/*--------------------int數組方法--------------------*/
hjPUBLIC void hjInit_IntArray(hjIntArray* _arr) {
_arr->data = NULL;
_arr->capacity = _arr->count = 0;
}
hjPUBLIC void hjWrite_IntArray(hjVM* _vm, hjIntArray* _arr, int _data, uint32_t _fillCount) {
//當前已經存在的元素個數加上要添加的元素個數
uint32_t newCount = _arr->count + _fillCount;
if (newCount > _arr->capacity) { //要擴容了
size_t oldSize = _arr->capacity * sizeof(int);
_arr->capacity = hjNumOf2Pow_GE_v(newCount);//找出大於newCount的2次冪,做新的容量
size_t newSize = _arr->capacity * sizeof(int);
//新的尺寸還不如舊的尺寸的話,就報錯!
hjASSERT(newSize > oldSize, "faint ... memory allocate!");
//申請新的內存空間
_arr->data = (int*)hjMemManager(_vm, _arr->data, oldSize, newSize);
}
//添加數據
uint32_t i = 0;
for (; i < _fillCount; ++i, ++_arr->count) {
_arr->data[_arr->count] = _data;
}
}
hjPUBLIC void hjAdd_IntArray(hjVM* _vm, hjIntArray* _arr, int _data) {
hjWrite_IntArray(_vm, _arr, _data, 1);
}
hjPUBLIC void hjClear_IntgArray(hjVM* _vm, hjIntArray* _arr) {
uint32_t size = _arr->capacity * sizeof(_arr->data[0]);
hjMemManager(_vm, _arr->data, size, 0);//size => 0
hjInit_IntArray(_arr);
}
//hj_utf8.cpp
#include"hj_utf8.h"
//獲取編碼UTF8後的字節數
hjPUBLIC uint32_t hjGet_ByteNumOfEncodedUTF8(int _value) {
hjASSERT(_value > 0, "can't encode negative value!");
//單個ASCII一個字節
if (_value <= 0x7f)return 1;
//此範圍內數值編碼爲UTF8需要2字節
if (_value <= 0x7ff)return 2;
//此範圍內數值編碼爲UTF8需要3字節
if (_value <= 0xffff)return 3;
//此範圍內數值編碼爲UTF8需要4字節
if (_value <= 0x10ffff)return 4;
//超過範圍返回0
return 0;
}
//獲取解碼UTF8後的字節數
hjPUBLIC uint32_t hjGet_ByteNumOfDecodedUTF8(uint8_t _byte) {
//_byte應該是UTF8的最高一字節,如果指定了UTF8編碼後面的低字節部分則返回0
if ((_byte & 0xc0) == 0x80)return 0;
if ((_byte & 0xf8) == 0xf0)return 4;
if ((_byte & 0xf0) == 0xe0)return 3;
if ((_byte & 0xe0) == 0xc0)return 2;
//ASCII碼
return 1;
}
//編碼UTF8
hjPUBLIC uint8_t hjEncodeUTF8(uint8_t* _buf, int _value) {
hjASSERT(_value > 0, "can't encode negative value!");
/*按照大端模式寫入緩衝區*/
//單個ASCII一個字節
if (_value <= 0x7f) {
*_buf = _value & 0x7f;
return 1;
}
//此範圍內數值編碼爲UTF8需要2字節
if (_value <= 0x7ff) {
//先寫入高字節
*_buf++ = 0xc0 | ((_value & 0x7c0) >> 6);
//再寫入低字節
*_buf = 0x80 | (_value & 0x3f);
return 2;
}
//此範圍內數值編碼爲UTF8需要3字節
if (_value <= 0xffff) {
//先寫入高字節
*_buf++ = 0xe0 | ((_value & 0xf000) >> 12);
//再寫入中字節
*_buf++ = 0x80 | ((_value & 0xfc0) >> 6);
//再寫入低字節
*_buf = 0x80 | (_value & 0x3f);
return 3;
}
//此範圍內數值編碼爲UTF8需要4字節
if (_value <= 0x10ffff){
*_buf++ = 0xf0 | ((_value & 0x1c0000) >> 18);
*_buf++ = 0x80 | ((_value & 0x3f000) >> 12);
*_buf++ = 0x80 | ((_value & 0xfc0) >> 6);
*_buf = 0x80 | (_value & 0x3f);
return 4;
}
hjNOT_REACHED;
//超過範圍返回0
return 0;
}
//解碼UTF8
hjPUBLIC int hjDecodeUTF8(const uint8_t* _bytePtr, uint32_t _len) {
//如果是一字節的ASCII碼:0xxx'xxxx
if (*_bytePtr <= 0x7f)return *_bytePtr;
int value;
uint32_t remainingBytes;
/*先讀取高字節*/
if ((*_bytePtr & 0xe0) == 0xc0) { //如果是2字節的UTF8
value = *_bytePtr & 0x1f;
remainingBytes = 1;
}
else if ((*_bytePtr & 0xf0) == 0xe0) { //如果是3字節的UTF8
value = *_bytePtr & 0x0f;
remainingBytes = 2;
}
else if ((*_bytePtr & 0xf8) == 0xf0) { //如果是4字節的UTF8
value = *_bytePtr & 0x07;
remainingBytes = 3;
}
else { //非法編碼
return -1;
}
/*如果UTF8被折斷就不再讀過去了*/
if (remainingBytes > _len - 1)return -1;
/*再讀取低字節*/
for (; remainingBytes > 0;) {
++_bytePtr;
--remainingBytes;
//高2位必須是10
if ((*_bytePtr & 0xc0) != 0x80)return -1;
//從次高序往低字節讀,不斷累加各字節的低6位
value = value << 6 | (*_bytePtr & 0x3f);
}
return value;
}
//hj_lexer.cpp
#include"hj_lexer.h"
/*初始化全局變量*/
char* hj_rootDir="";
/*定義私有化結構體和映射表*/
//關鍵字
typedef struct hjKeyToken {
char* keyword; //關鍵字字符串
uint8_t len; //字符串長度
hjTokenType type; //關鍵字類型
}hjKeyToken;
//關鍵字映射表
hjKeyToken hjMap_KeyToken[] = {
{"let",3,hjTOKEN_LET},
{"function",8,hjTOKEN_FUNCTION},
{"if",2,hjTOKEN_IF},
{"else",4,hjTOKEN_ELSE},
{"hjTRUE",4,hjTOKEN_TRUE},
{"hjFALSE",5,hjTOKEN_FALSE},
{"while",5,hjTOKEN_WHILE},
{"for",3,hjTOKEN_FOR},
{"break",5,hjTOKEN_BREAK},
{"continue",8,hjTOKEN_CONTINUE},
{"return",6,hjTOKEN_RETURN},
{"Nil",3,hjTOKEN_NIL},
{"class",5,hjTOKEN_CLASS},
{"self",4,hjTOKEN_SELF},
{"static",6,hjTOKEN_STATIC},
{"is",2,hjTOKEN_IS},
{"super",5,hjTOKEN_SUPER},
{"import",6,hjTOKEN_IMPORT}
};
//讀取腳本
hjPUBLIC char* hjReadScript(const char* _path) {
FILE* file = fopen(_path, "r");
if (file == NULL) {
__hjERROR_IO__("Couldn't open file \"%s\".", _path);
}
//獲取文件大小
struct stat myStat;
stat(_path, &myStat);
size_t fileSize = myStat.st_size;
char* fileContent = (char*)malloc(1 + fileSize);
if (fileContent == NULL) {
__hjERROR_MEM__("Couldn't allocate memory for reading file \"%s\".\n", _path);
}
//將文件中的內容按char的步長讀取進fileContent內
if (fread(fileContent, sizeof(char), fileSize, file) == 0) {
__hjERROR_IO__("Couldn't read file \"%s\".", _path);
}
fileContent[fileSize] = '\0';
fclose(file);
return fileContent;
}
//初始化詞法分析器
hjPUBLIC hjInit_Lexer(hjVM* _vm, hjLexer* _lexer, const char* _file, const char* _srcCode) {
//設置文件路徑
_lexer->file = _file;
//設置源碼字符串
_lexer->srcCode = _srcCode;
//設置當前字符
_lexer->curChar = *_srcCode;
//設置下一個字符指針
_lexer->next = _lexer->srcCode + 1;
//初始化當前單詞
_lexer->curToken.lineNo = 1;
_lexer->curToken.len = 0;
_lexer->curToken.start = NULL;
_lexer->curToken.type = hjTOKEN_UNKNOWN;
//初始先前單詞
_lexer->preToken = _lexer->curToken;
//初始化(計數器
_lexer->Lcounter = 0;
//初始化虛擬機
_lexer->vm = _vm;
}
//查看下一個字符
hjPUBLIC char hjPeek_NextChar(hjLexer* _lexer) {
return *(_lexer->next);
}
//獲取下一個單詞
hjPUBLIC void hjGet_NextToken(hjLexer* _lexer) {
/*當前單詞指針後移*/
_lexer->preToken = _lexer->curToken;
//跳過待識別單詞之間的空格
hjSkip_Blanks(_lexer);
//初始化當前單詞
_lexer->curToken.type = hjTOKEN_EOF;
_lexer->curToken.len = 0;
_lexer->curToken.start = _lexer->next - 1;
for (;_lexer->curChar!='\0';) {
switch (_lexer->curChar) {
/*
case '@':
_lexer->curToken.type = hjTOKEN_AT;
break;
case '#':
_lexer->curToken.type = hjTOKEN_WELL;
break;
case '`': //重音
_lexer->curToken.type = hjTOKEN_ACCENT;
break;
case ';': //分號
_lexer->curToken.type = hjTOKEN_SEMI;
break;
case '\\': 反斜槓
_lexer->curToken.type = hjTOKEN_SEMI;
break;
*/
case ':': //冒號
_lexer->curToken.type = hjTOKEN_COLON;
break;
case ',': //逗號
_lexer->curToken.type = hjTOKEN_COMMA;
break;
case '.': //點
if (hjMatch_NextChar(_lexer, '.')) {//兩個連續的點
_lexer->curToken.type = hjTOKEN_DOT_DOT;
}
else {//一個點
_lexer->curToken.type = hjTOKEN_DOT;
}
break;
case '(':
if (_lexer->Lcounter > 0) {
++_lexer->Lcounter;//遇到(加一
}
_lexer->curToken.type = hjTOKEN_LEFT_PAREN;
break;
case ')':
if (_lexer->Lcounter > 0) {
--_lexer->Lcounter;//遇到)減一
if (_lexer->Lcounter == 0) {
hjLex_Str(_lexer);
break;
}
}
_lexer->curToken.type = hjTOKEN_RIGHT_PAREN;
break;
case '[':
_lexer->curToken.type = hjTOKEN_LEFT_BRACKET;
break;
case ']':
_lexer->curToken.type = hjTOKEN_RIGHT_BRACKET;
break;
case '{':
_lexer->curToken.type = hjTOKEN_LEFT_BRACE;
break;
case '}':
_lexer->curToken.type = hjTOKEN_RIGHT_BRACE;
break;
case '=':
if (hjMatch_NextChar(_lexer, '=')) {//判斷等於
_lexer->curToken.type = hjTOKEN_EQ;
}
else {//賦值
_lexer->curToken.type = hjTOKEN_ASSIGN;
}
break;
case '+':
_lexer->curToken.type = hjTOKEN_ADD;
break;
case '-':
_lexer->curToken.type = hjTOKEN_SUB;
break;
case '*':
_lexer->curToken.type = hjTOKEN_MUL;
break;
case '/':
if (hjMatch_NextChar(_lexer,'/') ) { //單行註釋
hjSkip_CommentALine(_lexer);
_lexer->curToken.start = _lexer->next - 1;
continue;
}
else if (hjMatch_NextChar(_lexer, '*')) { //多行註釋
hjSkip_Comment(_lexer);
_lexer->curToken.start = _lexer->next - 1;
continue;
}
else { //除號
_lexer->curToken.type = hjTOKEN_DIV;
}
break;
case '%':
_lexer->curToken.type = hjTOKEN_MOD;
break;
case '^':
_lexer->curToken.type = hjTOKEN_POW;
break;
case '&':
if (hjMatch_NextChar(_lexer, '&')) {//邏輯與
_lexer->curToken.type = hjTOKEN_LOGIC_AND;
}
else {//位運算與
_lexer->curToken.type = hjTOKEN_BIT_AND;
}
break;
case '|':
if (hjMatch_NextChar(_lexer, '|')) {//邏輯或
_lexer->curToken.type = hjTOKEN_LOGIC_OR;
}
else {//位運算或
_lexer->curToken.type = hjTOKEN_BIT_OR;
}
break;
case '!':
if (hjMatch_NextChar(_lexer, '=')) {//不等於
_lexer->curToken.type = hjTOKEN_NEQ;
}
else {//邏輯非
_lexer->curToken.type = hjTOKEN_LOGIC_NOT;
}
break;
case '~':
_lexer->curToken.type = hjTOKEN_BIT_NOT;
break;
case '<':
if (hjMatch_NextChar(_lexer, '=')) {//<=
_lexer->curToken.type = hjTOKEN_LE;
}
else {//<
_lexer->curToken.type = hjTOKEN_LT;
}
break;
case '>':
if (hjMatch_NextChar(_lexer, '=')) {//>=
_lexer->curToken.type = hjTOKEN_GE;
}
else {//>
_lexer->curToken.type = hjTOKEN_GT;
}
break;
case '?':
_lexer->curToken.type = hjTOKEN_QUE;
break;
case '"': //雙引號
hjLex_Str(_lexer);
break;
/*eol、eof 沒有處理。eof沒辦法處理,但是eol之後可以想法處理一下 */
default:
//如果首字符是字母或下劃線
if (hjJudge_Alpha(_lexer->curChar) || _lexer->curChar == '_') {
hjLex_Id(_lexer,hjTOKEN_UNKNOWN);
}
//不處理#!及其後面的內容
else if (_lexer->curChar == '#' && hjMatch_NextChar(_lexer, '!')) {
hjSkip_ALine(_lexer);
_lexer->curToken.start = _lexer->next - 1;
continue;
}
else{
///__hjERROR_LEX__(_lexer, "unsupport char : \"%c\" , quit.", _lexer->curChar);
}
return;
}
/*默認執行上面操作一次就退出了,但是可能遇到continue,那樣就可能循環幾遍*/
_lexer->curToken.len = (uint32_t)(_lexer->next - _lexer->curToken.start);
hjGet_NextChar(_lexer);
return;
}
}
/*
匹配單詞
如果當前token是所期望的話,就讀入下一個token並返回true,否則返回false
*/
hjPUBLIC hjBOOL hjMatch_Token(hjLexer* _lexer, hjTokenType _expectedToken) {
if (_lexer->curToken.type == _expectedToken) {
hjGet_NextToken(_lexer);
return hjTRUE;
}
return hjFALSE;
}
/*
吸收當前單詞
斷言當前token爲所期望的話,就讀入下一個token,否則報錯
*/
hjPUBLIC void hjConsume_CurToken(hjLexer* _lexer, hjTokenType _expectedToken, const char* _errMsg) {
if (_lexer->curToken.type == _expectedToken) {
hjGet_NextToken(_lexer);
}
else {
__hjERROR_COMPILE__(_lexer, _errMsg);
}
}
/*
吸收下一個單詞
斷言當前token爲所期望的,否則報錯
*/
hjPUBLIC void hjConsume_NextToken(hjLexer* _lexer, hjTokenType _expectedToken, const char* _errMsg) {
hjGet_NextToken(_lexer);
if (_lexer->curToken.type != _expectedToken) {
__hjERROR_COMPILE__(_lexer, _errMsg);
}
}
//判斷是否是數字
hjPRIVATE hjBOOL hjJudge_Num(char _c) {
if (_c <= 57 && _c >= 48)return hjTRUE;
return hjFALSE;
}
//判斷是否是字母
hjPRIVATE hjBOOL hjJudge_Alpha(char _c) {
if ((_c <= 90 && _c >= 65 )|| (_c<= 122&& _c>= 97) )return hjTRUE;
return hjFALSE;
}
/*
判斷是標識符還是關鍵字
輸入的字符串肯定是標識符或者是關鍵字,這個函數就是具體區分一下到底是哪種
關鍵字,還是標識符!
*/
hjPRIVATE hjTokenType hjJudge_IdOrKey(const char* _start, uint32_t _len) {
uint32_t i ;
for (i=0; hjMap_KeyToken[i].keyword != NULL;++i) {
if (hjMap_KeyToken[i].len == _len && \
memcmp(hjMap_KeyToken[i].keyword ,_start,_len ) == 0) {
return hjMap_KeyToken[i].type;//返回具體的關鍵字類型
}
}
//如果不是關鍵字那就是標識符了
return hjTOKEN_ID;
}
//獲取下一個字符
hjPRIVATE void hjGet_NextChar(hjLexer* _lexer) {
_lexer->curChar = *(_lexer->next);//下一個字符當做是當前字符
++_lexer->next;//下一個字符後(這個指針的移動應該是在srcCode上移動的)
}
/*
匹配下一個字符
如果匹配上了,就後移當前字符指針,否則就不移動!
*/
hjPRIVATE hjBOOL hjMatch_NextChar(hjLexer* _lexer,char _expectedChar) {
if ( hjPeek_NextChar(_lexer)== _expectedChar ) {//如果下一個字符是我所希望的字符的話,就獲取該字符
hjGet_NextChar(_lexer);
return hjTRUE;
}
return hjFALSE;
}
//跳過連續的空字符
hjPRIVATE void hjSkip_Blanks(hjLexer* _lexer) {
for (;_lexer->curChar == ' '||_lexer->curChar=='\n'||_lexer->curChar=='\t'||_lexer->curChar=='\r';) {
if (_lexer->curChar == '\n') {
++_lexer->curToken.lineNo;//行數加一
}
hjGet_NextChar(_lexer);
}
}
//跳過單行註釋
hjPRIVATE void hjSkip_CommentALine(hjLexer* _lexer) {
//跳過一行
hjSkip_ALine(_lexer);
//註釋之後有可能會有空白字符
hjSkip_Blanks(_lexer);
}
//跳過多行註釋
hjPRIVATE void hjSkip_Comment(hjLexer* _lexer) {
char nextChar = hjPeek_NextChar(_lexer);
//吸收註釋內的字符
for (; nextChar != '*' && nextChar != '\0';) {
hjGet_NextChar(_lexer);
if (_lexer->curChar == '\n') {
++_lexer->curToken.lineNo;//行數加一
}
nextChar = hjPeek_NextChar(_lexer);
}
//匹配 */
if (hjMatch_NextChar(_lexer, '*')) {
if (!hjMatch_NextChar(_lexer, '/')) {
__hjERROR_LEX__(_lexer, "expect \"/\" after \"*\"!");
}
hjGet_NextChar(_lexer);
}
else {
__hjERROR_LEX__(_lexer, "expect \"*/\" before file end!");
}
//註釋之後有可能會有空白字符
hjSkip_Blanks(_lexer);
}
//跳過一行
hjPRIVATE void hjSkip_ALine(hjLexer* _lexer) {
hjGet_NextChar(_lexer);
for (;_lexer->curChar!='\0';) {
if (_lexer->curChar=='\n') {
++_lexer->curToken.lineNo;//行數加一
hjGet_NextChar(_lexer);
break;
}
hjGet_NextChar(_lexer);
}
}
//解析標識符
hjPRIVATE void hjLex_Id(hjLexer* _lexer, hjTokenType _token) {
//標識符是字母或下劃線開頭的,後面是連續的字母或數字或下劃線
for (;hjJudge_Num(_lexer->curChar)|| hjJudge_Alpha(_lexer->curChar) || _lexer->curChar == '_';) {
hjGet_NextChar(_lexer);
}
//next指向第一個不合法字符的下一個字符,因此要-1
uint32_t len = (uint32_t)(_lexer->next - _lexer->curToken.start - 1);
if (_token != hjTOKEN_UNKNOWN) {
_lexer->curToken.type = _token;
}
else { //是關鍵字或者是標識符
_lexer->curToken.type = hjJudge_IdOrKey(_lexer->curToken.start, len);
}
_lexer->curToken.len = len;
}
//解析字符串
hjPRIVATE void hjLex_Str(hjLexer* _lexer) {
hjByteArray str;
hjInit_ByteArray(&str);
for (;1;) {
hjGet_NextChar(_lexer);
if (_lexer->curChar == '\0') {
__hjERROR_LEX__(_lexer, "unterminated string!");
}
else if (_lexer->curChar == '"') { //雙引號
_lexer->curToken.type = hjTOKEN_STR;
break;
}
else if (_lexer->curChar == '%') {
if (!hjMatch_NextChar(_lexer, '(')) { //%後面沒有跟着(
__hjERROR_LEX__(_lexer, "\"%\" should followed by \"(\"!");
}
if(_lexer->Lcounter>0){ //
__hjERROR_COMPILE__(_lexer, "not support nest interpolate expression");
}
_lexer->Lcounter = 1;
_lexer->curToken.type = hjTOKEN_EXPR;
break;
}
/*處理轉移字符*/
if (_lexer->curChar == '\\') {
hjGet_NextChar(_lexer);
switch (_lexer->curChar) {
case '0':
hjAdd_ByteArray(_lexer->vm, &str, '\0');
break;
case 'a':
hjAdd_ByteArray(_lexer->vm, &str, '\a');
break;
case 'b':
hjAdd_ByteArray(_lexer->vm, &str, '\b');
break;
case 'f':
hjAdd_ByteArray(_lexer->vm, &str, '\f');
break;
case 'n':
hjAdd_ByteArray(_lexer->vm, &str, '\n');
break;
case 'r':
hjAdd_ByteArray(_lexer->vm, &str, '\r');
break;
case 't':
hjAdd_ByteArray(_lexer->vm, &str, '\t');
break;
case 'u':
hjLex_CodePointOfUTF8(_lexer, &str);
break;
case '"': //雙引號
hjAdd_ByteArray(_lexer->vm, &str, '"');
break;
case '\\':
hjAdd_ByteArray(_lexer->vm, &str, '\\');
break;
default:
__hjERROR_LEX__(_lexer, "unsupport escape \\%c", _lexer->curChar);
break;
}
}
else {
hjAdd_ByteArray(_lexer->vm, &str, _lexer->curChar);
}
}
hjClear_ByteArray(_lexer->vm, &str);
}
//解析UTF8碼點
hjPRIVATE void hjLex_CodePointOfUTF8(hjLexer* _lexer, hjByteArray* _buf) {
uint32_t i;
int value = 0;
uint8_t digit = 0;
//獲得數值,u後面跟着4位16進制數字
for (i=0;i<4;) {
++i;
hjGet_NextChar(_lexer);
if (_lexer->curChar == '\0') {
__hjERROR_LEX__(_lexer, "unterminated unicode!");
}
else if (_lexer->curChar >= '0' && _lexer->curChar <= '9') {
digit = _lexer->curChar - '0';
}
else if (_lexer->curChar >= 'a' && _lexer->curChar <= 'f') {
digit = _lexer->curChar - 'a'+10;
}
else if (_lexer->curChar >= 'A' && _lexer->curChar <= 'F') {
digit = _lexer->curChar - 'A' + 10;
}
else{
__hjERROR_LEX__(_lexer, "invalid unicode!");
}
value = (value * 16) | digit;
}
uint32_t byteNum = hjGet_ByteNumOfEncodedUTF8(value);
hjASSERT(byteNum != 0, "utf8 encode bytes should be between 1 and 4 ");
/*
爲了代碼通用,下面會直接寫 _buf->data ,在此先寫入byteNum個0,
以保證事先有byteNum個空間
*/
hjWrite_ByteArray(_lexer->vm, _buf, 0, byteNum);
//把value編碼成utf8後寫入緩衝區
hjEncodeUTF8(_buf->data + _buf->count - byteNum, value);
}
//hj_vm.cpp
#include"hj_vm.h"
//初始化虛擬機
hjPUBLIC void hjInit_VM(hjVM* _vm) {
_vm->allocatedByte = 0;
_vm->curLexer = NULL;
}
//創建虛擬機
hjPUBLIC hjVM* hjNew_VM() {
hjVM* vm = (hjVM*)malloc(sizeof(hjVM));
if (vm == NULL) {
}
hjInit_VM(vm);
return vm;
}
主函數的文件hj.cpp
//hj.cpp
#include"hj_lexer.h"
/*
項目文件引用關係——下次做個打印文件引用關係的工具!!!
common
|————core
| |————error
| | |————vm
| | |————lexer
| |
| |————mem
| | |————lexer
| | | |
| | |
|
|
|
|————utf8
| |————lexer
*/
void test_error() {
hjLexer* myLexer = (hjLexer*)malloc(sizeof(hjLexer));
hjToken* myToken = (hjToken*)malloc(sizeof(hjToken));
myToken->lineNo = 50;
myToken->start = "function";
myToken->type = hjTOKEN_FUNCTION;
myLexer->curToken = *myToken;
myLexer->file = "E:\\C\\hjRun.hj";
hjError(myLexer, hjERROR_MEM, "出錯了!!!");
}
//執行腳本文件
hjPRIVATE void hjRunScript(const char* _path) {
const char* lastSlash = strrchr(_path, '/');
if (lastSlash != NULL) {
char* root = (char*)malloc(lastSlash - _path + 2);
memcpy(root, _path, lastSlash - _path + 1);
root[lastSlash - _path + 1] = '\0';
hj_rootDir = root;
}
//創建虛擬機
hjVM* vm = hjNew_VM();
//讀取腳本
const char* srcCode = hjReadScript(_path);
//創建詞法分析器
hjLexer myLexer;
hjInit_Lexer(vm, &myLexer, _path, srcCode);
//導入單詞表
#include "token.list"
uint32_t i = 0;
for (; myLexer.curToken.type != hjTOKEN_EOF;) {
hjGet_NextToken(&myLexer);
//打印行號和單詞類型
printf("%d:%s[", myLexer.curToken.lineNo, hjTokenArr[myLexer.curToken.type]);
//打印單詞
for (i=0; i < myLexer.curToken.len;++i) {
printf("%c", *(myLexer.curToken.start+i));
}
printf("]\n");
}
}
int main(int argc,const char** argv) {
argc = 2;
argv[1] = "test.hj";
//test_error();
if (argc < 2) {
printf("參數不夠");
return 0;
}
hjRunScript(argv[1]);
system("pause");
return 0;
}
token.list
這個無所謂,把數組放在其他文件也一樣!
char* hjTokenArr[] = {
"UNKNOWN",
"NUM",
"STR",
"ID",
"EXPR",
"LET",
"FUNCTION",
"IF",
"ELSE",
"TRUE",
"FALSE",
"WHILE",
"FOR",
"BREAK",
"CONTINUE",
"RETURN",
"NIL",
"CLASS",
"SELF",
"STATIC",
"IS",
"SUPER",
"IMPORT",
"AT",
"WELL",
"ACCENT",
"SEMI",
"BACKSLASH",
"COLON",
"COMMA",
"DOT",
"DOT_DOT",
"LEFT_PAREN",
"RIGHT_PAREN",
"LEFT_BRACKET",
"RIGHT_BRACKET",
"LEFT_BRACE",
"RIGHT_BRACE",
"ASSIGN",
"ADD",
"SUB",
"MUL",
"DIV",
"MOD",
"POW",
"BIT_AND",
"BIT_OR",
"BIT_NOT",
"BIT_SHIFT_LEFT",
"BIT_SHIFT_RRIGHT",
"LOGIC_AND",
"LOGIC_OR",
"LOGIC_NOT",
"EQ",
"NEQ",
"GT",
"GE",
"LT",
"LE",
"QUE",
"EOL",
"EOF"
};
測試文件test.hj
// 單行註釋
/*
多
行
注
釋
*/
import people for People
function func(){
print("hello word")
let p = People.new("demllie","turtle")
p.run()
}
class Family : People{
let father
let mother
let child
new(f,m,c){
father = f
mother = m
child = c
super("Kiana","wife")
}
}
let f = Family.new("Kiana","female","shine")
f.run()
func()
運行結果
8:IMPORT[import]
8:ID[people]
8:FOR[for]
8:ID[People]
9:FUNCTION[function]
9:ID[func]
9:LEFT_PAREN[(]
9:RIGHT_PAREN[)]
9:LEFT_BRACE[{]
10:ID[print]
10:LEFT_PAREN[(]
10:STR["hello word"]
10:RIGHT_PAREN[)]
11:LET[let]
11:ID[p]
11:ASSIGN[=]
11:ID[People]
11:DOT[.]
11:ID[new]
11:LEFT_PAREN[(]
11:STR["demllie"]
11:COMMA[,]
11:STR["turtle"]
11:RIGHT_PAREN[)]
12:ID[p]
12:DOT[.]
12:ID[run]
12:LEFT_PAREN[(]
12:RIGHT_PAREN[)]
13:RIGHT_BRACE[}]
16:CLASS[class]
16:ID[Family]
16:COLON[:]
16:ID[People]
16:LEFT_BRACE[{]
17:LET[let]
17:ID[father]
18:LET[let]
18:ID[mother]
19:LET[let]
19:ID[child]
20:ID[new]
20:LEFT_PAREN[(]
20:ID[f]
20:COMMA[,]
20:ID[m]
20:COMMA[,]
20:ID[c]
20:RIGHT_PAREN[)]
20:LEFT_BRACE[{]
21:ID[father]
21:ASSIGN[=]
21:ID[f]
22:ID[mother]
22:ASSIGN[=]
22:ID[m]
23:ID[child]
23:ASSIGN[=]
23:ID[c]
25:SUPER[super]
25:LEFT_PAREN[(]
25:STR["Kiana"]
25:COMMA[,]
25:STR["wife"]
25:RIGHT_PAREN[)]
26:RIGHT_BRACE[}]
27:RIGHT_BRACE[}]
30:LET[let]
30:ID[f]
30:ASSIGN[=]
30:ID[Family]
30:DOT[.]
30:ID[new]
30:LEFT_PAREN[(]
30:STR["Kiana"]
30:COMMA[,]
30:STR["female"]
30:COMMA[,]
30:STR["shine"]
30:RIGHT_PAREN[)]
31:ID[f]
31:DOT[.]
31:ID[run]
31:LEFT_PAREN[(]
31:RIGHT_PAREN[)]
33:ID[func]
33:LEFT_PAREN[(]
33:RIGHT_PAREN[)]
35:EOF[]
最後
除了編碼風格外,文件依賴關係也變了,增加了幾種token類型,更改了關鍵字!
hj=happy joy
參考:《自制編程語言,基於C語言》