符号表
EXP ([Ee][-+]?[0-9]+)
TYPE int|float
STRUCT struct
RETURN return
IF if
ELSE else
WHILE while
sixteen [0-9]|[A-F]
sixteennoo [1-9]|[A-F]
eight [0-7]
eightnoo [1-7]
ten [0-9]
tennoo [1-9]
EIGHTINT (0{eightnoo}{eight}*)
SIXTEENINT 0[xX]({sixteennoo}{sixteen}*)
INT ({tennoo}{ten}*)|0
SIXTEENFLOAT 0[xX](({sixteennoo}{sixteen}*)|0)"."{sixteen}+
EIGHTFLOAT 0({eightnoo}{eight}*|0)"."{eight}+
FLOAT ({ten}*"."{ten}+)|({ten}+"."{ten}*)
EFLOAT (({ten}*"."{ten}+)|({ten}+"."{ten}*)|{ten}*){EXP}
WRONG_SIXTEENINT 0[xX]{sixteen}*[G-Zg-z]+[A-Za-z0-9]*
WRONG_EIGHTINT 0{eight}*[89A-Za-z]+[A-Za-z0-9]*
WRONG_EFLOAT ({ten}*"."{ten}*|{ten}+)[eE]({FLOAT}*|[A-Za-z]*))|[{"."}]?[eE][-+]?({ten}+|{ten}*"."{ten}*
ID [A-Za-z_][A-Za-z_0-9]*
SEMI ;
COMMA ,
ASSIGNOP =
PLUS \+
MINUS \-
AND &&
OR \|\|
DOT \.
NOT \!
LP \(
RP \)
LB \[
RB \]
LC \{
RC \}
RELOP >|<|==|<=|>=|!=
COMMENT (\/\/.*)|([/][*]([^(\*/)])*[*][/])
STAR \*
DIV \/
SPACE1 [\t]
SPACE2 [ ]
EOL \n|\r\n
ERROR_TYPE .
Tree.c
struct NODE // 左孩子右兄弟表示,多叉树转化成为二叉树
{
char name[40];
struct NODE *firstchild; // 左孩子
struct NODE *nextsibling; // 右兄弟
int line; // 列号
int column; // 行号
char type[40];
char var_fun_str_name[30]; //文法中实际的输入
};
struct NODE *Create_newnode(char *name, int line, int column, char *type) // 每遇到一个词法单元,就会分配一个树上结点
struct NODE *insert(int num, ...) // 一个父亲结点(非终结符)连接着多个孩子节点(终结符与非终结符)
// 依次读入参数变量,将第一个变量作为父亲节点的孩子结点插入。将第二个变量作为孩子结点的兄弟结点插入到孩子结点的下面。
// 我们要将第一个参数作为变量的数量,真正的变量从第二个开始。这里也用到了可变参数机制。
return node_parent; // 返回归约之后的父亲结点(非终结符)
void print(struct NODE *root, int ceng)
// 按照 dfs 的顺序来遍历,也就是先序遍历
// 碰到节点就打印,然后递归左边,递归右边。对于终结符来说,我们需要打印它的类型以及实际内容,对于非终结符,我们需要打印它的类型以及行号。
char *sixteenint_to_int(char *str) // 十六进制转成十进制
char *eightint_to_int(char *str) // 八进制转成十进制
Lexical.l
flex进行scanner,将数值存入yylval。
而bison读取yylval之中的值。
{INT} {
strcpy(str,"INT"); // str用来存储类型名称
strcpy(str2,yytext); // str2用来存储该类型具体的东西 (存储到yytext里面)
nodee = Create_newnode(str,yylineno,column,yytext); // 每遇到一个词法单元,为其分配树上节点
strcpy(nodee->var_fun_str_name,str2); // 把结点具体名称维护到name中
yylval.token_node = nodee; // token_node 是在 syntax.y 中的联合体中定义,
column+=yyleng; // 维护列号
return INT; // 返回类型名称
}
Syntax.y
定义部分
%{
//对库函数的引用与全局变量声明与引用
}%
%token<token_node> 终结符
以表达式“ x o p y o p z x \ op \ y \ op \ z x op y op z”为例,运算符op的关联性决定了运算符嵌套,是通过先将x与y分组还是先将y与z分组来解析。
%
l
e
f
t
%left
%left 指定左相关性(将x与y优先分组)
%
r
i
g
h
t
%right
%right 指定右相关性(将y与z优先分组)
%
n
o
n
a
s
s
o
c
%nonassoc
%nonassoc 未指定结合性,这意味着“
x
o
p
y
o
p
z
x \ op \ y \ op \ z
x op y op z”被视为语法错误。
排在后面的优先级更高
由于else总是匹配最近的if,所以我们定义了一个比else优先级更低的东西
规则部分
产生式左边的非终结符为初始符号,箭头等同于:。
产生式左边的名字为$$
产生式右边的依次为$(1,2,3,…)
产生式之间以;分隔
如果语法没有错误,$$ = insert(num, $1, $2, …)。然后再将父亲节点的内容拷贝进去。
而对于语法错误,我们就不需要将其插入进语法树中了。
规约与移进
Bison总会选择移入
调试
bison -d -v syntax.y
诊断模式
bison -d -t syntax.y
具体规则
Program -> ExtDefList | ExtDefList error(Unexpected character)
ExtDefList -> 空 | ExtDef ExtDefList//定义列表,递归定义
ExtDef -> Specifier ExtDecList SEMI(;) (全局变量)
| Specifier ExtDecList error (全局变量缺分号)
| Specifier SEMI(;)
| Specifier FunDec CompSt (定义函数实现过程,包括主函数)
| Specifier FunDec SEMI(;) //函数声明
| Specifier error (结构体缺分号)
ExtDecList -> VarDec (声明变量)
| VarDec COMMA(,) ExtDecList(多个声明变量)
Specifier -> TYPE(int | float) (普通类型)
| StructSpecifier (结构体类型)
StructSpecifier -> STRUCT(struct) OptTag LC({) DefList RC(}) (定义结构体的产生式)//struct (id){int a;\nfloatb;}(id2)
| STRUCT(struct) Tag (使用已经定义的结构体)
| STRUCT(struct) OptTag LC({) DefList error (struct缺})
OptTag -> 空 | ID([A-Za-z_][A-Za-z_0-9]*) //自定义数据类型
Tag -> ID([A-Za-z_][A-Za-z_0-9]*)
VarDec -> ID([A-Za-z_][A-Za-z_0-9]*) | VarDec LB([) INT RB(]) //array[10]
| VarDec LB([) ID([A-Za-z_][A-Za-z_0-9]*) RB(]) //array[i]
| VarDec LB([) error RB(]) ([]中括号中间不是int或id)
| VarDec LB INT error (缺],例如a[3)
| VarDec LB ID error (缺],例如a[i)
FunDec -> ID([A-Za-z_][A-Za-z_0-9]*) LP(() VarList RP()) //function(int a,int b)
| ID([A-Za-z_][A-Za-z_0-9]*) LP(() RP()) //无参函数
| ID LP error (函数无参数列表缺))
| ID LP error RP (函数参数列表中参数错误)
| ID LP VarList error (函数参数列表缺))
VarList -> ParamDec COMMA(,) VarList | ParamDec //int a, float b.....用逗号隔开的一堆变量声明
ParamDec -> Specifier VarDec
CompSt -> LC({) DefList StmtList RC(}) //语句块,作用域
StmtList -> 空 | Stmt StmtList //语句链,语句1+语句2.....
Stmt -> Exp SEMI(;) //Stmt:各种语句操作
| CompSt
| RETURN(return) Exp SEMI(;)
| IF LP(() Exp RP()) Stmt %prec LOWER_THAN_ELSE //ifelse语句,%prec是设置优先级,让else能跟最近的if匹配
| IF LP(() Exp RP()) Stmt ELSE(else) Stmt
| WHILE LP(() Exp RP()) Stmt
| ELSE Stmt (没有if只有else)
| Exp error (表达式缺分号;)
| RETURN Exp error (return缺分号;)
| IF LP error RP Stmt %prec LOWER_THAN_ELSE (if跟的()中的表达式错误)
| IF LP error RP Stmt ELSE Stmt (if跟的()中的表达式错误)
| IF LP Exp error Stmt ELSE Stmt (if缺))
| WHILE LP error RP Stmt (while的()中语法错误)
| WHILE LP Exp error Stmt (while语句缺))
DefList -> 空 | Def DefList //定义语句链
Def -> Specifier DecList SEMI //这个是变量定义不是声明吧?
| Specifier error SEMI (变量声明错误)
| Specifier DecList error (变量声明缺分号;)
DecList -> Dec | Dec COMMA DecList //定义并操作:int a = 10,b = 1 + 2......
Dec -> VarDec
| VarDec ASSIGNOP Exp
| VarDec ASSIGNOP error ( =右边不是表达式 )
Exp -> Exp ASSIGNOP Exp (EXP为表达式) (表达式 = 表达式)
| Exp AND Exp (表达式 && 表达式)
| Exp OR Exp (表达式 || 表达式)
| Exp RELOP Exp (表达式 bool运算 表达式)
| Exp PLUS Exp (表达式 + 表达式)
| Exp MINUS Exp (表达式 - 表达式)
| Exp STAR Exp (表达式 * 表达式)
| Exp DIV Exp (表达式 / 表达式)
| LP Exp RP ((表达式))
| MINUS Exp (-表达式)
| NOT Exp (!表达式)
| ID LP Args RP ( ID ( 变量 ) )
| ID LP RP ( ID ( ) )
| Exp LB Exp RB ( 表达式 [ 表达式 ] )
| Exp DOT ID (表达式 . ID)
| ID
| INT
| FLOAT
| EIGHTINT
| SIXTEENINT
| EIGHTFLOAT
| SIXTEENFLOAT
| EFLOAT
| Exp LB Exp COMMA Exp RB (表达式 ( 表达式 , 表达式 ) )
| Exp LB error RB (表达式[]里语法错误)
| Exp LB error (缺])
| ID LP error (缺))
| Exp ASSIGNOP error
| Exp AND error
| Exp OR error
| Exp RELOP error
| Exp PLUS error
| Exp MINUS error
| Exp STAR error
| Exp DIV error
| LP error RP
| MINUS error
| NOT error
| ID LP error RP ( ()括号中的内容错误 )
| LP Exp error (缺少))
| LB Exp error (缺少])
Args -> Exp COMMA Args | Exp (Args: 变量) (Args -> 表达式 , 变量 | 表达式)
用户函数(main函数部分)
int main(int argc,char** argv)
{
FILE* f=fopen(argv[1],"r");
yyrestart(f);
yyparse();
if(!ERROR_A&&!ERROR_B) // 没有报错生成语法树
{
print(node,0); // 从第0层开始dfs先序遍历输出
}
fclose(f);
return 0;
}