【编译原理】复习总结

说明

  1. 只总结到了LR之前,后面没怎么学,但编译原理实在是太美了,以后会接着学
  2. 本篇文章是根据这个 哈工大网课 (MOOC上还在开课,可以跟学)总结的,讲的很好,非常简练,一些难点需要反复观看
  3. 中南大学的录屏,讲的很好,非常细致,哈工大看不懂的可以看这个
  4. 算法实现理论课考试一般是不考的,但是对编程实现很有用🥰

第一章 基础知识

编译:将高级语言翻译成汇编语言或机器语言的过程
语句可以分为:声明语句执行语句

输入:字符流
1.词法分析:从左向右逐行扫描源程序,确定单词类型,将识别出来的单词转换成token
token:<种别码,属性值>
⟹ \Longrightarrow token流
2.语法分析:从词法分析器输出的token序列中识别出各类短语,构造语法分析树。
⟹ \Longrightarrow 语法分析树
3.语义分析:字符表(标识符的属性信息),语义检查(变量或过程未声明就使用或重复声明,操作符与操作数类型不匹配、数组下标不是整数、函数返回类型不对等等)
⟹ \Longrightarrow 语法分析树
4.中间代码生成:表示形式:三地址指令(类似于汇编代码指令序列,每个指令最多有三个操作数);语法树
三地址指令的表示:四元式(op,y,z,x)、三元式、间接三元式
⟹ \Longrightarrow 中间代码
5.代码优化:对中间代码进行改造
⟹ \Longrightarrow 中间代码
6.目标代码生成:一其中个重要任务:为程序中使用的变量合理分配寄存器
⟹ \Longrightarrow 目标代码

第二章 文法

句型:既可以包含终结符,也可以包含非终结符,也可能是空串
句子:不包含非终结符的句型
语言L(G):由文法G的开始符号S推出的所有句子构成的集合
文法的分类
0型文法:只要左部含非终结符即可
1型文法(上下文有关):左部符号个数 <= 右部
2型文法(上下文无关,被研究最多):左部单一个非终结符
3型文法(正则):包括左线性和右线性。对右部要求很高,终结符只能在一侧
在这里插入图片描述▲例子都是标识符的文法
作业:写出标识符的左线性文法

四种文法之间的关系:在这里插入图片描述

CFG分析树(经常考)

短语:每一颗子树的边缘
直接短语(简单短语):高度为2的子树的边缘
句柄:需要最左规约的元素
在这里插入图片描述

二义性文法(Ambiguous Grammar)

可以为某个句子生成多颗语法树的文法,namely,有两个不同的最左(右)推导
没有算法能够判断一个2型文法是否无二义性
但能给出一组充分条件,满足条件的一定无二义性,但不满足不一定有。

正则表达式(正规表达式)

正则文法和正则表达式等价
运算优先级:(),*,连接,|
在这里插入图片描述
(a|b)(a|b)表示的语言:L((a|b)(a|b)) = L(a|b)L(a|b) = {a,b}{a,b} = {aa,ab,bb,ba}在这里插入图片描述▲例:C语言无符号整数
在这里插入图片描述▲例:C语言标识符
在这里插入图片描述

第三章词法分析

现态+输入 ⇒ \Rightarrow 输出
有穷自动机FA(Deterministic finite automata):DFA(确定) ,NFA(非确定)
M = ( S,Σ ,δ,s0,F )
S:有穷状态集
Σ:输入字母表,即输入符号集合。假设ε不是 Σ中的元素
δ:将S×Σ映射到S的转换函数。s∈S, a∈Σ, δ(s,a)表示从状态s出发,沿着标记为a的边所能到达的状态。
s0 :开始状态 (或初始状态),s0∈ S
F :接收状态(或终止状态)集合,F⊆ S
在这里插入图片描述
在这里插入图片描述
A没有任何输入也可以到状态B和终态C,所以ABC都算是终态和初态
带不带空的NFA都有相对应的DFA
NFA(不确定的)较直观,但DFA(确定的)实现起来比较简单

DFA的算法实现

输入:以文件结束符EOF结尾的字符串x。DFA的开始状态S0,接收状态集F,转换函数move
输出:如果D接收x,则回答yes,否则回答no
方法:将下述算法应用于输入串x
在这里插入图片描述

正则表达式转换成有穷自动机

直接转化成DFA比较难,一般先转换成NFA
在这里插入图片描述
根据NFA得出转换表,将状态集合作为一个新的状态,生成DFA
在这里插入图片描述在这里插入图片描述

最小化DFA

输入输出完全一样的状态,可以合并为一个状态

子集构造法(subset construction)

输入:NFA
输出:DFA
方法:核心思想:循环遍历,不漏下任何一种情况,和手动做差不多在这里插入图片描述

识别单词的DFA

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

错误处理
词法分析阶段可检测错误的类型:

  1. 单词拼写错误
    例:int i = 0x3G; float j =1.05e;
  2. 非法字符
    例:~ @

词法错误检测:
如果当前状态与当前输入符号在转换表对应项中的信息为空,而当前状态又不是终止状态,则调用错误处理程序

错误处理:
查找已扫描字符串中最后一个对应于某终态的字符

  1. 如果找到了,将该字符与其前面的字符识别成一个单词。然后将输入指针退回到该字符,扫描器重新回到初始状态,继续识别下一个单词
  2. 如果没找到,则确定出错,采用错误恢复策略

错误恢复策略:
最简单的错误恢复策略:“恐慌模式 (panic mode)”恢复:
从剩余的输入中不断删除字符,直到词法分析器能够在剩余输入的开头发现一个正确的字符为止

第四章语法分析-自顶向下

在这里插入图片描述
推导过程不是唯一的,但最左最右推导是唯一的
自顶向下的语法分析采用最左推导方式:总是选择每个句型的最左非终结符进行替换,根据输入流中的下一个终结符,选择最左非终结符的一个候选式

通用形式

递归下降分析 (Recursive-Descent Parsing)

由一组过程组成,每个过程对应一个非终结符
从文法开始符号S对应的过程开始,其中递归调用文法中其它非终结符对应的过程。如果S对应的过程体恰好扫描了整个输入串,则成功完成语法分析

当有多个候选式都符合条件时(同一非终结符的多个候选式存在共同前缀),任选其中一个之后若后面走不通,则需要回溯

预测分析 (Predictive Parsing)

预测分析是递归下降分析技术的一个特例,通过在输入中向前看固定个数(通常是一个)符号来选择正确的A-产生式。
可以对某些文法构造出向前看k个输入符号的预测分析器,该类文法有时也称为LL(k) 文法类
预测分析不需要回溯,是一种确定的自顶向下分析方法

文法转换

左递归文法会使递归下降分析器陷入无限循环
含有A→Aα形式产生式的文法称为是直接左递归的 (immediate left recursive)
经过两步或两步以上推导产生的左递归称为是间接左递归的
消除直接左递归:
在这里插入图片描述
消除间接左递归:代入,将间接转换为直接,再消除
在这里插入图片描述

消除左递归算法:
输入:不含循环推导(即形如A多步推导得到A的推导)和ε-产生式的文法G 
输出:等价的无左递归文法
在这里插入图片描述
提取左公因子(Left Factoring )
在这里插入图片描述
算法:
在这里插入图片描述

LL(1)文法

S_文法
每个产生式的右部都以终结符开始,同一非终结符的各个候选式的首终结符都不同
S_文法不含ε产生式
可以保证预测分析的确定性,选出的候选式是唯一的。

非终结符的后继(终结)符号集:在这里插入图片描述
产生式的可选集:
在这里插入图片描述
串首终结符集:
在这里插入图片描述

LL(1)文法:

同一非终结符的各个产生式的可选集互不相交
A → α | β 满足下面的条件:

  1. 如果α和β都不能推出ε,FIRST (α)∩FIRST (β) =Φ
    因为如果相同,就会有多个候选式都符合条件(select有交集),需要回溯
  2. α和β至多有一个能推导出ε :
    如果 β =>* ε,则FIRST (α)∩FOLLOW(A) =Φ;
    如果 α =>* ε,则FIRST (β)∩FOLLOW(A) =Φ;
    因为当其中一个可以推出空的时候,候选式选择的时候不只α和β的first集,也可以是跟在A后面的终结符,会有多个候选式都符合条件(select有交集),需要回溯

FIRST集&FOLLOW集的计算

计算单个符号的FIRST集:在这里插入图片描述

不断应用下列规则,直到没有新的终结符或ε可以被加入到任何FIRST集合中为止。

  1. 如果X是一个终结符,那么FIRST ( X ) = { X }
  2. 如果X不是一个终结符,X→Y1…Yk∈P (k≥1),
    把FIRST(Y1)元素加到FIRST ( X )里,如果ε在FIRST(Y1)里,那么把FIRST(Y2)元素加到FIRST ( X )里,如果如果ε也在FIRST(Y2)里,那么再把FIRST(Y3)元素加到FIRST ( X )里,以此类推
    但是ε是不加入的,只有Y1…Yk全部都可以推出ε,再把ε加入。
  3. 如果 X→ε∈P,那么将ε加入到FIRST( X )中

计算完单个符号的FIRST集就可以计算一个符号串的FIRST集了:
Step1. 向FIRST(X1X2…Xn)加入FIRST(X1)中所有的非ε符号
Step2. 如果ε在FIRST(X1)中,再加入FIRST(X2)中的所有非ε符号;
如果ε在FIRST(X1)和FIRST(X2)中,再加入FIRST(X3)中的所有非ε符号,以此类推。
Step3. 最后,如果对所有的i,ε都在FIRST(Xi)中,那么将ε加入到FIRST(X1X2…Xn) 中

计算非终结符的FOLLOW集:
在这里插入图片描述

图解:

  1. 把结束符$/#放到FOLLOW(E)里
  2. FIRST(E’)(except ε)放到FOLLOW(T)里
  3. E’可以推出ε,所以把FOLLOW(E)放到FOLLOW(T)里
  4. E’可以推出ε,所以把FOLLOW(E’)放到FOLLOW(T)里
  5. FIRST(T’)(except ε)放到FOLLOW(F)里
  6. T’可以推出ε,所以把FOLLOW(T)放到FOLLOW(F)里
  7. T’可以推出ε,所以把FOLLOW(T’)放到FOLLOW(F)里
  8. 把 ) 放到FOLLOW(E)里
  9. 最右非终结符,所以把FOLLOW(E)放到FOLLOW(E’)里,FOLLOW(T)放到FOLLOW(T’)里
  10. 循环上述步骤,直至FOLLOW集不再变化
    算法:
    不断应用下列规则,直到没有新的终结符可以被加入到任何FOLLOW集合中为止。
  11. KaTeX parse error: Expected 'EOF', got '#' at position 5: (书上是#̲)放入FOLLOW( S )中…是输入右端的结束标记。
  12. 如果存在一个产生式A→αBβ,那么FIRST ( β )中除ε 之外的所有符号都在FOLLOW( B )中如果存在一个产生式A→αB,或存在产生式A→αBβ且FIRST ( β ) 包含ε,那么 FOLLOW( A )中的所有符号都在FOLLOW( B )中。

产生式的可选集SELECT集:
在这里插入图片描述

  1. 如果产生式的右部第一个字符为终结符,那该产生式的SELECT集就是该终结符
  2. 如果产生式的右部第一个字符为终结符为非终结符,SELECT集是该非终结符的FIRST集中的终结符
  3. 若为空,则该产生式的SELECT集就是该产生式左部的FOLLOW集

根据SELECT集经简单变换可以得到预测分析表:
在这里插入图片描述

递归的预测分析法

构造该文法的递归下降分析器的主程序DESCENT:
先求SELECT,除了4、7都很好求,根据依赖关系求出4、7
在这里插入图片描述在这里插入图片描述在这里插入图片描述
根据SELECT集就可以得到各个非终结符的过程:

非递归预测分析法
非递归的预测分析不需要为每个非终结符编写递归下降过程,而是根据预测分析表构造一个自动机,也叫表驱动的预测分析。
在这里插入图片描述
算法:
在这里插入图片描述
二者比较:
在这里插入图片描述

实现步骤

  1. 构造文法
  2. 改造文化:消除二义性、左递归、回溯
  3. 求每个变量的FIRST集,每个非终结符的FOLLOW集,从而求得每个产生式的SELECT集
  4. 检查是否为LL(1)文法:相同左部产生式的SELECT无交集
  5. 对于递归的预测分析:根据预测分析表为每一个非终结符编写一个过程;对于非递归的预测分析:实现表驱动的预测分析算法

错误处理

两种情况下可以检测到错误:

  1. 栈顶的终结符和当前输入符号不匹配
  2. 栈顶非终结符与当前输入符号在预测分析表对应项中的信息为空

错误恢复:恐慌模式:

  1. 忽略输入中的一些符号,直到输入中出现由设计者选定的同步词法单元(synchronizing token)集合中的某个词法单元。其效果依赖于同步集合的选取。集合的选取应该使得语法分析器能从实际遇到的错误中快速恢复。例如可以把FOLLOW(A)中的所有终结符放入非终结符A的同步记号集合。
  2. 如果终结符在栈顶而不能匹配,一个简单的办法就是弹出此终结符。
    在这里插入图片描述

第五章语法分析-自底向上

通用形式

在这里插入图片描述
对输入串一次从左到右扫描过程中,将输入符号移入栈顶,知道栈顶的一个或多个符号可以进行规约
直到检测出语法错误。或栈中包含开始符号且输入缓冲区为空(这时语法分析成功完成)

LR分析法

LR文法是最大的,可以构造出相应移入-规约语法分析器的文法类。
L:对输入token流进行从左到右的扫描
R:反向构造出一个最右推导序列
LR(k)分析:需要向前查看k个输入符号的LR分析。
K=0,k=1这两种情况具有实践意义
省略k时,表示k=1
基本原理:
自底向上分析的关键:如何正确识别句柄
句柄是逐步形成的,用状态表示句柄识别的进展程度
LR分析器会基于状态来构造自动机进行句柄的识别

若把前面通过构造项目集规范族得到的DFA的每个状态都看作终结态,则该DFA是识别活前缀的DFA
DFA+栈=PDA

知识点

  1. 语法分析时必须先消除文法中的左递归
    错。自底向上进行分析不需要消除左递归和左公共因子,自顶向下进行分析则需。

  2. LR 分析法在自左至右扫描输入串时就能发现错误,但不能准确地指出出错地点。
    对?

  3. 两个正规集相等的必要条件是他们对应的正规式等价。
    错。正规集是正规式能表示的集合

  4. 词法分析器的输出结果是 单词的种别编号和自身值

  5. 如果文法 G 是无二义的,则它的任何句子α 最左推导和最右推导对应的语法树必定相同

  6. 四元式之间的联系是通过__临时变量_实现的。

  7. 计算机执行用高级语言编写的程序主要有两种途径:解释__和__编译

  8. 扫描器是__词法分析器___,它接受输入的__源程序___,对源程序进行___词法分析__并识别出一个个单词符号,其输出结果是单词符号,供语法分析器使用。

  9. 自上而下分析法采用___移进__、归约、错误处理、___接受__等四种操作。

  10. LR分析器包括总控程序、分析表、分析栈(状态栈,文法符号栈)

  11. 语义分析的基本功能包括: 确定类型、类型检查、语义处理和某些静态语义检查。

  12. 采用三元式实现三地址代码时,不利于对中间代码进行优化。

  13. 一个优先表一定存在相应的优先函数。错?

  14. 目标代码生成时,应考虑如何充分利用计算机的寄存器的问题。?

  15. 一个 LL(1)文法一定是无二义的。

  16. 正规文法产生的语言都可以用上下文无关文法来描述

  17. 编译过程可分为 ( 词法分析) ,(语法分析),(语义分析与中间代码生成 ),(优化)和(目标
    代码生成 )五个阶段。

  18. 从功能上说,程序语言的语句大体可分为( 执行性 )语句和(说明性 )语句两大类。

  19. 符号表中的信息栏中登记了每个名字的有关的性质,如(类型、种属、所占单元大小、地址)等等。

  20. 根据优化所涉及的程序范围,可将优化分成为(局部优化),(循环优化),(全局优化)三个级别。

  21. 规范推导是最右推导,每次都替换最右边的非终结符

  22. 句柄:一个句型的最左直接短语

  23. 语法制导翻译:在语法分析过程中,根据每个产生式所对应的语义程序进行翻译的方法

  24. 素短语:至少含有一个终结符,并且,除它自身外不再含任何更小的素短语。

  25. 前端:包括词法分析、语法分析、语义分析、中间代码生成阶段以及相关出错处理和符号表管理

  26. 后端:依赖于目标机,包括目标代码生成以及相关出错处理和符号表操作

  27. 分前后端的优点:某一个编译程序的前端加上相应的后端则可以为不同的机器构成同一个源语言的编译程序;不同语言编译的前端生成同一中中间语言,再使用同一个机器的后端则可以为同一个机器生成几个语言的编译程序

  28. 遍:对源程序或其等价的中间程序从头到尾扫描并完成规定任务的过程

  29. 解释程序:不需要在运行之前把源程序翻译成目标代码,也可以运行并生成结果。

  30. 和编译程序的区别:编译型代表:C&C++,C#,Java,解释型代表:html,javascript。区别有很多,说说常见的几个:
    (1)编译型语言的源代码有错误编译不通过,无法生成可执行代码,更无法执行程序;解释型语言只有执行时才会判断是否出错,即使一句出错,也可以继续执行下一句。
    (2)编译型语言都为强类型,即必须说明数据的类型,如int a;解释型语言多为弱类型,如js中var a,a可以为字符串也可以为整型。
    (3)编译型语言执行效率上大大优于解释型,主要因为编译器在编译过程中会根据不同平台自动优化目标代码,且特点为1次编译,N次运行,另外强类型的程序安全性高;解释型语言无上述过程,逐语句翻译造成执行效率低下,每次执行都会重复解释一遍,并且安全性低。
    (4)编译型程序适合对通用性,重复性,高效性有要求的系统,如开发操作系统;相比解释型语言更具灵活性,如开发网站前台页。
    (5)编译程序编译时间较长,运行速度较快

大题

  1. 写一个文法 G, 使其语言为不以 0开头的偶数集:
    S -> ABC|C
    A -> 1|2|3|4|5|6|7|8|9
    B -> DB|ε
    C -> 0|2|4|6|8
    D -> 0|A

  2. 已知文法 G(S)及相应翻译方案
    S→aAb {print “1”}
    S→a {print “2”}
    A→AS {print “3”}
    A→c {print “4”}
    输入 acab, 输出是什么?4231
    写出LR自底向上分析过程

  3. 已知文法 G(S)
    S→bAb
    A→(B | a
    B→Aa)
    写出句子 b(aa)b 的规范归约过程
    步骤 符号栈 输入串 动作
    0 # b(aa)b# 移进
    1 #b (aa)b# 移进
    2 #b( aa)b# 移进
    3 #b(a a)b# 规约
    4 #b(A a)b# 移进
    5 #b(Aa )b# 移进
    6 #b(Aa) b# 规约
    7 #b(B b# 规约
    8 #bA b# 移进
    9 #bAb # 规约(S→bAb)
    10 #S # 接受

  4. 文法 G(S)
    S→dAB
    A→aA| a
    B→Bb| ε
    描述的语言是什么?
    L(G)={danbm |n>0, m≥0} (n是次方)(d连接上n个a和n个b)

  5. 已知文法 G(S)
    S→BA
    A→BS| d
    B→aA| bS | c
    的预测分析表如下
    给出句子 adccd 的分析过程。

  6. 目标代码有哪几种形式?生成目标代码时通常应考虑哪几个问题?
    目标代码通常采用三种形式:机器语言,汇编语言,待装配机器语言模块。
    应着重考虑的问题:
    (1)如何使生成的目标代码较短;
    (2)如何充分利用寄存器,以减少访问内存次数;
    (3)如何充分利用指令系统的特点。

  7. 一个文法 G 别是 LL(1)文法的充要条件是: 相同左部的产生式的SELECT集无交集
    (1) FIRST(α) ∩FIRST(β)=Ф
    (2) 如果 β=* >ε, FIRST(α) ∩FOLLOW(A)= Ф

  8. 已知文法 G[S]
    S→S*aF | aF | *aF
    F→+aF | +a
    消除文法左递归和提公共左因子。
    S→aFA | aFA
    A→
    aFA | ε
    F→+aB
    B→F | ε

  9. 符号表的作用是什么?符号表查找和整理技术有哪几种?
    作用:登记源程序中出现的各种名字及其信息,以及了解各阶段的进展状况。
    主要技术:线性表,二叉树,杂凑技术。
    名字+属性
    编译过程中,每当扫描器(词法分析器)识别出一个名字后,编译程序就查阅符号表,看其是否在符号表中。
    如果它是一个新名字就将它填进表里

选择题

1.如果文法G是无二义的,则它的任何句子α( )。

  • A.最左推导和最右推导对应的语法树必定相同
  • B.最左推导和最右推导对应的语法树可能不同
  • C.最左推导和最右推导必定相同
  • D.可能存在两个不同的最左推导,但它们对应的语法树相同

2.( )文法不是LL(1)的。

  • A.递归
  • B.右递归
  • C. 2型
  • D.含有公共左因子的

3.一个文法G,若( ),则称它是LL(1)文法。

  • A. G中不含左递归
  • B. G无二义性
  • C. G的LL(1)分析表中不含多重定义的条目
  • D. G中产生式不含左公因子
  • 12
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: 抱歉,我是AI语言模型,无法直接编写代码。以下是一些关于正则表达式和词法分析程序的基本知识,希望能对您有所帮助。 正则表达式是一种用于描述字符串模式的语言,它可以用来匹配、搜索、替换字符串。在编译原理中,正则表达式通常用于描述词法单元的模式,即词法分析器将输入的字符流转换为单词符号流时所使用的规则。 Pascal语言子集的单词符号包括关键字、标识符、常量、运算符、界符等。下面是一些可能用到的正则表达式: 1. 关键字:用管道符号“|”连接多个关键字,表示其中任意一个都可以匹配成功。 ``` and|array|begin|case|const|div|do|downto|else|end|file|for|function|goto|if|in|label|mod|nil|not|of|or|packed|procedure|program|record|repeat|set|then|to|type|until|var|while|with ``` 2. 标识符:以字母或下划线开头,后面可以跟任意个字母、数字或下划线。 ``` [a-zA-Z_][a-zA-Z0-9_]* ``` 3. 常量:包括整数、实数、字符、字符串等多种类型,可以用不同的正则表达式来描述。 ``` 整数:[+-]?\d+ 实数:[+-]?\d+(\.\d+)?([eE][+-]?\d+)? 字符:'[^']*' 字符串:"[^"]*" ``` 4. 运算符:用管道符号“|”连接多个运算符,表示其中任意一个都可以匹配成功。 ``` :=|<=|>=|<>|<|>|:=|\+|-|\*|/|\(|\)|\[|\]|\^|@|\.|,|:|;|\{|\} ``` 5. 界符:同样用管道符号“|”连接多个界符。 ``` .|..|...|(|)|[|]|^|@|,|:|;|{|} ``` 以上只是一些基本的正则表达式,实际上还需要根据具体的语法规则来进行调整和完善。词法分析程序的实现可以采用有限状态自动机(DFA)或正则表达式匹配等算法。 ### 回答2: 正则文法: letter → 'a' | 'b' | ... | 'z' | 'A' | 'B' | ... | 'Z' digit → '0' | '1' | ... | '9' id → letter(id | digit)* num → digit+ relop → '<' | '<=' | '>' | '>=' | '<>' | '=' addop → '+' | '-' mulop → '*' | '/' | 'div' | 'mod' assignop → ':=' semicolon → ';' colon → ':' comma → ',' leftparen → '(' rightparen → ')' begin → 'begin' end → 'end' if → 'if' then → 'then' else → 'else' while → 'while' do → 'do' program → 'program' var → 'var' const → 'const' integer → 'integer' real → 'real' boolean → 'boolean' false → 'false' true → 'true' 通过以上正则文法,我们可以描述pascal中的绝大部分保留字、运算符、标点符号等单词符号。要实现词法分析程序,我们需要对每个单词符号定义一个正则表达式,并用它们来定义整个pascal语言子集的单词符号。 我们可以先将所有单词符号按照优先级从高到低的顺序排列,然后对每个单词符号编写相应的正则表达式: 1. relop → '((<=)|(>=)|(<>)|(>)|(<)|(=))' 2. addop → '(\+|\-)' 3. mulop → '((div)|(mod)|(\/)|(\*))' 4. assignop → ':=' 5. semicolon → ';' 6. colon → ':' 7. comma → ',' 8. leftparen → '\(' 9. rightparen → '\)' 10. begin → 'begin' 11. end → 'end' 12. if → 'if' 13. then → 'then' 14. else → 'else' 15. while → 'while' 16. do → 'do' 17. program → 'program' 18. var → 'var' 19. const → 'const' 20. real → '[0-9]+\.[0-9]+' 21. integer → '[0-9]+' 22. id → '[a-zA-Z][a-zA-Z0-9]*' 其中,数字和标识符的正则表达式比较简单,不再赘述。对于复杂一些的单词符号,我们需要注意一些细节: 1. relop的正则表达式中,需要将长度较长的运算符放在前面,以保证正则表达式匹配时能够正确地识别所有符合条件的运算符。 2. mulop的正则表达式中,需要将'/'和'*'分别使用'\/'和'\*'来表示,否则会出现语法错误。 3. 对于浮点数,我们需要使用'[0-9]+\.[0-9]+'来表示,其中的'.'需要使用转义字符'\'来转义。 4. 对于标识符,需要用'[a-zA-Z][a-zA-Z0-9]*'来表示,其中的'[a-zA-Z]'表示第一个字符必须是字母,'[a-zA-Z0-9]*'表示后面可以跟任意多个字母或数字。 在确定了所有单词符号的正则表达式后,我们就可以开始编写词法分析程序了。该程序的主要功能是将输入的pascal源代码分解为一个个单独的单词符号,方便后续的语法分析和语义分析。 该程序的基本流程如下: 1. 初始化:读入pascal源代码文件,打开输出文件,将游标指向开头位置。 2. 读取一个字符,判断它是否为空格或换行符。如果是,则继续读取下一个字符;否则进入下一步。 3. 根据当前游标位置,对源代码进行预处理,去掉注释等无用的内容。 4. 对当前游标位置开始的字符串进行匹配,依次按照单词符号的优先级,比较每个正则表达式是否与字符串匹配,如果匹配成功,则输出该单词符号,并将游标指向下一个位置,继续从第2步开始处理。 5. 如果没有任何正则表达式能够匹配当前字符串,则输出错误信息,停止程序运行。 在词法分析程序中,我们需要定义一个Token类,用来表示单词符号及其相关信息(如值、行号、列号等)。每次成功匹配一个单词符号后,我们就创建一个对应的Token对象,并将它输出到输出文件中。如果匹配失败,则输出错误信息,并停止程序的运行。 总的来说,词法分析程序需要具有高效、准确、健壮的特点,才能为语法分析和语义分析提供良好的基础。 ### 回答3: 为了完成正则文法所描述的pascal语言子集单词符号的词法分析程序,我们需要实现以下步骤: 一、正则文法分析:首先,我们需要对正则文法进行分析,以确定何种类型的正则表达式可用于描述我们所需的单词符号。在Pascal语言中,一些常见的单词符号包括标识符、数字、关键字、操作符和分隔符等。我们可以使用正则表达式来定义这些单词符号的模式,以便于程序进行匹配和分析。 二、程序设计:在了解了正则文法后,我们需要编写程序来实现词法分析。这个程序的目的是将输入的Pascal代码转换为一个个单词符号。在程序实现时,我们可以使用自动机的方法,将Pascal代码自动分解为单词符号,按照设定的正则表达式进行匹配和识别。可以使用各种语言编写这个程序,如Java, C++或Python等。 三、测试和调试:完成程序的设计后,我们需要进行测试和调试。可以使用一些代表性的Pascal程序进行测试,检查我们的程序是否正确识别单词符号。如果程序存在错误或缺陷,需要进行反复测试和排错,直到程序能够正确识别各种类型的单词符号。 总之,通过正则文法分析,程序设计和测试调试等步骤,我们可以完成一个完整的Pascal语言子集单词符号的词法分析程序。这个程序可以用于编译器等相关应用中,为程序员提供便利,从而实现高效的Pascal语言编程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值