1:Micro编译器结构
(1)词法分析器:读取源程序,产生记号表示流,供语法分析器调用
(2)语法分析器:一直处理记号,知道遇到了需要语义处理的语法结构,直接调用语义例程
(3)语义例程:调用适当的支持例程生成代码
(4)符号表:有语义例程使用(接口描述)
2:Micro词法分析器
词法记号集:token(枚举类型)
Typedef enum token_types{
BEGIN, END, READ, WRITE, ID, INTLITERAL, LPAREN, RPAREN, SEMI
COLON, COMMA, ASSIGNOP, PLUSOP, MINUSOP, SCANEOF
}token;
Extern token scanner(void);//不带参数,返回token类型值的函数(语法分析器)
词法分析器的主要识别循环过程:
#include
#include
//识别操作符,注释,分隔符,标识符,整数常量的词法分析器循环
intin_char, c;
while((in_char = getchar()) != EOF)
{
//遇到空格就直接进行下一个token的读取
if(isspace(in_char))
continue;
//如果以字母开头,表示的是标识符
elseif(isalpha(in_char))
{
//如果读取的字符是数字,字母,或者下划线,则继续读取,直到获取最长的符合序列
for(c = getchar(); isalnum(c) || c =='_'; c = getchar());
//将额外字符压回输入流
ungetc(c, stdin);
//返回此标识符
returnID;
}
//如果以数字开头,表示的是整数常量
elseif(isdigit(in_char))
{
//如果读取的字符是数字,则继续读取,知道获取最长的符合序列
while(isdigit(c = getchar()));
//将额外的字符压回输入流
ungetc(c, stdin);
//返回此整数常量
returnINTLITERAL;
}
elseif(in_char =='(')
returnLPAREN;
elseif(in_char ==')')
returnRPAREN;
elseif(in_char ==';')
returnSEMICOLON;
elseif(in_char ==',')
returnCOMMA;
elseif(in_char =='+')
returnPLUSOP;
elseif(in_char ==':')
{
//查找赋值操作":="
c = getchar();
if(c =='=')
returnASSIGNOP;
else
{
ungetc(c, stdin);
lexical_error(in_char);
}
}
elseif(in_char =='-')
{
//查找注释符"--"
c = getchar();
if(c =='-')
{
while((in_char = getchar()) !='\n');
}
//否则为减号
else
{
ungetc(c, stdin);
returnMINUSOP;
}
}
else
//不是以字母或者数字开头,则为无效字符,出错
lexical_error(in_char);
}
保留字的识别方式:
(1)词法分析器中有一张保留字表,每当一个标识符被识别时,检查保留字表,如果在此表中,则被解释成保留字;
(2)保留字作为编译器符号表中的初始部分,含有特殊属性reserved,词法分析器识别一个标识符后,在符号中找到该标识符,如果有特殊属性,则识别为保留字。
(3)要检查保留字需要额外的缓存来存放每一个被检查了的标识符,所以,另外定义例程来实现这个功能:check_reserved()和buffer_char()
代码修改如下:
#include
#include
//识别操作符,注释,分隔符,标识符,整数常量的词法分析器循环
intin_char, c;
clear_buffer();
if(feof(stdin))
returnSCANEOF;
while((in_char = getchar()) != EOF)
{
//遇到空格就直接进行下一个token的读取
if(isspace(in_char))
continue;
//如果以字母开头,表示的是标识符
elseif(isalpha(in_char))
{
//缓存每个字符
buffer_char(in_char);
//如果读取的字符是数字,字母,或者下划线,则继续读取,直到获取最长的符合序列
for(c = getchar(); isalnum(c) || c =='_'; c = getchar())
buffer_cahr(c);
//将额外字符压回输入流
ungetc(c, stdin);
//返回标识符并检测其是否为保留字
returncheck_reserved();
}
//如果以数字开头,表示的是整数常量
elseif(isdigit(in_char))
{
//缓存每个字符
buffer_char(in_char);
//如果读取的字符是数字,则继续读取,知道获取最长的符合序列
while(isdigit(c = getchar()))
buffer_char(c);
//将额外的字符压回输入流
ungetc(c, stdin);
//返回此整数常量
returnINTLITERAL;
}
elseif(in_char =='(')
returnLPAREN;
elseif(in_char ==')')
returnRPAREN;
elseif(in_char ==';')
returnSEMICOLON;
elseif(in_char ==',')
returnCOMMA;
elseif(in_char =='+')
returnPLUSOP;
elseif(in_char ==':')
{
//查找赋值操作":="
c = getchar();
if(c =='=')
returnASSIGNOP;
else
{
ungetc(c, stdin);
lexical_error(in_char);
}
}
elseif(in_char =='-')
{
//查找注释符"--"
c = getchar();
if(c =='-')
{
while((in_char = getchar()) !='\n');
}
//否则为减号
else
{
ungetc(c, stdin);
returnMINUSOP;
}
}
else
//不是以字母或者数字开头,则为无效字符,出错
lexical_error(in_char);
}
3:Micro语法
使用CFG(Context-Free Grammar,上下文无关文法,也成BNF文法)给出定义:
产生式:A --> B C D ... Z
A:左部(Left-Hand Side,LHS)
B C D ... Z:右部(Right-Hand Side,RHS)
产生式代表了一个规则,左部文法符号可以由其右部文法符号代替,如:
--> begin end
CFG中有两种文法符号:
(1)非终结符:
通常由''限定或者出现在产生式的左边来被识别,它们实际上是占位符,必须根据以它作为左部的产生式来替换或者重写
(2)终结符:
从来不被重写,代表语言的词法记号(token)
CFG的全部目的:指定哪些终结符序列式合法的。
CFG的检测方式:有一个开始符号(start)或目标符号(goal)的非终结符开始,随后应用产生式重写非非终结符,知道仅剩下终结符,任何可由此产生的终结符序列都被认为是合法的。
扩展的BNF可以定义:
(1)可选项:"["和"]"括起来
(2)可选的项列表:"{"和"}"括起来
但是上述功能也可以通过BNF来实现,所以,扩展的BNF实际上跟BNF是一致的。
下面定义扩展的CFG:
1. --> begin end
2. --> {}
3. --> ID := ;
4. --> read ();
5. --> write ();
6. --> ID {, ID}
7. --> {}
8. --> { }
9. --> ()
10. --> ID
11. --> INTLITERAL
12. --> PLUSOP
13. --> MINUSOP
14. --> SCANEOF
使用上述的CFG推导一个程序:begin ID := ID + (INTLITERAL - ID); end
begin end
begin {} end
begin end
begin ID := ; end
begin ID := { }; end
begin ID := ; end
begin ID := + ; end
begin ID := ID + ; end
begin ID := ID + (); end
begin ID := ID + ( { }); end
begin ID := ID + ( ); end
begin ID := ID + ( - ); end
begin ID := ID + (INTLITERAL - ); end
begin ID := ID + (INTLITERAL - ID); end
CFG不包含优先级,如果要包含优先级,可定义如下:
--> { }
--> { }
--> ()
--> ID
--> INTLITERAL
4:递归下降语法分析
递归下降:
递归语法分析例程,当处理一个程序的时候,它下降遍历所识别的分析树。
基本思想:
每个非终结符都有一个相关的语法分析过程(parsing procedure)用以识别由该非终结符生成的任意词法记号序列。
对应于Micro文法产生式所编写的语法分析例程:
voidsystem_goal(void)
{
program();
match(SCANEOF);
}
voidprogram(void)
{
match(BEGIN);
statement_list();
match(END);
}
voidstatement_list(void)
{
statement();
while(true)
{
switch(next_token())
{
caseID:
caseREAD:
caseWRITE:
statement();
default:
return;
}
}
}
voidstatement(void)
{
token tok = next_token();
switch(tok)
{
caseID:
match(ID);
match(ASSIGNOP);
expression_r();
match(SEMICOLON);
break;
caseREAD:
match(READ);
match(LPAREN);
id_list();
match(RPAREN);
match(SEMICOLON);
break;
caseWRITE:
match(WRITE);
match(LPAREN);
expr_list();
match(RPAREN);
match(SEMICOLON);
break;
default:
syntax_error(tok);
break;
}
}
voidid_list(void)
{
match(ID);
while(next_token() == COMMA)
{
match(COMMA);
match(ID);
}
}
voidexpression_r(void)
{
primary();
for(t = next_token(); t == PLUSOP || t == MINUSOP; t = next_token())
{
add_op();
primary();
}
}
voidexpr_list(void)
{
expression_r();
while(next_token == COMMA)
{
match(COMMA);
expression_r();
}
}
voidadd_op(void)
{
token tok = next_token();
if(add_op == PLUSOP || add_op == MINUSOP)
match(tok);
else
syntax_error(tok);
}
voidprimary(void)
{
token tok = next_token();
swith(tok)
{
caseLPAREN:
match(LPAREN);
expression_r();
match(RPAREN);
break;
caseID:
match(ID);
break;
caseINTLITERAL:
match(INTLITERAL);
break;
default:
syntax_error();
break;
}
}
5:翻译Micro
5.1:目标语言(三地址机器代码)
5.2:临时变量(Temp&X)
5.3:动作符号(见代码)
5.4:语义信息(见代码)
5.5:Micro动作符号(见代码)
文法符号的语义记录:
#defineMAXIDLEN 31
typedefcharstring[MAXIDLEN];
typedefstructoperator
{
enumop {PLUS, MINUS}operator;
}op_rec;
enumexpr {IDEXPR, INTLITERALEXPR, TEMPEXPR};
typedefstructexpression
{
enumexpr kind;
union
{
string name;
intval;
};
}expr_rec;
带有符号动作的Micro文法:
--> #start begin end
--> {}
--> := #assign
--> read ();
--> write ()
--> #read_id {, #read_id}
--> #write_expr
{, #write_expr}
--> { #gen_infix}
--> ()
-->
--> INTLITERAL #process_iteral
--> PLUSOP #process_op
--> MINUSOP #process_op
--> ID #process_id
--> SCANEOF #finish
符号表例程的规范及相应于Micro动作符号的语义例程所必须的辅助例程:
//判断s是否在符号表中
externintlookup(string s);
//将s无条件地加入符号表
externvoidenter(string s);
//辅助例程check_id():把一个变量加入符号表
//并生成一条预留存储空间的汇编命令语句来声明变量
voidcheck_id(string s)
{
if(! lookup(s))
{
enter(s);
//创建一条完整的指令
generate("Declare", s,"Integer"," ");
}
}
//函数get_temp()分配临时变量
char*get_temp(void)
{
//目前为止最大的临时分配空间
staticintmax_temp = 0;
staticchartempname[MAXIDLEN];
max_temp++;
sprintf(tempname,"Temp&%d", max_temp);
check_id(tempname);
returntempname;
}
Micro的动作例程:
voidstart(void)
{
}
voidfinish(void)
{
generate("Halt"," "," "," ");
}
voidassign(expr_rec target, expr_rec source)
{
generate("Store", extract(source), ," ");
}
op_rec process_op(void)
{
op_rec o;
if(current_token == PLUSOP)
o.operator= PLUS;
else
o.operator= MINUS;
returno;
}
expr_rec gen_infix(expr_rec e1, op_rec op, expr_rec e2)
{
expr_rec erec;
erec.kind = TEMPEXPR;
strcpy(erec.name, get_temp());
generate(extract(op), extract(e1), extract(e2), erec.name);
returnerec;
}
voidread_id(expr_rec in_var)
{
generate("Read", in_var.name,"Integer"," ");
}
expr_rec process_id(void)
{
expr_rec t;
check_id(token_buffer);
t.kind = IDEXPR;
strcpy(, token_buffer);
returnt;
}
expr_rec process_literal(void)
{
expr_rec t;
t.kind = LITERALEXPR;
(void)sscanf(token_buffer,"%d", &t.val);
returnt;
}
voidwrite_expr(expr_rec out_expr)
{
generate("Write", extract(out_expr),"Integer"," ");
}
修改语法分析过程以包含语义处理的例子:
未包含语义处理之前:
voidexpression_r(void)
{
primary();
for(t = next_token(); t == PLUSOP || t == MINUSOP; t = next_token())
{
add_op();
primary();
}
}
包含了语义处理之后:
voidexpression_r(expr_rec *result)
{
expr_rec left_operand, right_operand;
op_rec op;
primary(&left_operand);
while(naex_token() == PLUSOP || next_token == MINUSOP)
{
add_op(&op);
primary(&right_operand);
left_operand = gen_infix(left_operand, op, right_operand);
}
*result = left_operand;
}
递归下降语法分析和翻译示例:begin A := BB - 314 + A; end SCANEOF
上述过程中语法分析器动作有:
1:调用语法分析例程(如:system_goal(),statement_list()等)找出输入中的一个字符串来匹配文法中的非终结符
2:调用match()来匹配文法终结符和一个输入词法记号(如:match(BEGIN),match(ID)等)
3:调用语义动作例程(如:start(),process_id()等)
分析步骤记录:
Step Parser Action Remaining Input Generated Code
_______________________________________________________________________________
(1)Call system_goal() begin A := BB - 314 + A; end SCANEOF
(2)Call program() begin A := BB - 314 + A; end SCANEOF
(3)Semantic Action: start() begin A:= BB - 314 + A; end SCANEOF
(4)Math(BEGIN) begin A:= BB - 314 + A; end SCANEOF
(5)Call statement_list() A := BB - 314 + A; end SCANEOF
(6)Call statement() A := BB - 314 + A; end SCANEOF
(7)Call ident() A := BB - 314 + A; end SCANEOF
(8)match(ID) A := BB - 314 + A; end SCANEOF
(9)Semantic Action: := BB - 314 + A; end SCANEOFDeclare A, Integer
process_id()
(10)match(ASSIGNOP) := BB - 314 + A; end SCANEOF
(11)Call expression_r() BB - 314 + A; end SCANEOF
(12)Call primary() BB - 314 + A; end SCANEOF
(13)Call ident() BB - 314 + A; end SCANEOF
(14)match(ID) BB - 314 + A; end SCANEOF
(15)Semantic Action: - 314 + A; end SCANEOFDeclare BB, Integer
process_id()
(16)Call add_op() - 314 + A; end SCANEOF
(17)match(MINUSOP) - 314 + A; end SCANEOF
(18)Semantic Action: 314 + A; end SCANEOF
process_op()
(19)Call primary() 314 + A; end SCANEOF
(20)match(INTLITERAL) 314 + A; end SCANEOF
(21)Semantic Action: + A; end SCANEOF
process_literal()
(22)Semantic Action: + A; end SCANEOFDeclare Temp&1, Integer
Gen_infix()Sub BB, 314, Temp&1
(23)Call add_op() + A; end SCANEOF
(24)mathc(PLUSOP) + A; end SCANEOF
(25)Semantic Action: A; end SCANEOF
process_op()
(26)Call primary() A; end SCANEOF
(27)Call ident() A; end SCANEOF
(28)match(ID) A; end SCANEOF
(29)Semantic Action: ; end SCANEOF
process_id()
(30)Semantic Action: ; end SCANEOF Declare Temp&2, Integer
gen_infix()Add Temp&1, A, Temp&2
(31)Semantic Action: assign() ; end SCANEOF Store Temp&2, A
(32)match(SEMICOLON) ; end SCANEOF
(33)match(END) end SCANEOF
(34)match(SCANEOF) SCANEOF
(35)Semantic Action: finish() Haltc 语言AES256 ECB
转载文章标签 c 语言AES256 ECB 编译器构造 c语言描 语法分析 标识符 保留字 文章分类 架构 后端开发
上一篇:spring 5 使用哪个版本
下一篇:jQuery内存泄露解决办法
-
C语言 aes256实现
排序之选择排序算法的实现算法思路:第一趟从待排序区选择最小(最大)的元素放到排序区的起始位置,第二趟从剩下的待排序区选择最小(最大)的元素放到排序区的第二个位置。以此类推,直到待排序区的元素个数为0。该算法为不稳定的排序算法。将数组第一个元素设为开始时的最小值。实现过程中i作为区分已排序区和未排序区的交界,i左边为排序区,右边为未排序区。j作为索引,遍历未排序区,与当前i上的值比较,
C语言 aes256实现 aes算法c语言实现 c语言sort c语言sort函数 c语言sort函数从大到小排序
















