pl/0词法分析器
下面是这个分析器的功能:
1、 待分析的简单语言的词法
(1) 关键字:
begin if then while do end
所有关键字都是小写。
(2) 运算符和界符:
:= + – * / < <= <> > >= = ; ( ) #
(3) 其他单词是标识符(ID)和整型常数(NUM),通过以下正规式定义:
ID=letter(letter| digit)*
NUM=digit digit *
(4) 空格由空白、制表符和换行符组成。空格一般用来分隔ID、NUM,运算符、界符和关键字,词法分析阶段通常被忽略。
2、 各种单词符号对应的种别码
词法分析程序的功能
输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。
其中:syn为单词种别码;
token为存放的单词自身字符串;
sum为整型常数。
#include <iostream>
#include <fstream>
#include <string>
#include <windows.h>
using namespace std;
#define CODE "E:\\code\\code.txt"
#define RESULT "E:\\code\\result.txt"
//token数组用来接收关键字,变量,运算符和界符
//这里限制变量名的长度最多为9
//prog数组存储的是源代码字符串长度
char *prog, token[10];
char ch;
//syn是各个单词符号对应的数字
int syn, p, m = 0, n, line, sum = 0;
//rwtab数组存储的是关键字
char *rwtab1[10] = { "begin","if","then","while","do","end" };
char *rwtab2[4] = { "const","var","procedure","call" };
void scaner()
{
//规定,标识符只能由字母或数字构成
/*
共分为三大块,分别是标示符、数字、符号,对应下面的 if else if 和 else
*/
//将全部置空
for (n = 0; n<10; n++)
//token为已捕获的字符数
token[n] = NULL;
ch = prog[p++];
//这样处理,可以去除空格
while (ch == ' ')
{
ch = prog[p];
p++;
}
//在这个if判断中,范围是a-z或者A-Z,因为规定变量只能以字母开头
if ((ch >= 'a'&&ch <= 'z') || (ch >= 'A'&&ch <= 'Z')) //可能是标示符或者变量名
{
m = 0;
//这里,是变量的第一个字符以后,可以是字母,数字
while ((ch >= '0'&&ch <= '9') || (ch >= 'a'&&ch <= 'z') || (ch >= 'A'&&ch <= 'Z'))
{
token[m++] = ch;
ch = prog[p++];
}
//变量的字符串结束标志
token[m++] = '\0';
p--;
syn = 10;
//将识别出来的字符和已定义的标示符作比较, 判断是否是关键字,所有关键字都是小写
for (n = 0; n<6; n++)
if (strcmp(token, rwtab1[n]) == 0)
{
syn = n + 1;
break;
}
for (n = 0; n < 4;n++)
{
if (strcmp(token, rwtab2[n]) == 0)
{
syn = n + 31;
break;
}
}
}
else if ((ch >= '0'&&ch <= '9')) //数字 ,如果是数字,就用sum来保存这个数字
{
sum = 0;
while ((ch >= '0'&&ch <= '9'))
{
//这里*10是只考虑十进制数
sum = sum * 10 + ch - '0';
ch = prog[p++];
}
p--;
syn = 11;
//可接收的数字的最大值为32767,如果更大,会报错
if (sum>32767)
syn = -1;
}
else switch (ch) //如果是其他的字符
{
case '<':
m = 0;
token[m++] = ch;
ch = prog[p++];
if (ch == '>')
{
//说明是不等号
syn = 21;
token[m++] = ch;
}
else if (ch == '=')
{
//说明是<=
syn = 22;
token[m++] = ch;
}
else
{
//否则,就只是一个<符号
syn = 23;
//此时p回退一个
p--;
}
break;
case '>':
m = 0;
token[m++] = ch;
ch = prog[p++];
if (ch == '=')
{
syn = 24;
token[m++] = ch;
}
else
{
syn = 20;
p--;
}
break;
case ':':
m = 0;
token[m++] = ch;
ch = prog[p++];
if (ch == '=')
{
//说明是赋值运算符
syn = 18;
token[m++] = ch;
}
else
{
//否则就只是个:
syn = 17;
p--;
}
break;
case '*':
syn = 13;
token[0] = ch;
break;
case '/':
syn = 14;
token[0] = ch;
break;
case '+':
syn = 15;
token[0] = ch;
break;
case '-':
syn = 16;
token[0] = ch;
break;
case '=':
syn = 25;
token[0] = ch;
break;
case ';':
syn = 26;
token[0] = ch;
break;
case '(':
syn = 27;
token[0] = ch;
break;
case ')':
syn = 28;
token[0] = ch;
break;
case ',':
syn = 29;
token[0] = ch;
break;
case '!':
syn = 30;
token[0] = ch;
break;
case '.':
//如果接收到的是.,说明到了源代码的结尾,置syn=0,函数结束
syn = 0;
token[0] = ch;
break;
case '\n':
//如果接收到的是换行符,则syn=-2,行+1
syn = -2;
break;
default:
//如果接收到的是其他未定义的字符,置syn=-1,会报错。
syn = -1;
break;
}
}
/*
读取源代码文件(.txt)
*/
void read()
{
FILE *fp;
fp = fopen(CODE, "r");
fseek(fp, 0, SEEK_END);
int file_size;
file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
prog = (char *)malloc(file_size * sizeof(char));
fread(prog, file_size, sizeof(char), fp);
//关闭文件流
fclose(fp);
}
int main()
{
int p = 0;
int line = 1;
ofstream outfile(RESULT);
cout<< "加载代码文件中......" << endl;
Sleep(3000);
//读取源代码文件
read();
p = 0;
outfile << "词法分析的结果为:" << endl;
do
{
scaner();
switch (syn)
{
case 11:
//cout << "(" << syn << "," << sum << ")" << endl;
outfile << "(" << syn << "," << sum << ")" << endl;
break;
case -1:
//cout << "Error in line " << line << "!" << endl;
outfile << "Error in line" << line << "!" << endl;
break;
case -2:
line = line++;
break;
default:
//cout << "(" << syn << "," << token << ")" << endl;
outfile << "(" << syn << "," << token << ")" << endl;
break;
}
} while (syn != 0);
outfile.close();
cout << "词法分析完毕,请在result.txt中查看" << endl;
system("pause");
return 0;
}
pl/0 程序
var m, n, r, q;
procedure gcd;
begin
while r#0 do
begin
q := m / n;
r := m - q * n;
m := n;
n := r;
end;
end;
begin
read(m);
read(n);
if m < n then
begin
r := m;
m := n;
n := r;
end;
begin
r:=1;
call gcd;
write(m);
end;
end.
输出结果
#
#
using---->25
namespace---->25
std---->25
;------->41
int---->7
main---->1
(------->42
)------->43
const---->18
string---->25
str---->25
=------->38
hello---->25
;------->41
const---->18
string---->25
str2---->25
=------->38
world---->25
;------->41
string---->25
n_str---->25
;------->41
n_str---->25
=------->38
str---->25
;------->41
n_str---->25
+------->27
=------->38
str2---->25
;------->41
cout---->25
<------>33
<------>33
n_str---->25
<------>33
<------>33
endl---->25
;------->41
return---->17
0------>26
;------->41
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/judyge/article/details/52274690
标签:----,ch,pl0,syn,分析器,词法,token,25,break From: https://www.cnblogs.com/djcsch2001/p/18163603