【全代码】《基于C语言自制编程语言》词法分析器

前言

这本书的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语言》

相关推荐
带完整书签 第1章 引子 001 1.1 为什么要制作编程语言 002 1.2 自制编程语言并不是很难 003 1.3 本书的构成与面向读者 004 1.4 用什么语言来制作 006 1.5 要制作怎样的语言 007 1.5.1 要设计怎样的语法 007 1.5.2 要设计怎样的运行方式 009 补充知识 “用户”指的是谁? 012 补充知识 解释器并不会进行翻译 012 1.6 环境搭建 012 1.6.1 搭建开发环境 012 补充知识 关于bison与flex的安装 014 1.6.2 本书涉及的源代码以及编译器 015 第2章 试做一个计算器 017 2.1 yacc/lex是什么 018 补充知识 词法分析器与解析器是各自独立的 019 2.2 试做一个计算器 020 2.2.1 lex 021 2.2.2 简单正则表达式讲座 024 2.2.3 yacc 026 2.2.4 生成执行文件 033 2.2.5 理解冲突所代表的含义 034 2.2.6 错误处理 040 2.3 不借助工具编写计算器 041 2.3.1 自制词法分析器 041 补充知识 保留字(关键字) 046 补充知识 避免重复包含 047 2.3.2 自制语法分析器 048 补充知识 预读记号的处理 053 2.4 少许理论知识——LL(1)与LALR(1) 054 补充知识 Pascal/C中的语法处理诀窍 056 2.5 习题:扩展计算器 056 2.5.1 让计算器支持括号 056 2.5.2 让计算器支持负数 058 第3章 制作无类型语言crowbar 061 3.1 制作crowbarver.0.1 语言的基础部分 062 3.1.1 crowbar是什么 062 3.1.2 程序的结构 063 3.1.3 数据类型 064 3.1.4 变量 064 补充知识 初次赋值兼做变量声明的理由 066 补充说明 各种语言局变量处理 067 3.1.5 语句与结构控制 067 补充知识 elif、elsif、elseif的选择 068 3.1.6 语句与运算符 069 3.1.7 内置函数 069 3.1.8 让crowbar支持C语言调用 070 3.1.9 从crowbar中调用C语言(内置函数的编写) 071 3.2 预先准备 071 3.2.1 模块与命名规则 072 3.2.2 内存管理模块MEM 073 补充知识 valgrind 075 补充知识 富翁式编程 075 补充知识 符号表与扣留操作 076 3.2.3 调试模块DBG 076 3.3 crowbarver.0.1 的实现 077 3.3.1 crowbar的解释器——CRB_Interpreter 077 补充知识 不完类型 080 3.3.2 词法分析——crowbar.l 081 补充知识 静态变量的许可范围 084 3.3.3 分析树的构建——crowbar.y与create.c 085 3.3.4 常量折叠 089 3.3.5 错误信息 089 补充知识 关于crowbar中使用的枚举型定义 091 3.3.6 运行——execute.c 092 3.3.7 表达式评估——eval.c 096 3.3.8 值——CRB_Value 104 3.3.9 原生指针型 105 3.3.1 0变量 106 3.3.1 1字符串与垃圾回收机制——string_pool.c 108 3.3.1 2编译与运行 110 第4章 数组和mark-sweep垃圾回收器 113 4.1 crowbarver. 0.2 114 4.1.1 crowbar的数组 114 4.1.2 访问数组元素 115 4.1.3 数组是一种引用类型 116 补充知识 “数组的数组”和多维数组 116 4.1.4 为数组添加元素 118 4.1.5 增加(模拟)函数调用功能 118 4.1.6 其他细节 118 4.2 制作mark-sweepGC 119 4.2.1 引用数据类型的结构 119 4.2.2 mark-sweepGC 121 补充知识 引用和immutable 123 4.2.3 crowbar栈 124 4.2.4 其他根 127 4.2.5 原生函数的形式参数 128 4.3 实现GC本身 129 4.3.1 对象的管理方法 129 4.3.2 GC何时启动 129 4.3.3 sweep阶段 132 补充知识 GC现存的问题 133 补充知识 CopingGC 134 4.4 其他修改 136 4.4.1 修改语法 136 4.4.2 函数的模拟 137 4.4.3 左值的处理 139 4.4.4 创建数组和原生函数的书写方法 142 4.4.5 原生指针类型的修改 144 第5章 中文支持和Unicode 147 5.1 中文支持策略和基础知识 148 5.1.1 现存问题 148 5.1.2 宽字符(双字节)串和多字节字符串 149 补充知识 wchar_t肯定能表示1个字符吗? 150 5.1.3 多字节字符/宽字符之间的转换函数群 150 5.2 Unicode 153 5.2.1 Unicode的历史 153 5.2.2 Unicode的编码方式 154 补充知识 Unicode可以固定(字节)长度吗? 156 5.3 crowbarbook_ver.0.3 的实现 156 5.3.1 要实现到什么程度? 156 5.3.2 发起转换的时机 157 5.3.3 关于区域设置 158 5.3.4 解决0x5C问题 158 补充知识 失败的#ifdef 160 5.3.5 应该是什么样子 160 补充知识 还可以是别的样子——CodeSetIndependent 161 第6章 制作静态类型的语言Diksam 163 6.1 制作DiksamVer0.1 语言的基本部分 164 6.1.1 Diksam的运行状态 164 6.1.2 什么是Diksam 165 6.1.3 程序结构 165 6.1.4 数据类型 166 6.1.5 变量 166 6.1.6 语句和流程控制 167 6.1.7 表达式 167 6.1.8 内建函数 168 6.1.9 其他 168 6.2 什么是静态的/执行字节码的语言 169 6.2.1 静态类型的语言 169 6.2.2 什么是字节码 169 6.2.3 将表达式转换为字节码 170 6.2.4 将控制结构转换为字节码 173 6.2.5 函数的实现 173 6.3 Diksamver.0.1 的实现——编译篇 175 6.3.1 目录结构 175 6.3.2 编译的概要 176 6.3.3 构建分析树(create.c) 176 6.3.4 修正分析树(fix_tree.c) 179 6.3.5 Diksam的运行形式——DVM_Executable 185 6.3.6 常量池 186 补充知识 YARV的情况 187 6.3.7 局变量 188 6.3.8 函数 189 6.3.9 顶层结构的字节码 189 6.3.1 0行号对应表 190 6.3.1 1栈的需要量 190 6.3.1 2生成字节码(generate.c) 191 6.3.1 3生成实际的编码 193 6.4 Diksam虚拟机 197 6.4.1 加载/链接DVM_Executable到DVM 200 6.4.2 执行——巨大的switchcase 202 6.4.3 函数调用 204 第7章 为Diksam引入数组 207 7.1 Diksam中数组的设计 208 7.1.1 声明数组类型的变量 208 7.1.2 数组常量 209 补充知识 D语言的数组 210 7.2 修改编译器 210 7.2.1 数组的语法规则 210 7.2.2 TypeSpecifier结构体 212 7.3 修改DVM 213 7.3.1 增加指令 213 补充知识 创建Java的数组常量 215 补充知识 C语言中数组的初始化 217 7.3.2 对象 217 补充知识 ArrayStoreException 218 7.3.3 增加null 219 7.3.4 哎!还缺点什么吧? 219 第8章 将类引入Diksam 221 8.1 分割源文件 222 8.1.1 包和分割源代码 222 补充知识 #include、文件名、行号 225 8.1.2 DVM_ExecutableList 225 8.1.3 ExecutableEntry 226 8.1.4 分开编译源代码 227 8.1.5 加载和再链接 230 补充知识 动态加载时的编译器 233 8.2 设计Diksam中的类 233 8.2.1 超简单的面向对象入门 233 8.2.2 类的定义和实例创建 237 8.2.3 继承 239 8.2.4 关于接口 241 8.2.5 编译与接口 242 8.2.6 Diksam怎么会设计成这样? 243 8.2.7 数组和字符串的方法 245 8.2.8 检查类的类型 246 8.2.9 向下转型 246 8.3 关于类的实现——继承和多态 247 8.3.1 字段的内存布局 247 8.3.2 多态——以单继承为前提 249 8.3.3 多继承——C++ 250 8.3.4 Diksam的多继承 252 补充知识 无类型语言中的继承 254 8.3.5 重写的条件 254 8.4 关于类的实现 256 8.4.1 语法规则 256 8.4.2 编译时的数据结构 258 8.4.3 DVM_Executable中的数据结构 260 8.4.4 与类有关的指令 262 补充知识 方法调用、括号和方法指针 263 8.4.5 方法调用 264 8.4.6 super 266 8.4.7 类的链接 266 8.4.8 实现数组和字符串的方法 267 8.4.9 类型检查和向下转型 267 补充知识 对象终结器(finalizer)和析构函数(destructor) 268 第9章 应用篇 271 9.1 为crowbar引入对象和闭包 272 9.1.1 crowbar的对象 272 9.1.2 对象实现 273 9.1.3 闭包 274 9.1.4 方法 276 9.1.5 闭包的实现 278 9.1.6 试着跟踪程序实际执行时的轨迹 281 9.1.7 闭包的语法规则 284 9.1.8 普通函数 284 9.1.9 模拟方法(修改版) 285 9.1.1 0基于原型的面向对象 286 9.2 异常处理机制 286 9.2.1 为crowbar引入异常 286 9.2.2 setjmp()/longjmp() 289 补充知识 Java和C#异常处理的不同 293 9.2.3 为Diksam引入异常 295 补充知识 catch的编写方法 296 9.2.4 异常的数据结构 297 9.2.5 异常处理时生成的字节码 299 9.2.6 受查异常 301 补充知识 受查异常的是与非 303 补充知识 异常处理本身的是与非 304 9.3 构建脚本 305 9.3.1 基本思路 306 9.3.2 YY_INPUT 307 9.3.3 Diksam的构建脚本 308 9.3.4 三次加载/链接 308 9.4 为crowbar引入鬼车 309 9.4.1 关于“鬼车” 309 9.4.2 正则表达式常量 310 9.4.3 正则表达式的相关函数 311 9.5 其他 312 9.5.1 foreach和迭代器(crowbar) 312 9.5.2 switchcase(Diksam) 314 9.5.3 enum(Diksam) 315 9.5.4 delegate(Diksam) 316 9.5.5 final、const(Diksam) 319 附录A crowbar语言的设计 322 附录B Diksam语言的设计 336 附录C DiksamVirtualMachine指令集 359 编程语言实用化指南——写在最后 369 参考文献 375
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页