词法分析和语法分析1
- 格式:pdf
- 大小:160.20 KB
- 文档页数:19
词法分析和语法分析1
为了造福⼤众,你懂的
⼀.实验⽬的1.创建⼀个词法分析程序,该程序⽀持分析常规语法。必须使⽤DFA(确定性有限⾃动机)或NFA(不确定性有限⾃动机)来实现此程序。程序有两个输⼊:⼀个本⽂档,包括⼀组3°语法(正规⽂法)的产⽣式;⼀个源代码⽂本⽂档,包括⼀组需要识别的字符串。程序的输出是⼀个令牌表,该表由五种token组成:关键词,标识符,常量,限定符和运算符。
2.创建⼀个采⽤LL(1)⽅法或LR(1)⽅法的语法分析程序。程序的输⼊是⼀个⽂本⽂件包括⼀组的2°⽂法⽣成(上下⽂⽆关⽂法)产⽣式集合和任务1⽣成的token令牌表。该程序的输出是yes或no,即,这源代码的字符串是否符合这2°语法。
⼆.说明src⾥⾯是源代码,编译需要配置qt环境
Executable⾥⾯是编译好的exe⽂件
运⾏后:Function Choose底下选择词法分析还是语法分析,词法分析成功后才能分析语法。
Load选项加载测试的代码⽂件,然后选择uage⽂件夹底下词法分析的5个词法规则⽂件,共有常量(⽀持浮点和科学计数法),标识符、关键字、界符和操作符5种词法。
加载完成后没有提⽰,直接点run运⾏,可以看到输出token表,词法分析完成,同⽬录下会⽣成⼀个中间⽂件⽤于保存token。
然后Function Choose切到语法分析,测试代码和token表⾃动填好了,选择load语法规则⽂件,只有⼀个,加载成功后可以看到左下⾓的LR分析表(Action和Goto表合并了)。
然后再run,右下⾓显⽰分析过程,右上⾓显⽰分析结果(yes/no)。
另外,程序不⽀持打开中⽂路径底下的⽂件,⽀持的词法和语法有限。
三.词法
词法规则⽂件内容共分为五种,作为词法分析的依据。1. 常量
[const]->'NUMBER'"C"
"C"->'NUMBER'"C"
"C"->'.'"G"
"C"->'e'"E"
"C"->'E'"E"
"C"->''
"C"->'i'
[const]->'.'"D"
"D"->'NUMBER'"G"
"G"->'NUMBER'"G"
"G"->'e'"E""G"->'E'"E"
"G"->''
"G"->'i'
"E"->'+'"H"
"E"->'-'"H"
"E"->'NUMBER'"I"
"H"->'NUMBER'"I"
"I"->'NUMBER'"I"
"I"->''
"I"->'i'
2. 标识符
[identifier]->'LETTER'
[identifier]->'LETTER'"L"
"L"->'LETTER'"L"
"L"->'NUMBER'"L"
"L"->'LETTER'
"L"->'NUMBER'
3. 界符
[limiter]->';'
[limiter]->','
[limiter]->'('
[limiter]->')'
[limiter]->'{'
[limiter]->'}'
[limiter]->','
4. 关键字
[keyword]->'void'
[keyword]->'int'
[keyword]->'double'
[keyword]->'char'
[keyword]->'if'
[keyword]->'else'
[keyword]->'for'
[keyword]->'break'
[keyword]->'continue'
[keyword]->'return'
5. 操作符
[operator]->'+'
[operator]->'-'[operator]->'*'
[operator]->'/'
[operator]->'%'
[operator]->'='
[operator]->'<'
[operator]->'>'
[operator]->'+'"op"
[operator]->'-'"op"
[operator]->'*'"op"
[operator]->'/'"op"
[operator]->'%'"op"
[operator]->'='"op"
[operator]->'<'"op"
[operator]->'>'"op"
"op"->'='
[operator]->'+'"A"
"A"->'+'
[operator]->'-'"S"
"S"->'-'
四.语法[START]->"X"
"X"->'@'
"X"->"FUN""X"
"STYLE"->'void'
"STYLE"->'int'
"FUN"->"STYLE"'identifier''('')''{'"STATEMENTS"'}'
"FUN"->"STYLE"'identifier''('"PRALIST"')''{'"STATEMENTS"'}'
"PRALIST"->"PRA""EXRTA"
"EXRTA"->','"PRA"
"EXRTA"->'@'
"PRA"->"STYLE"'identifier'
"CALLPRALIST"->"VALUE""EXRTAB"
"EXRTAB"->'@'
"EXRTAB"->','"VALUE"
"BLOCK"->'{'"STATEMENTS"'}'
"STATEMENTS"->'@'
"STATEMENTS"->"STATEMENT""STATEMENTS""STATEMENT"->"EXPRESSION"';'
"STATEMENT"->"DEFINE"';'
"STATEMENT"->'identifier''('')'';'
"STATEMENT"->'identifier''('"CALLPRALIST"')'';'
"STATEMENT"->"BRANCH"
"STATEMENT"->'return'';'
"STATEMENT"->'return'"EXPRESSION"';'
"BRANCH"->'if''('"EXPRESSION"')'"BLOCK"
"EXPRESSION"->"VALUE"'operator'"VALUE"
"EXPRESSION"->"VALUE"'operator'"VALUE"
"VALUE"->'('"EXPRESSION"')'
"VALUE"->'identifier'
"VALUE"->'const'
"DEFINE"->"STYLE"'identifier'
"DEFINE"->"STYLE"'identifier''operator'"EXPRESSION"
"BLOCK"->"STATEMENT"
"BLOCK"->'{'"STATEMENTS"'}'
五.模块设计以及程序主要代码1.分析器主要流程:
2.模块设计:
主函数模块:程序开始,设计简单,主要调⽤窗体模块;
窗体模块:主要分为两部分,⼀是窗⼝的设计部分,定义页⾯分布以及功能按钮的实现,创造界⾯,⼆是调⽤功能函数;
功能函数模块:功能函数分别是词法分析和语法分析,语法分析建⽴在词法分析基础上,需要先进⾏词法分析。主要功能包括⽂件输⼊与输出,产⽣式的读⼊,对单词种类的判断,对输⼊字符串的判断等等。
模块关系图如下
3.Main函数:
#include "mainwindow.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show(); return a.exec();
}
4.Mainwindow:
主要构造了界⾯以及⽂法⽂件,测试代码的读⼊与中间⽂件,分析结果的输出,构造并显⽰分析表。1. 读⼊测试代码
void MainWindow::on_actionLoad_TestCode_triggered()
{
if(funcChoose==0){
QMessageBox::warning(this, tr("Analyzer"),tr("请先进⾏功能选择"));
return;
}
QString fileName = QFileDialog::getOpenFileName(this,"select testcode");
if (!fileName.isEmpty()) {
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("分析器"),
tr("⽆法读取⽂件 %1:\n%2.")
.arg(fileName).arg(file.errorString()));
return; // 只读⽅式打开⽂件,出错则提⽰,并返回false
}
QTextStream in(&file); // 新建⽂本流对象
QApplication::setOverrideCursor(Qt::WaitCursor);
// 读取⽂件的全部⽂本内容,并添加到编辑器中
ui->textEdit_1->setPlainText(in.readAll());
QApplication::restoreOverrideCursor();
}
}
2. 读⼊⽂法
void MainWindow::on_actionLoad_Grammer_triggered()
{
if(funcChoose==1){ // 词法分析则有多个
if(lexical!=NULL)delete lexical;
lexical=new Lexical();
ui->textEdit_2->clear();
QStringList fileNames = QFileDialog::getOpenFileNames(this,"select lexical");
for(int i=0;i
QString qs=fileNames.at(i);
lexical->buildDFA(qs.toStdString());
}