《编译原理实践及应用》第3章词法分析—DFA与NFA
- 格式:pptx
- 大小:3.30 MB
- 文档页数:49
编译原理第三章练习题答案编译原理第三章练习题答案编译原理是计算机科学中的重要课程之一,它研究的是将高级语言程序转化为机器语言的过程。
在编译原理的学习过程中,练习题是提高理解和应用能力的重要途径。
本文将为大家提供编译原理第三章的练习题答案,希望能够对大家的学习有所帮助。
1. 什么是词法分析?请简要描述词法分析的过程。
词法分析是编译过程中的第一个阶段,它的主要任务是将源程序中的字符序列划分为有意义的词素(token)序列。
词法分析的过程包括以下几个步骤:1)扫描:从源程序中读取字符序列,并将其转化为内部表示形式。
2)识别:根据预先定义的词法规则,将字符序列划分为不同的词素。
3)分类:将识别出的词素进行分类,如关键字、标识符、常量等。
4)输出:将分类后的词素输出给语法分析器进行进一步处理。
2. 什么是正则表达式?请给出一个简单的正则表达式示例。
正则表达式是一种用于描述字符串模式的工具,它由一系列字符和操作符组成。
正则表达式可以用于词法分析中的词法规则定义。
以下是一个简单的正则表达式示例:[a-z]+该正则表达式表示匹配一个或多个小写字母。
3. 请简要描述DFA和NFA的区别。
DFA(Deterministic Finite Automaton)和NFA(Nondeterministic Finite Automaton)是有限状态自动机的两种形式。
它们在词法分析中常用于构建词法分析器。
DFA是一种确定性有限状态自动机,它的状态转换是确定的,每个输入符号只能对应一个状态转换。
相比之下,NFA是一种非确定性有限状态自动机,它的状态转换是非确定的,每个输入符号可以对应多个状态转换。
4. 请简要描述词法分析器的实现过程。
词法分析器的实现过程包括以下几个步骤:1)定义词法规则:根据编程语言的语法规范,定义词法规则,如关键字、标识符、常量等。
2)构建正则表达式:根据词法规则,使用正则表达式描述不同类型的词素。
3)构建有限状态自动机:根据正则表达式,构建DFA或NFA来识别词素。
- 1 -实验三词法分析——有穷自动机的应用实验目的:一:输入正则文法二:FA1.生成FA(DFA或NFA)2.运行FA,DFA(自动);NFA(交互)3.**NFA→DFA实验设想:对输入的文法存储并判断是确定的有穷状态自动机还是不确定是有穷状态自动机,并给出标准的表示形式,若是DFA,可直接测试一个符号串是否是文法的句子,即能否被有穷状态机接受,给出过程及结果;若是NFA,首先将其转化为DFA,再测试一个符号串是否是文法的句子,亦即是否能被DFA接受。
例如:输入文法规则的数目:7输入开始状态: S输入文法Z::=Za Z::=Bb Z::=Aa B::=Ab B::=b A::=Ba A::=a此为确定有穷状态自动机!DFA D=({Z,A,B},{a,b},M,S,{Z}) 其中M:M(Z,a)=ZM(B,b)=ZM(B,a)=AM(A,a)=ZM(A,b)=BM(S,b)=BM(S,a)=A输入要推导的符号串:ababaaM(S,ababaa)=M(M(S,a),babaa)=M(A,babaa)=M(M(A,b),abaa)=M(B,abaa)=M(M(B,a),baa)=M(A,baa)=M(M(A,b),aa)=M(B,aa)=M(M(B,a),a)=M(A,a)- 1 -=Z该符号串能被有穷状态所接受!输入文法规则的数目:7输入开始状态: S输入规则:Z::=Ab Z::=Ba Z::=Zc A::=Ba A::=a B::=Ab B::=b 文法规则存储完毕!此为非确定有穷状态自动机!NFA N=({Z,B,A},{b,a,c},M,{S},{Z})其中M:M(A,a)=$M(A,b)={Z,B}M(A,c)=$M(B,a)={Z,A}M(B,b)=$M(B,c)=$M(Z,a)=$M(Z,b)=$M(Z,c)={Z}M(S,a)={A}M(S,b)={B}M(S,c)=$将NFA转化为DFA!DFA N'=({[S],[B],[A],[AZ],[BZ],[Z]},{[b],[a],[c]}, M',[S],F') 其中M':M'([S],b)=[B]M'([S],a)=[A]M'([B],a)=[AZ]M'([A],b)=[BZ]M'([AZ],b)=[BZ]M'([AZ],c)=[Z]M'([BZ],a)=[AZ]M'([BZ],c)=[Z]M'([Z],c)=[Z]其中F'={[AZ],[BZ],[Z]} 输入要推导的字符串:ababc M'([S],ababc)=M'(M'([S],a),babc)=M'([A],babc)=M'(M'([A],b),abc)=M'([BZ],abc)=M'(M'([BZ],a),bc)=M'([AZ],bc)=M'(M'([AZ],b),c)=M'([BZ],c)=[Z][Z]属于终止状态集合!该字符串能被有穷状态所接受!参考程序#include<iostream.h>#include<String.h>struct LeftItem;struct RightNode //存储状态转换关系中弧与终止状态结点结构{char tran;char nextstate;RightNode* nextsibling;RightNode(char x,char y){tran=x; nextstate=y; nextsibling=NULL;}};struct LeftItem //存储状态转换关系中初始状态结点结构{char state;RightNode* link;};struct StateItem //存放确定化的NFA状态结点结构{char newstates[10];StateItem(){newstates[0]='\0';}};/////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /// int CheckState(LeftItem Array[],int size){RightNode* p;RightNode* q;for(int i=0;i<size;i++){p=Array[i].link;q=p->nextsibling;if(q==NULL) return 1;while(q!=NULL){if(p->tran==q->tran) return 0;q=q->nextsibling;}}return 1;}int CheckExist(StateItem SArray[],int& length,char temp[])//将NFA确定化创建二维矩阵时判别新产生的状态是否在状态数组中存储过{ int i=0,k,m;while(i<=length){if(strlen(SArray[i].newstates)==strlen(temp)) {if(strcmp(SArray[i].newstates,temp)==0){k=i;break;}}i++;}if(i>length){length++;m=length;return m;}elsereturn k;}int getcount1(LeftItem Array[],int size) //取得FA中状态的个数{ char temp[20];int len=0,count=0;int i,j;RightNode* pNode;for(i=0;i<size;i++){pNode=Array[i].link;while(pNode){for(j=0;j<len;j++)if(pNode->nextstate==temp[j]) break;if(j==len){count++;temp[len]=pNode->nextstate;len++;}pNode=pNode->nextsibling;}}return count;}int getcount2(LeftItem Array[],int size) //取得FA中输入字母的个数{ char temp[20];int len=0,count=0;int i,j;RightNode* pNode;for(i=0;i<size;i++){pNode=Array[i].link;while(pNode){for(j=0;j<len;j++)if(pNode->tran==temp[j]) break;if(j==len){count++;temp[len]=pNode->tran;len++;}pNode=pNode->nextsibling;}}return count;}int getstate(RightNode* pNode,char arc) //判定一个状态是否能通过一条弧进入下一状态{while(pNode){if(pNode->tran==arc) return 1;pNode=pNode->nextsibling;}return 0;}void Sort(char A[],int n) //将取得的新状态进行排序{for(int i=n-1;i>0;i--)for(int j=0;j<i;j++){if(A[j+1]<A[j]){char temp=A[j+1];A[j+1]=A[j];A[j]=temp;}}}void Bianli1(LeftItem Array[],int size) //输出FA中有穷非空的状态集合{char temp[20];int len=0;int i,j;RightNode* pNode;for(i=0;i<size;i++){pNode=Array[i].link;while(pNode){for(j=0;j<len;j++)if(pNode->nextstate==temp[j]) break;if(j==len){if(len==0) cout<<pNode->nextstate;elsecout<<","<<pNode->nextstate;temp[len]=pNode->nextstate;len++;}pNode=pNode->nextsibling;}}}void Bianli2(LeftItem Array[],int size) //输出FA中有穷的输入字母表{char temp[20];int len=0;int i,j;RightNode* pNode;for(i=0;i<size;i++){pNode=Array[i].link;while(pNode){for(j=0;j<len;j++)if(pNode->tran==temp[j]) break; if(j==len){if(len==0) cout<<pNode->tran; elsecout<<","<<pNode->tran;temp[len]=pNode->tran;len++;}pNode=pNode->nextsibling;}}}void Bianli31(LeftItem Array[],int size)//输出DFA状态转换关系的集合M{int i;RightNode* pNode;for(i=0;i<size;i++){pNode=Array[i].link;while(pNode!=NULL){cout<<" M("<<Array[i].state<<","<<pNode->tran <<")="<<pNode->nextstate<<endl;pNode=pNode->nextsibling;}}}void Bianli32(LeftItem Array[],int size) //输出NFA状态转换关系集合M {char K[20];int len=0;int i,j;RightNode* pNode;RightNode* qNode;for(i=0;i<size;i++){pNode=Array[i].link;while(pNode){for(j=0;j<len;j++)if(pNode->tran==K[j]) break;if(j==len){K[len]=pNode->tran;len++;}pNode=pNode->nextsibling;}}Sort(K,len);for(i=0;i<size;i++){for(j=0;j<len;j++){pNode=Array[i].link;cout<<" M("<<Array[i].state<<","<<K[j]<<")="; if(getstate(pNode,K[j])){cout<<"{";while(pNode){if(pNode->tran==K[j]){qNode=pNode->nextsibling; cout<<pNode->nextstate; break;}pNode=pNode->nextsibling;}while(qNode){if(qNode->tran==K[j])cout<<","<<qNode->nextstate; qNode=qNode->nextsibling;}cout<<"}"<<endl;}elsecout<<"$"<<endl;}}}void Initiate(LeftItem Array[],int size,char TArray[]) //将FA中的输入字母表存入数组TArray[] {int len=0;int i,j;RightNode* pNode;for(i=0;i<size;i++){pNode=Array[i].link;while(pNode){for(j=0;j<len;j++)if(pNode->tran==TArray[j]) break;if(j==len){TArray[len]=pNode->tran;len++;}pNode=pNode->nextsibling;}}}void GetState(LeftItem Array[],int size,char nstate[],char arc,char temp[])//将NFA确定化创建二维矩阵时取得新状态{int i=0;while(nstate[i]!='\0'){for(int j=0;j<size;j++){if(Array[j].state==nstate[i]) {RightNode* p=Array[j].link; while(p!=NULL){if(p->tran==arc){int k=0;while(temp[k]!='\0'){if(p->nextstate==temp[k]) break; k++;}if(temp[k]=='\0'){temp[k]=p->nextstate;temp[k+1]='\0';}}p=p->nextsibling;}}}i++;}}void Change(StateItem SArray[],char temp[],int& length,intMArray[][20],int index,int i) //取得新状态后对状态数组以及状态转换矩阵进行对应变化{int k;if(temp[0]!='\0'){k=CheckExist(SArray,length,temp);MArray[index][i]=k;if(k==length)strcpy(SArray[length].newstates,temp);}}char FindNewState(LeftItem Array[],int size,char S,char arc) //得到当前状态的下一状态{int i;for(i=0;i<size;i++){if(Array[i].state==S){RightNode* p=Array[i].link;while(p!=NULL){if(p->tran==arc) return p->nextstate;p=p->nextsibling;}}}return NULL;}int Findy(char TArray[],char s) //取得输入字母在字母表中的下表{ int i=0;while(TArray[i]!='\0'){if(TArray[i]==s) return i;i++;}}void CreateFA1(LeftItem Array[],int size,char start,char end) //根据输入文法创建FA{if(CheckState(Array,size)){cout<<"此为确定有穷状态自动机!"<<endl; cout<<"DFA D=(";}else{cout<<"此为非确定有穷状态自动机!"<<endl; cout<<"NFA N=(";}cout<<"{";Bianli1(Array,size);cout<<"},{";Bianli2(Array,size);cout<<"},M,";if(CheckState(Array,size)) cout<<start; else cout<<"{"<<start<<"}";cout<<","<<"{"<<end<<"})"<<endl;cout<<"其中M:"<<endl;if(CheckState(Array,size))Bianli31(Array,size);elseBianli32(Array,size);}void CreateFA2(LeftItem Array[],int size,char start,charend,StateItem SArray[],char TArray[],int& length,int MArray[][20]) //将NFA转换为DFA{char temp[20];int index=0;int i;do{i=0;while(TArray[i]!='\0'){temp[0]='\0';GetState(Array,size,SArray[index].newstates,TArray[i],temp);Sort(temp,strlen(temp));Change(SArray,temp,length,MArray,index,i);i++;}index++;}while(index<=length);}void Display(StateItem SArray[],char TArray[],int MArray[][20],int x,int y,char start,char end)//输出确定化的NFA{int i,j,k;cout<<"将NFA转化为DFA!"<<endl;cout<<"DFA N'=({";for(i=0;i<x;i++){if(i==0) cout<<"["<<SArray[i].newstates<<"]"; else cout<<",["<<SArray[i].newstates<<"]";}cout<<"},{";for(i=0;i<y;i++){if(i==0) cout<<"["<<TArray[i]<<"]";elsecout<<",["<<TArray[i]<<"]";}cout<<"}, M',["<<start<<"],F')"<<endl;cout<<"其中M':"<<endl;for(i=0;i<x;i++)for(j=0;j<y;j++){if(MArray[i][j]!=-1){k=MArray[i][j];cout<<"M'(["<<SArray[i].newstates<<"],"<<TArray[j]<<")=["<<SArray[k].newst ates<<"]"<<endl;}}cout<<"其中F'={";k=0;for(i=0;i<x;i++){j=0;while(SArray[i].newstates[j]!='\0'){if(SArray[i].newstates[j]==end) break;j++;}if(SArray[i].newstates[j]!='\0'){if(k==0) cout<<"["<<SArray[i].newstates<<"]";elsecout<<",["<<SArray[i].newstates<<"]";k++;}}cout<<"}"<<endl;}void RunFA1(LeftItem Array[],int size,char start,char end) {char TD[20];int i=0,j;char s=start;cout<<"请输入要推导的符号串:"; cin>>TD;cout<<" M("<<s<<",";for(j=0;TD[j]!='\0';j++)cout<<TD[j];cout<<")"<<endl;while(TD[i]!='\0'){if(TD[i+1]!='\0'){cout<<"=M(M("<<s<<","<<TD[i]<<"),"; for(j=i+1;TD[j]!='\0';j++)cout<<TD[j];cout<<")"<<endl;}s=FindNewState(Array,size,s,TD[i]); if(s==NULL) break;if(TD[i+1]=='\0')cout<<"="<<s<<endl;else{cout<<"=M("<<s<<",";for(j=i+1;TD[j]!='\0';j++)cout<<TD[j];cout<<")"<<endl;}i++;}if(TD[i]=='\0'){if(s==end)cout<<"该符号串能被有穷状态所接受!"<<endl<<endl; elsecout<<"该符号串不能被有穷状态所接受!"<<endl<<endl;}elsecout<<"该符号串不能被有穷状态所接受!"<<endl<<endl;}void RunFA2(StateItem SArray[],char TArray[],int start,int end,int MArray[][20]){char TD[20];int i,j,k,x,y;char s=start;cout<<"请输入要推导的字符串:";cin>>TD;cout<<" M'(["<<s<<"],";for(i=0;TD[i]!='\0';i++)cout<<TD[i];cout<<")"<<endl;x=0;i=0;while(TD[i]!='\0'){if(TD[i+1]!='\0'){cout<<"=M'(M'([";cout<<SArray[x].newstates; cout<<"]";cout<<","<<TD[i]<<"),";for(j=i+1;TD[j]!='\0';j++) cout<<TD[j];cout<<")"<<endl;}y=Findy(TArray,TD[i]);x=MArray[x][y];if(x==-1) break;if(TD[i+1]=='\0'){cout<<"=";cout<<"["<<SArray[x].newstates<<"]"<<endl; }else{cout<<"=M'(";cout<<"["<<SArray[x].newstates<<"],";for(j=i+1;TD[j]!='\0';j++)cout<<TD[j];cout<<")"<<endl;}i++;}if(TD[i]=='\0'){for(k=0;SArray[x].newstates[k]!='\0';k++)if(SArray[x].newstates[k]==end) break;if(SArray[x].newstates[k]!='\0'){cout<<"["<<SArray[x].newstates<<"]"<<"属于终止状态集合!"<<endl;cout<<"该字符串能被有穷状态所接受!"<<endl<<endl;}elsecout<<"该字符串不能被有穷状态所接受!"<<endl<<endl;}elsecout<<"该字符串不能被有穷状态所接受!"<<endl<<endl;}/////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /// void main(){int size=0,sign=0;int i,j,n,sel;int count1,count2;int length=0;char start;char end;char temp[10];int MArray[20][20];RightNode* p;cout<<"请输入文法规则的数目:"; cin>>n;cout<<"请输入开始状态: ";cin>>start; //得到初始状态LeftItem* Array=new LeftItem[n]; for(i=0;i<n;i++){do{cout<<"请输入第"<<i+1<<"条规则:";cin>>temp;}while(strlen(temp)>6);if(strlen(temp)==6){for(j=0;j<size;j++)if(Array[j].state==temp[4]) break;if(j==size){Array[size].state=temp[4];Array[size].link=new RightNode(temp[5],temp[0]);size++;}else{for(p=Array[j].link;p->nextsibling!=NULL;p=p->nextsibling) {} p->nextsibling=new RightNode(temp[5],temp[0]);}}else{for(j=0;j<size;j++)if(Array[j].state==start) break;if(j==size){Array[size].state=start;Array[size].link=new RightNode(temp[4],temp[0]);size++;}else{for(p=Array[j].link;p->nextsibling!=NULL;p=p->nextsibling) {} p->nextsibling=new RightNode(temp[4],temp[0]);}}}end=Array[0].link->nextstate; //得到终止状态cout<<endl<<"文法规则存储完毕!"<<endl<<endl; count1=getcount1(Array,size);count2=getcount2(Array,size);StateItem* SArray=new StateItem[100];char* TArray=new char[count2+1];SArray[0].newstates[0]=start;SArray[0].newstates[1]='\0';Initiate(Array,size,TArray);TArray[count2]='\0';for(i=0;i<20;i++)for(j=0;j<20;j++)MArray[i][j]=-1;cout<<endl;aaa:cout<<"-----生成FA请按1-----"<<endl;cout<<"-----运行FA请按2-----"<<endl;cout<<"-----退出请按3-------"<<endl;do{cin>>sel;}while(sel!=1&&sel!=2&&sel!=3);switch(sel){case 1:CreateFA1(Array,size,start,end); //根据输入文法建立FAif(!CheckState(Array,size)) //将NFA确定化{CreateFA2(Array,size,start,end,SArray,TArray,length,MArray); Display(SArray,TArray,MArray,length+1,count2,start,end);}sign++;break;case 2:if(sign==0){cout<<"请先生成FA!"<<endl;goto aaa;}if(CheckState(Array,size))RunFA1(Array,size,start,end); //运行DFA elseRunFA2(SArray,TArray,start,end,MArray); //运行确定化的NFA break;case 3:break;}if(sel!=3) goto aaa;}。
第3章词法分析习题答案1.判断下面的陈述是否正确。
(1)有穷自动机接受的语言是正规语言。
(√)(2)若r1和r2是Σ上的正规式,则r1|r2也是Σ上的正规式。
(√)(3)设M是一个NFA,并且L(M)={x,y,z},则M的状态数至少为4个。
(× )(4)设Σ={a,b},则Σ上所有以b为首的符号串构成的正规集的正规式为b*(a|b)*。
(× )(5)对任何一个NFA M,都存在一个DFA M',使得L(M')=L(M)。
(√)(6)对一个右线性文法G,必存在一个左线性文法G',使得L(G)=L(G'),反之亦然。
(√) (7)一个DFA,可以通过多条路识别一个符号串。
(× )(8)一个NFA,可以通过多条路识别一个符号串。
(√)(9)如果一个有穷自动机可以接受空符号串,则它的状态图一定含有 边。
(× )(10)DFA具有翻译单词的能力。
(× )2.指与出正规式匹配的串.(1)(ab|b)*c 与后面的那些串匹配?ababbc abab c babc aaabc(2)ab*c*(a|b)c 与后面的那些串匹配? acac acbbc abbcac abc acc(3)(a|b)a*(ba)* 与后面的那些串匹配? ba bba aa baa ababa答案(1) ababbc c babc(2) acac abbcac abc(3) ba bba aa baa ababa3. 为下边所描述的串写正规式,字母表是{0, 1}.(1)以01 结尾的所有串(2)只包含一个0的所有串(3) 包含偶数个1但不含0的所有串(4)包含偶数个1且含任意数目0的所有串(5)包含01子串的所有串(6)不包含01子串的所有串答案注意 正规式不唯一(1)(0|1)*01(2)1*01*(3)(11)*(4)(0*10*10*)*(5)(0|1)*01(0|1)*(6)1*0*4.请描述下面正规式定义的串. 字母表{x, y}.(1) x(x|y)*x(2)x*(yx)*x*(3) (x|y)*(xx|yy) (x|y)*答案(1)必须以 x 开头和x结尾的串(2)每个 y 至少有一个 x 跟在后边的串 (3)所有含两个相继的x或两个相继的y的串5.处于/* 和 */之间的串构成注解,注解中间没有*/。
基本定义NFA,也称不确定的有穷自动机,是由一个五元式定义的数学模型,特点是它的不确定性,即在当前状态下,读入同一个字符,可能有多个下一状态。
DFA,也称确定的有穷自动机,也是由一个五元式定义的数学模型,相对的特点是它的确定性,即在当前状态下,读入同一个字符,最多有一个后继状态。
NFA与DFA的矩阵表示一个NFA或者DFA还可以用一个矩阵[5]表示,矩阵也可以说是状态转换表,它的优点是可以快速访问给定的状态在给定的输入字符时能转换到的状态集。
矩阵,每个状态一行,每个输入符号和ε(如果有需要的)各占一列,表的第i行中与输入符号a对应的表项是一个状态集合,表示NFA或者DFA在状态i输入a时所能到达的状态集合(DFA的集合唯一),即δ(i,a)[6]。
(7)如图可用表表示:NFA状态转换表DFA状态转换表NFA向DFA的转换的思路从NFA的矩阵表示中可以看出,表项通常是一状态的集合,而在DFA的矩阵表示中,表项是一个状态,NFA到相应的DFA的构造的基本思路是:DFA的每一个状态对应NFA的一组状态DFA使用它的状态记录在NFA读入一个输入符号后可能达到的所有状态[4]。
NFA和DFA之间的联系在非确定的有限自动机NFA中,由于某些状态的转移需从若干个可能的后续状态中进行选择,故一个NFA对符号串的识别就必然是一个试探的过程。
这种不确定性给识别过程带来的反复,无疑会影响到FA的工作效率。
而DFA则是确定的,将NFA转化为DFA将大大提高工作效率,因此将NFA转化为DFA是有其一定必要的。
子集构造法已证明:非确定的有限自动机与确定的有限自动机从功能上来说是等价的,也就是说,我们能够从:NFA M使得L(M)=L(M’)为了使得NFA确定化,我们首先给出两个定义:定义1:集合I的ε-闭包:令I是一个状态集的子集,定义ε-closure(I)为:1)若s∈I,则s∈ε-closure(I);2)若s∈I,则从s出发经过任意条ε弧能够到达的任何状态都属于ε-closure(I)。
词法分析(1)---词法分析的有关概念以及转换图词法分析是编译的第一个阶段,前面简介中也谈到过词法分析器的任务就是:字符流------>词法记号流这里词法分析和语法分析会交错进行,也就是说,词法分析器不会读取所有的词法记号再使用语法分析器来处理,通常情况下,每取一个词法记号,就送入语法分析器进行分析,图解:词法分析器是编译器中与源程序直接接触的部分,因此词法分析器可以做诸如1). 去掉注释,自动生成文档(c#中的///注释)2). 提供错误位置(可以通过记录行号来提供),当字符流变成词法记号流以后,就没有了行的概念3). 完成预处理,比如宏定义1. 词法记号,词法单元(lexeme),模式模式是一种规则每个词法单元都有一个特定记号比如 int a=3,这里 int,a,=,3都是词法单元,每个词法单元都属于某个词法记号,比如3就是"num"这个词法记号的一个词法单元,而模式规定了什么样的字符串的词法记号是什么样的(模式是一种规则)某一特定模式规定了某个词法记号下的一类词法单元,比如:模式:用字母开头的包含字母和数字的串上面模式的词法记号:id(所有符合上面模式的字符串的记号都是id)词法单元:a123 或者 aabc 等词法记号举例(简称为记号):1) 每个的关键字都有属于自己的一个记号,比如关键字for,它可以使用记号f or;关键字int,可以使用记号int2) 所有的关系运算符只有一个记号,比如 >=,<=都用记号relation3) 所有的标识符只有一个记号,比如a123,aab使用记号id4) 所有的常数只有一个记号,比如123,22,32.3,23E10使用记号num5) 所有的字符串只有一个记号,比如"123","ab1"使用记号literal在实际的编译器设计中,词法记号,一般用一个整形数字表示词法记号的属性:我们喜欢用<词法记号, 属性>这个二元组来描述一个词法单元,比如,对于源代码:position := initial + rate * 60对于词法单元 +,我们可以使用 <add_op, '+'> 来表示。