Compiler
compiler.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include
#include
/*
** @ Name: Simplified C Compiler
** @ Auther: TBAALi
** @ Time: 2019-07-24
**
** @ Introduction:
** SC 语言(源程序) -> SCC编译器 -> Intelx86机器语言(目标语言)
** 控制台程序的函数入口为:mainCRTStartup
**
** 源程序
** |
** 预处理,词法分析 - 此法着色
** |
** 语法分析 - 语法自动缩进
** |
** 语义分析
** |
** Obj目标文件
** |
** 链接器 - 库文件
** |
** exe可执行文件
**
** 形式语言:不考虑语义,只从语法这一方面来看待语言
** 巴克斯范式:是一种形式化符号类描述给定语言的语法,从一个符号开始然后给出替换前面符号的规则
**
EBNF:
元符号 表示含义 备注
::= 定义为,推导为
| 或者
< > 尖括号用于括起非终结符
{ } 含0次在内任意多次重复
[ ] 含0次或1次
( ) 括号内看做一项
. 一条生成规则的结束
“ ” 终结符
**
** SC语言以C89为蓝本进行简化:
1. 支持单字节、双字节、四字节的基本数据类型。
2. 支持数组、结构体
3. 支持字符串
4. 支持函数、局部变量、全局变量
5. 支持条件语句、循环语句
6. 支持基本的算术运算、关系运算
7. 能用多种方式实现的功能,只保留一种
SC语言字符集由字母、数字、空格、标点和特殊字符组成
源码字符集:用于书写SC语言源文件的字符集
执行字符集:SC语言编译后在执行环境中解释的字符集
基本字符集:
1. 字母
* 英文26个小写字母
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
* 英文26个大写字母
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
2. 下滑线
_
3. 10个数字
0
1
2
3
4
5
6
7
8
9
4. 标点和特殊符号
+
-
*
/
%
=
!
>
<
.
&
(
)
[
]
{
}
;
:
\
"
'
5. 空白符
空格符、制表符、换行符。空白符只在字符常量和字符串常量中起作用
6. 空字符
字节的所有位均置为0
SC语言词法定义
1. 关键字
* 定义:
::="char"
::="short"
::="int"
::="void"
::="struct"
::="if"
::="else"
::="for"
::="continue"
::="break"
::="return"
::="sizeof"
<__cdecl关键字>::="__cdecl"
<__stdcall关键字>::="__stacall"
<__align关键字>::="__align"
* 语义
...
__cdecl : 函数调用约定关键字 __cdecl调用约定
__stdcall : 函数调用约定关键字 __stdcall调用约定
__align : 结构成员对齐函数 __align(n)强制结构成员对齐到n
2. 标识符
* 定义
<标识符>::=<非数字>{<数字>|<非数字>}
<非数字>::=
"_"
|"a"
|"b"
|"c"
|"d"
|"e"
|"f"
|"h"
|"i"
|"j"
|"k"
|"l"
|"m"
|"n"
|"o"
|"p"
|"q"
|"r"
|"s"
|"t"
|"u"
|"v"
|"w"
|"x"
|"y"
|"z"
|"A"
|"B"
|"C"
|"D"
|"E"
|"F"
|"G"
|"H"
|"I"
|"J"
|"K"
|"L"
|"M"
|"N"
|"O"
|"P"
|"Q"
|"R"
|"S"
|"T"
|"U"
|"V"
|"W"
|"X"
|"Y"
|"Z"
<数字>::=
"0"
|"1"
|"2"
|"3"
|"4"
|"5"
|"6"
|"7"
|"8"
|"9"
* 语义
标识符可以代表很多实体:函数、变量、结构体名称、结构体成员名、数组名
3. 整数常量
* 定义
<整数常量>::=<数字>{<数字>}
<数字>::=
"0"
|"1"
|"2"
|"3"
|"4"
|"5"
|"6"
|"7"
|"8"
|"9"
* 语义
整数常量的值以10为基计算,语法上的第一个数字是最高有效位
4. 字符常量
* 定义
<字符常量>::=''
::=<转义序列>|源字符集中除单引号', 反斜杠\, 新行字符外的任何字符
<转义序列>为下列序列之一
\'
\"
\\
\a
\b
\f
\n
\r
\t
\v
* 语义
整型字符常量的类型是int
5. 字符串常量
* 定义
<字符串常量>::="{<串字符>}"
<串字符>::=<转义字符>|源字符集中除双引号", 反斜杠\, 新行字符外的任何字符。
* 语义
字符串常量实际是字节数组,该数组的元素类型为char,用该多字节符序列中的各个字节初始化数组的各个元素。
6. 运算符及分隔符
* 定义
<加号>::="+"
<减号>::="-"
<星号>::="*"
<除号>::="\"
<取余号>::="%"
<等于号>::="=="
<不等于号>::="!="
<小于号>::="<"
<小于等于号>::="<="
<大于号>::=">"
<大于等于号>::=">="
<赋值等号>::="="
<箭头>::="->"
<点号>::="."
<与号>::="&"
<左小括号>::="("
<右小括号>::=")"
<左中括号>::="["
<右中括号>::="]"
<左大括号>::="{"
<右大括号>::="}"
<分号>::=";"
<逗号>::=","
<省略号>::="..."
* 语义
算符说明要执行的运算
分隔符是具有独立的语法和语义含义的符号
[] () {} 应成对出现
7. 注释
\* *\ 中间的部分
SC语言语法定义
外部声明
1. 外部声明
* 定义
<翻译单元>::={<外部声明>}<文件结束符>
<外部声明>::=<函数定义>|<声明>
* 语义
每个SC源文件就是一个翻译单元,由一系列外部声明构成,出现在任何函数之外,
因而具有全局作用域。
2. 函数定义
* 定义
<函数定义>::=<类型区分符><声明符><函数体>
<函数体>::=<符合语句>
* 语义
函数定义中的声明符指定要定义的函数名以及形参列表
3. 声明
* 定义
<声明>::=<类型区分符>[<初始值声明符号>]<分号>
<初始值声明符表>::=<初始值声明符>{<逗号><初始值声符>}
<初始值声明符>::=<声明符>|<声明符><赋值运算符><初始值符>
* 语义
声明规定了一组标识符的解释和属性,而同时还导致为标识符所代表的对象或函数保留存储空间的声明
类型区分符指示声明符所代表实体的部分。
4. 类型区分符
* 定义
<类型区分符>::=
|
|
|
|<结构区分符>
<结构区分符>::=
<标识符>
<左大括号>
<结构声明表>
<右大括号>
|
<标识符>
<结构声明表>::=<结构声明>{<结构声明>}
<结构声明>::=<类型区分符>{<结构声明符表>}<分号>
<结构声明符表>::=<声明符>{<逗号><声明符>}
5. 声明符
* 定义
<声明符>::={<指针>}[<调用约定>][<结构成员对齐>]<直接声明符>
<调用约定>::=<__cdecl关键字>|<__stdcall关键字>
<结构成员对齐>::=<__align关键字><左小括号><整数常量><右小括号>
<指针>::=<星号>
<直接声明符>::=<标识符><直接声明符后缀>
<直接声明符后缀>::={<左中括号><右中括号>}
|<左中括号><整数常量><右中括号>
|<左小括号><右小括号>
|<左小括号><形参表><右小括号>}
<参数声明>::=<类型区分符><声明符>
* 语义
每个声明符声明一个标识符,并表明当某个表达式中出现于该声明符形式相同的操作数时
则该操作数指示一个函数或对象,他们具有声明区分符所指出的作用域、存储期及类型。
6. 初始值符
* 定义
<初始值符>::=<赋值表达式>、
* 语义
初值符规定存储在对象中的初始值,若未显示的初始化一个自动存储期的对象,则其值不确定
语句
1. 语句
* 定义
<语句>::={<符合语句>
|
|
|
|
|
|<表达式语句>}
* 语义
语句规定了要执行的动作,除非特别规定外,语句均按顺序执行
2. 复合语句
* 定义
<复合语句>::=<左大括号>{<声明>}{<语句>}<右大括号>
* 语义
复合语句允许将一系列语句组合成一个语法单位。
3. 表达式语句与空语句
* 定义
<表达式语句>::=[]<分号>
* 语义
表达式语句中的表达式将按void表达式求值以获得其副作用
4. 选择语句
* 定义
::=<左小括号><表达式><右小括号><语句>[<语句>]
5. 循环语句
* 定义
::=<左小括号><表达式语句><表达式语句><表达式><右小括号><语句>
6. 跳转语句
* 定义
::=<分号>
::=<分号>
::=<分号>
表达式
1. 表达式
* 定义
<表达式>::=<赋值表达式>{<逗号><赋值表达式>}
* 语义
表达式是由算符和操作数组成的序列,它规定了对一个值的计算,或产生一个副作用,或他们的组合。
2. 赋值表达式
* 定义
<赋值表达式>::=<相等类表达式>|<一元表达式><赋值等号><赋值表达式>
3. 相等类表达式
* 定义
<相等类表达式>::=<关系表达式>{<等于号><关系表达式>|<不等于号><关系表达式>}
4. 关系表达式
* 定义
<关系表达式>::=<加减类表达式>{<小于号><加减类表达式>
|<大于号><加减类表达式>
|<小于等于号><加减类表达式>
|<大于等于号><加减类表达式>}
5. 加减类表达式
* 定义
<加减类表达式>::=<乘除类表达式>{<加号><乘除类表达式>
|<减号><乘除类表达式>}
6. 乘除类表达式
* 定义
<乘除类表达式>::=<一元表达式>{
<星号><一元表达式>
|<除号><一元表达式>
|<取余运算符><一元表达式>}
7. 一元表达式
* 定义
<一元表达式>::=<后缀表达式>
|<与号><一元表达式>
|<星号><一元表达式>
|<加号><一元表达式>
|<减号><一元表达式>
|
::=(<类型区分符>)
8. 后缀表达式
* 定义
<后缀表达式>::=<初等表达式>{
<左中括号><右中括号>
|<左小括号><右小括号>
|<左小括号><实参表达式><右小括号>
|<点号>IDENTIFIER
|<箭头>IDENTIFIER}
<实参表达式>::=<赋值表达式>{<逗号><赋值表达式>}
9. 初等表达式
<初等表达式>::=<标识符>|<整数常量>|<字符串常量>|<字符常量>|(<表达式>)
SC语言词法分析
源程序是由字符序列构成的,此法分析器扫描源程序字符串,根据语言的此法规则分析并识别具有独立意识
的最小语法单元:单词码,并以某种编码形式输出。
**
*/
void ERROR(const char* error_msg)
{
printf("ERROR: %s \n", error_msg);
}
/*
** 单词编码
*/
enum e_TokenCode
{
/*运算符及分隔符*/
TK_PLUS, // +
TK_MINUS, // -
TK_STAR, // *
TK_DIVIDE, // /
TK_MOD, // %
TK_EQ, // ==
TK_NEQ, // !=
TK_LT, // <
TK_LEQ, // <=
TK_GT, // >
TK_GEQ, // >=
TK_ASSIGN, // =
TK_POINTSTO,// ->
TK_DOT, // .
TK_AND, // $
TK_OPENPA, // (
TK_CLOSEPA, // )
TK_OPENBR, // [
TK_CLOSEBR, // ]
TK_BEGIN, // {
TK_END, // }
TK_SEMICOLON, // ;
TK_COMMA, // ,
TK_ELLIPSIS,// ...
TK_EOF, // 文件结束符
/*常量*/
TK_CINT, // 整型常量
TK_CCHAR, // 字符常量
TK_CSTR, // 字符串常量
/*关键字*/
KW_CHAR, // char
KW_SHORT, // short
KW_INT, // int
KW_VOID, // void
KW_STRUCT, // struct
KW_IF, // if
KW_ELSE, // else
KW_FOR, // for
KW_CONTINUE,// continue
KW_BREAK, // break
KW_RETURN, // return
KW_SIZEOF, // sizeof
KW_ALIGN, // __align
KW_CDECL, // __cdecl
KW_STDCALL, // __stdcall
/*标识符*/
TK_IDENT,
};
/*C中字符串是以连续的字节流表示的 以 '\0' 结尾*/
/*动态字符串定义*/
typedef struct DynString
{
int count; // 字符串长度
int capacity; // 包含该字符串的缓冲区长度
char* data; // 指向字符串的指针
} DynString;
/*动态字符串操作函数*/
void dynstring_init(DynString* pstr, int initsize);
void dynstring_free(DynString* pstr);
void dynstring_reset(DynString* pstr);
void dynstring_realloc(DynString* pstr, int new_size);
void dynstring_chcat(DynString* pstr, int ch);
/*动态数租定义*/
typedef struct DynArray
{
int count; // 动态数组元素个数
int capacity; // 动态数组缓存区长度
void** data; // 指向数据指针数组
} DynArray;
/*单词表*/
/*单词存储结构定义*/
e_TokenCode token; // ++++++++++++++++ 得确定
typedef struct TkWord
{
int tkcode; /*单词编码*/
struct TkWord* next; /*指向hash冲突的同义词*/
char* spelling; /*单词字符串*/
struct Symbol* sym_struct; /*指向单词所表示的结构的定义*/
struct Symbol* sym_identifier; /*指向单词所表示的标识符*/
} TkWord;
/*动态数组操作*/
void dynarray_realloc(DynArray* parr, int new_size);
void dynarray_add(DynArray* parr, void* data);
void dynarray_init(DynArray* parr, int initsize);
void dynarray_free(DynArray* parr);
int dynarray_search(DynArray* parr, int key);
/*哈希表函数*/
#define MAXKEY 1024 /*哈希表长度*/
TkWord* tk_hashtable[MAXKEY]; /*单词哈希表*/
DynArray tktable; /*单词表*/
int elf_hash(char* key);
/*单词表操作函数*/
TkWord* tkword_direct_insert(TkWord* tp);
TkWord* tkword_find(char* p, int keyno);
TkWord* tkword_insert(char* p);
void* mallocz(int size);
/*此法分析初始化*/
void init_lex();
/*错误处理*/
/*错误处理程序用到的枚举定义*/
/*错误级别*/
enum e_ErrorLevel
{
LEVEL_WARNING,
LEVEL_ERROR,
};
/*工作阶段*/
enum e_WorkStage
{
STAGE_COMPILE,
STAGE_LINK,
};
void handle_exception(int stage, int level, char* fmt, va_list ap);
void warning(char* fmt, ...);
void error(char* fmt, ...);
void except(char* msg);
void skip(int c);
char* get_tkstr(int v);
void link_error(char* fmt, ...);
char ch;
/*此法分析*/
void get_token();
void getch();
/*预处理*/
void preprocess();
void parse_comment();
void skip_white_space();
/*解析标识符*/
int is_nodigit(char c);
int is_digit(char c);
void parse_identifier();
void parse_num();
void parse_string(char sep);
/*此法着色*/
void color_token(int lex_state);
/*词法分析用到的全局变量*/
TkWord* tk_hashtable[MAXKEY]; // 单词哈希表
DynArray tktable; // 单词表中放置标识符,包括变量名,函数名,数据结构定义名
DynString tkstr; // 单词字符串
DynString sourcestr; // 单词源码字符串
int tkvalue; // 单词值,单词为整型常量
char ch; // 当前取得的源码字符
int token; // 单词编码
int line_num; // 行号
main.cpp
#include "compiler.h"
#include
int main()
{
std::cout << "Compiler" << std::endl;
return 0;
}
void _entry()
{
int ret;
ret = main();
exit(ret);
}
/* ===============================================
* 初始化动态字符串存储容量
* pstr: 动态字符换存储结构
* initsize: 字符串初始化分配空间
*/
void dynstring_init(DynString* pstr, int initsize)
{
if (pstr != NULL)
{
pstr->data = (char*)malloc(sizeof(char) * initsize);
pstr->count = 0;
pstr->capacity = initsize;
}
}
/* ================================================
* 释放动态字符串使用的内训空间
* pstr: 动态字符换存储结构
*/
void dynstring_free(DynString* pstr)
{
if (pstr != NULL)
{
if (pstr->data)
{
free(pstr->data);
}
pstr->count = 0;
pstr->capacity = 0;
}
}
/* =================================================
* 重置动态字符串,先释放,重新初始化
* pstr: 动态字符串存储结构
*/
void dynstring_reset(DynString* pstr)
{
dynstring_free(pstr);
dynstring_init(pstr, 8); /*字符串初始化分配空间8字节*/
}
/* ==================================================
* 重新分配字符换容量
* pstr: 动态字符串存储结构
* new_size: 字符串新长度
*/
void dynstring_realloc(DynString* pstr, int new_size)
{
int capacity_;
char* data_;
capacity_ = pstr->capacity;
while (capacity_ < new_size)
{
capacity_ = capacity_ * 2;
}
data_ = (char*)realloc(pstr->data, capacity_); /* 重新分配内存块大小, void* 指向之前已经分配内存块的指针, size_t 新大小 */
if (!data_)
{
error("内存分配失败!");
}
pstr->capacity = capacity_;
pstr->data = data_;
}
/* ==================================================
* 追加单个字符到动态字符串对象
* pstr: 动态字符串存储结构
* ch: 所要追加的字符
*/
void dynstring_chcat(DynString* pstr, int ch)
{
int count_;
count_ = pstr->count + 1;
if (count_ > pstr->capacity)
{
dynstring_realloc(pstr, count_);
}
((char*)pstr->data)[count_ - 1] = ch;
pstr->count = count_;
}
/* ==================================================
* 重新分配动态数组容量
* parr: 动态数组存储容量
* new_size: 动态数组最新元素个数
*/
void dynarray_realloc(DynArray* parr, int new_size)
{
int capacity;
void* data;
capacity = parr->capacity;
while (capacity < new_size)
{
capacity = capacity * 2;
}
data = realloc(parr->data, capacity);
if (!data)
{
error("内存分配失败!");
}
parr->capacity = capacity;
parr->data = (void**)data; // TMD
}
/* ===============================================
* 追加动态数组元素
* parr: 动态数组存储结构
* data: 所要追加的新元素
*/
void dynarray_add(DynArray* parr, void* data)
{
int count;
count = parr->count + 1;
if (count * sizeof(void*) > parr->capacity)
{
dynarray_realloc(parr, count * sizeof(void*));
}
parr->data[count - 1] = data;
parr->count = count;
}
/* ===============================================
* 初始化动态数组存储容量
* parr: 动态数组存储结构
* initsize: 动态数组初始化分配空间
*/
void dynarray_init(DynArray* parr, int initsize)
{
if (parr != NULL)
{
parr->data = (void**)malloc(sizeof(void*) * initsize);
parr->count = 0;
parr->capacity = initsize;
}
}
/* ===============================================
* 释放动态数组使用的内存空间
* parr: 动态数组存储结构
*/
void dynarray_free(DynArray* parr)
{
void** p;
for (p = parr->data;
parr->count;
++p, --parr->count)
{
if (*p)
{
free(*p);
}
free(parr->data);
parr->data = NULL;
}
}
/* ==================================================
* 动态数组元素查找
* parr: 动态数组查找结构
* key: 要查找的元素
*/
int dynarray_search(DynArray* parr, int key)
{
int i;
int** p;
p = (int**)parr->data;
for (i = 0; i < parr->count; ++i, p++)
{
if (key == **p)
{
return i;
}
}
return -1;
}
compiler.cpp
#include "Compiler.h"
int main()
{
std::cout << "Heelo" << std::endl;
return 0;
}
/* ===============================================
* 初始化动态字符串存储容量
* pstr: 动态字符换存储结构
* initsize: 字符串初始化分配空间
*/
void dynstring_init(DynString* pstr, int initsize)
{
if (pstr != NULL)
{
pstr->data = (char*)malloc(sizeof(char) * initsize);
pstr->count = 0;
pstr->capacity = initsize;
}
}
/* ================================================
* 释放动态字符串使用的内训空间
* pstr: 动态字符换存储结构
*/
void dynstring_free(DynString* pstr)
{
if (pstr != NULL)
{
if (pstr->data)
{
free(pstr->data);
}
pstr->count = 0;
pstr->capacity = 0;
}
}
/* =================================================
* 重置动态字符串,先释放,重新初始化
* pstr: 动态字符串存储结构
*/
void dynstring_reset(DynString* pstr)
{
dynstring_free(pstr);
dynstring_init(pstr, 8); /*字符串初始化分配空间8字节*/
}
/* ==================================================
* 重新分配字符换容量
* pstr: 动态字符串存储结构
* new_size: 字符串新长度
*/
void dynstring_realloc(DynString* pstr, int new_size)
{
int capacity_;
char* data_;
capacity_ = pstr->capacity;
while (capacity_ < new_size)
{
capacity_ = capacity_ * 2;
}
data_ = (char*)realloc(pstr->data, capacity_); /* 重新分配内存块大小, void* 指向之前已经分配内存块的指针, size_t 新大小 */
if (!data_)
{
ERROR("内存分配失败!");
}
pstr->capacity = capacity_;
pstr->data = data_;
}
/* ==================================================
* 追加单个字符到动态字符串对象
* pstr: 动态字符串存储结构
* ch: 所要追加的字符
*/
void dynstring_chcat(DynString* pstr, int ch)
{
int count_;
count_ = pstr->count + 1;
if (count_ > pstr->capacity)
{
dynstring_realloc(pstr, count_);
}
((char*)pstr->data)[count_ - 1] = ch;
pstr->count = count_;
}
/* ==================================================
* 重新分配动态数组容量
* parr: 动态数组存储容量
* new_size: 动态数组最新元素个数
*/
void dynarray_realloc(DynArray* parr, int new_size)
{
int capacity;
void* data;
capacity = parr->capacity;
while (capacity < new_size)
{
capacity = capacity * 2;
}
data = realloc(parr->data, capacity);
if (!data)
{
ERROR("内存分配失败!");
}
parr->capacity = capacity;
parr->data = (void**)data; // TMD
}
/* ===============================================
* 追加动态数组元素
* parr: 动态数组存储结构
* data: 所要追加的新元素
*/
void dynarray_add(DynArray* parr, void* data)
{
int count;
count = parr->count + 1;
if (count * sizeof(void*) > (unsigned int)parr->capacity)
{
dynarray_realloc(parr, count * sizeof(void*));
}
parr->data[count - 1] = data;
parr->count = count;
}
/* ===============================================
* 初始化动态数组存储容量
* parr: 动态数组存储结构
* initsize: 动态数组初始化分配空间
*/
void dynarray_init(DynArray* parr, int initsize)
{
if (parr != NULL)
{
parr->data = (void**)malloc(sizeof(void*) * initsize);
parr->count = 0;
parr->capacity = initsize;
}
}
/* ===============================================
* 释放动态数组使用的内存空间
* parr: 动态数组存储结构
*/
void dynarray_free(DynArray* parr)
{
void** p;
for (p = parr->data;
parr->count;
++p, --parr->count)
{
if (*p)
{
free(*p);
}
free(parr->data);
parr->data = NULL;
}
}
/* ==================================================
* 动态数组元素查找
* parr: 动态数组查找结构
* key: 要查找的元素
*/
int dynarray_search(DynArray* parr, int key)
{
int i;
int** p;
p = (int**)parr->data;
for (i = 0; i < parr->count; ++i, p++)
{
if (key == **p)
{
return i;
}
}
return -1;
}
/*2019-08-21 20:04*/
/* ==================================================
* 我们需要的哈希函数是以单词字符串为关键字进行哈希计算的
* 计算哈希地址
* key: 哈希关键字
* MAXKEY: 哈希表长度
*/
int elf_hash(char* key)
{
int h = 0;
int g;
while (*key)
{
h = (h << 4) + *key++;
g = h & 0xf0000000;
if (g)
{
h ^= g >> 24;
}
h &= ~g;
}
return h % MAXKEY;
}
/*单词表操作函数: */
/* ======================================================
* 运算符,关键字,常量直接放入单词表
*/
TkWord* tkword_direct_insert(TkWord* tp)
{
int keyno;
dynarray_add(&tktable, tp);
keyno = elf_hash(tp->spelling);
tp->next = tk_hashtable[keyno];
tk_hashtable[keyno] = tp;
return tp;
}
/* ======================================================
* 在单词表中查找单词
* p: 要查找的单词
8 keyno: 要查找单词的哈希值
*/
TkWord* tkword_find(char* p, int keyno)
{
TkWord* tp = NULL;
TkWord* tp1;
for (tp1 = tk_hashtable[keyno]; tp1; tp1 = tp1->next)
{
if (!strcmp(p, tp1->spelling)) // 比较字符串
{
token = (e_TokenCode)tp1->tkcode; /* error token得确定*/
tp = tp1;
}
}
return tp;
}
/* ======================================================
* 标识符插入单词表,先查找,查找不到再插入单词表
*/
TkWord* tkword_insert(char* p)
{
TkWord* tp;
int keyno;
char* s;
char* end;
int length;
keyno = elf_hash(p);
tp = tkword_find(p, keyno);
if (tp == NULL)
{
length = strlen(p);
tp = (TkWord*)mallocz(sizeof(TkWord) + length + 1);
tp->next = tk_hashtable[keyno];
tk_hashtable[keyno] = tp;
dynarray_add(&tktable, tp);
tp->tkcode = tktable.count - 1;
s = (char*)tp + sizeof(TkWord);
tp->spelling = (char*)s;
for (end = p + length; p < end; )
{
*s++ = *p++;
}
*s = (char)'\0';
}
return tp;
}
/* ======================================================
* 分配堆内存,并将数据初始花化为0
* size: 分配内存大小
*/
void* mallocz(int size)
{
void* ptr;
ptr = malloc(size);
if (!ptr && size)
{
ERROR("内存分配失败!");
}
memset(ptr, 0, size);
return ptr;
}
/* ======================================================
* 此法分析初始化
* typedef struct TkWord
* {
* int tkcode; /*单词编码
* struct TkWord* next; /*指向hash冲突的同义词
* char* spelling; /*单词字符串
* struct Symbol* sym_struct; /*指向单词所表示的结构的定义
* struct Symbol* sym_identifier; /*指向单词所表示的标识符
* } TkWord;
*/
void init_lex()
{
TkWord* tp;
static TkWord keyword[] =
{
/*单词编码*/ /*指向hash冲突的同义词*/ /*单词字符串*/ /*指向单词所表示的结构的定义*/ /*指向单词所表示的标识符*/
{TK_PLUS, NULL, (char*)"+", NULL, NULL}, // +
{TK_MINUS, NULL, (char*)"-", NULL, NULL}, // -
{TK_STAR, NULL, (char*)"*", NULL, NULL}, // *
{TK_DIVIDE, NULL, (char*)"/", NULL, NULL}, // /
{TK_MOD, NULL, (char*)"%", NULL, NULL}, // %
{TK_EQ, NULL, (char*)"==", NULL, NULL}, // ==
{TK_NEQ, NULL, (char*)"~=", NULL, NULL}, // !=
{TK_LT, NULL, (char*)"<", NULL, NULL}, // <
{TK_LEQ, NULL, (char*)"<=", NULL, NULL}, // <=
{TK_GT, NULL, (char*)">", NULL, NULL}, // >
{TK_GEQ, NULL, (char*)">=", NULL, NULL}, // >=
{TK_ASSIGN, NULL, (char*)"=", NULL, NULL}, // =
{TK_POINTSTO, NULL, (char*)"->", NULL, NULL}, // ->
{TK_DOT, NULL, (char*)".", NULL, NULL}, // .
{TK_AND, NULL, (char*)"$", NULL, NULL}, // $
{TK_OPENPA, NULL, (char*)"(", NULL, NULL}, // (
{TK_CLOSEPA, NULL, (char*)")", NULL, NULL}, // )
{TK_OPENBR, NULL, (char*)"[", NULL, NULL}, // [
{TK_CLOSEBR, NULL, (char*)"]", NULL, NULL}, // ]
{TK_BEGIN, NULL, (char*)"{", NULL, NULL}, // {
{TK_END, NULL, (char*)"}", NULL, NULL}, // }
{TK_SEMICOLON, NULL, (char*)";", NULL, NULL}, // ;
{TK_COMMA, NULL, (char*)",", NULL, NULL}, // ,
{TK_ELLIPSIS, NULL, (char*)"...", NULL, NULL}, // ...
{TK_EOF, NULL, (char*)"End_Of_File", NULL, NULL}, // 文件结束符
/*常量*/
{TK_CINT, NULL, (char*)"整型常量", NULL, NULL}, // 整型常量
{TK_CCHAR, NULL, (char*)"字符常量", NULL, NULL}, // 字符常量
{TK_CSTR, NULL, (char*)"字符串常量", NULL, NULL}, // 字符串常量
/*关键字*/
{KW_CHAR, NULL, (char*)"char", NULL, NULL}, // char
{KW_SHORT, NULL, (char*)"short", NULL, NULL}, // short
{KW_INT, NULL, (char*)"int", NULL, NULL}, // int
{KW_VOID, NULL, (char*)"void", NULL, NULL}, // void
{KW_STRUCT, NULL, (char*)"struct", NULL, NULL}, // struct
{KW_IF, NULL, (char*)"if", NULL, NULL}, // if
{KW_ELSE, NULL, (char*)"else", NULL, NULL}, // else
{KW_FOR, NULL, (char*)"for", NULL, NULL}, // for
{KW_CONTINUE, NULL, (char*)"continue", NULL, NULL}, // continue
{KW_BREAK, NULL, (char*)"break", NULL, NULL}, // break
{KW_RETURN, NULL, (char*)"return", NULL, NULL}, // return
{KW_SIZEOF, NULL, (char*)"sizeof", NULL, NULL}, // sizeof
{KW_ALIGN, NULL, (char*)"__align", NULL, NULL}, // __align
{KW_CDECL, NULL, (char*)"__cdecl", NULL, NULL}, // __cdecl
{KW_STDCALL, NULL, (char*)"__stdcall", NULL, NULL}, // __stdcall
/*标识符*/
{TK_IDENT, NULL, (char*)"标识符", NULL, NULL},
{0, NULL, NULL, NULL, NULL},
};
/*关键字,运算符优先进入单词表*/
dynarray_init(&tktable, 8);
for (tp = &keyword[0]; tp->spelling != NULL; tp++)
{
tkword_direct_insert(tp);
}
}
/*错误处理*/
/*错误处理程序用到的枚举定义*/
/*错误级别*/
/* ======================================================
* 异常处理
* stage: 编译阶段还是链接阶段
* level: 错误级别
* fmt: 参数输出的格式
* ap: 可变参数列表
*/
void handle_exception(int stage, int level, char* fmt, va_list ap)
{
char buf[1024];
vsprintf(buf, fmt, ap); /*使用参数格式换输出*/
if (stage == STAGE_COMPILE)
{
if (level == LEVEL_WARNING)
{
printf("%s(第%d行):编译警告:%s~\n", __FILE__, __LINE__, buf);
}
else
{
printf("%s(第%d行):编译错误:%s~\n", __FILE__, __LINE__, buf);
exit(-1);
}
}
else
{
printf("链接错误:%s\n!", buf);
}
}
/* ======================================================
* 编译警告处理
* fmt: 参数输出格式
* ap: 可变参数列表
*/
void warning(char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
handle_exception(STAGE_COMPILE, LEVEL_WARNING, fmt, ap);
va_end(ap);
}
/* ============================================================
* 编译致命错误处理
* fmt: 参数输出格式
* ap: 可变参数列表
*/
void error(char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
handle_exception(STAGE_COMPILE, LEVEL_ERROR, fmt, ap);
va_end(ap);
}
/* ============================================================
* 错误提示,此处缺少某个语法成分
* msg: 需要什么语法成分
*/
void except(char* msg)
{
error((char*)"缺少%s", msg);
}
/* ============================================================
* 跳过单词c,取下一个单词,如果当前单词不是c,提示错误
* c: 要跳过的单词
*/
void skip(int c)
{
if (token != c)
{
error((char*)"缺少 '%s' ", get_tkstr(c));
}
// get_token();
}
/* ============================================================
* 取得单词v所代表的源码字符串
* V: 单词编号
*/
char* get_tkstr(int v)
{
if (v > tktable.count)
{
return NULL;
}
else if (v >= TK_CINT && v <= TK_CSTR)
{
// return sourcestr.data;
}
else
{
return ((TkWord*)tktable.data[v])->spelling;
}
}
/* ============================================================
* 链接错误处理
* fmt: 参数输出格式
* ap: 可变参数列表
*/
void link_error(char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
handle_exception(STAGE_LINK, LEVEL_ERROR, fmt, ap);
va_end(ap);
}
/*此法分析过程*/
/* ============================================================
* 取单词
*/
/*此法分析*/
void get_token()
{
preprocess();
switch (ch)
{
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '_':
{
TkWord* tp;
parse_identifier();
tp = tkword_insert(tkstr.data);
token = (e_TokenCode)(tp->tkcode);
}
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
parse_num();
token = TK_CINT;
break;
}
case'+':
getch();
token = TK_PLUS;
break;
case'-':
getch();
if (ch == '>')
{
token = TK_POINTSTO;
getch();
}
else
{
token = TK_MINUS;
}
break;
case'/':
token = TK_DIVIDE;
getch();
break;
case'%':
token = TK_MOD;
getch();
break;
case'=':
getch();
if (ch == '=')
{
token = TK_EQ;
getch();
}
else
token = TK_ASSIGN;
break;
case'!':
getch();
if (ch == '=')
{
token = TK_NEQ;
getch();
}
else
error((char*)"暂不支持");
break;
case'<':
getch();
if (ch == '=')
{
token = TK_LEQ;
getch();
}
else
token = TK_LT;
break;
case'>':
getch();
if (ch == '=')
{
token = TK_GEQ;
getch();
}
else
token = TK_GT;
break;
case'.':
getch();
if (ch == '.')
{
getch();
if (ch != '.')
{
error((char*)"...拼写错误!");
}
else
{
token = TK_ELLIPSIS;
}
getch();
}
else
{
token = TK_DOT;
}
break;
case'&':
token = TK_AND;
getch();
break;
case';':
token = TK_SEMICOLON;
getch();
break;
case']':
token = TK_CLOSEBR;
getch();
break;
case'}':
token = TK_END;
getch();
break;
case')':
token = TK_CLOSEPA;
getch();
break;
case'[':
token = TK_OPENBR;
getch();
break;
case'{':
token = TK_BEGIN;
getch();
break;
case',':
token = TK_COMMA;
getch();
break;
case'(':
token = TK_OPENPA;
getch();
break;
case'*':
token = TK_STAR;
getch();
break;
case'\'':
parse_string(ch);
token = TK_CCHAR;
// tkvalue = *(char*)tkstr.data;
break;
case'\"':
parse_string(ch);
token = TK_CSTR;
break;
case EOF:
token = TK_EOF;
break;
default:
error((char*)"不认识的字符:\\x%02x ", ch);
getch();
break;
}
}
/* ============================================================
* 从SC源文件中读取一个字符
*/
void getch()
{
ch = getc(fin); // 文件尾返回EOF,其他返回实际字符值
}
/*预处理*/
/* ============================================================
* 预处理,忽略空白字符及注释
*/
void preprocess()
{
while (1)
{
if (ch == ' '
|| ch == '\t'
|| ch == '\r')
skip_white_space();
else if (ch == '/')
{
// 向前再读一个字节看是否是注释开始,猜错了把多读的字符放回去
getch();
if (ch == '*')
{
parse_comment();
}
else
{
ungetc(ch, fin); // 把一个字符退回到输入流中
ch = '/';
break;
}
}
else
break;
}
}
/* ============================================================
* 解释注释
*/
void parse_comment()
{
getch();
do
{
if (ch == '\n'
|| ch == '*'
|| ch == CH_EOF)
break;
else
getch();
}while(1);
if (ch == '\n')
{
line_num++;
getch();
}
else if (ch == '*')
{
getch();
if (ch == '/')
{
getch();
return;
}
}
else
{
error("一直到文件末尾未看到配对的注释结束符!");
return;
}
}
/* ==================================================
* 空白字符处理,忽略空格,Tab,回车
*/
void skip_white_space()
{
while (ch == ' '
|| ch == '\t'
|| ch == '\r')
{
if (ch == '\r')
{
getch();
if (ch != '\n')
return;
lint_num++;
}
printf("%c", ch);
getch();
}
}
/*解析标识符*/
/* ==================================================
* 判断c是否为字母或下划线
* c: 字符值
*/
int is_nodigit(char c)
{
return (c >= 'a'
&& c <= 'z')
|| (c >= 'A'
&& c <= 'Z')
|| c == '+';
}
/* ==================================================
* 判断c是否为数字
* c: 字符值
*/
int is_digit(char c)
{
return c >= '0' && c <= '9';
}
/* ===================================================
* 解析标识符
*/
void parse_identifier()
{
dynstring_reset(&tkstr);
dynstring_chcat(&tkstr, ch);
getch();
while(is_nodigit(ch)
|| is_digit(ch))
{
dynstring_chcat(&tkstr, ch);
getch();
}
dynstring_chcat(&tkstr, '\0');
}
/* ==================================================
* 解析整型常量
*/
void parse_num()
{
}
void parse_string(char sep);
/*此法着色*/
void color_token(int lex_state);
``