目录
一.简单版
#include<stdio.h>
#include<iostream>
using namespace std;
#include<string.h>
//char prog[80]="begin if x>=24 then s:=0 end #"
char prog[80];
char token[8]; //prog存放输入符号串;token存放识别出的单词
int syn, p, sum,m;
char ch; //syn-种别码;p-prog数组的下标;sum-识别出的整数
char *rwtab[6] = {"begin", "if", "then", "while", "do", "end"}; //关键字表置初值
//扫描子程序
void scaner( )
{
m=0;
for (int n=0; n<8; n++ ) token[n]=NULL; //将token清空
ch=prog[p++] ; //根据全局变量p读取下一个字符,分析下一个单词
while (ch==' '|| ch == '\n') ch=prog[p++] ;
//1.首字符为字母的情况,可能为标识符或关键字
if(ch<='z'&& ch>='a')
{ m=0;
while (ch<='z'&& ch>='a'||ch<='9'&& ch>='0')
{
token[m++]=ch;//将ch保存至token[m++]中
ch=prog[p++] ;//读取下一个字符
}
token[m++]='\0';
p--;//......
syn=10 ; //标识符,置syn=10
for (int n=0; n<6; n++ ) //判断当前标识符是否为关键字
if (strcmp( token, rwtab[n])==0)
{
syn=n+1;//关键字,置关键字syn
break ;
}
}
//2.首字符为数字的情况,为整数
else if (ch<='9'&& ch>='0')
{
while (ch<='9'&& ch>='0')
{
sum=sum*10+ch-'0'; //将ch数字字符转换成整数送入sum,进位故sum*10,
ch=prog[p++] ;//读取下一个字符
}
p--;//.......
syn=11; //整数,置syn=11
}
//3.其他算符或界符等情况
else
switch(ch)
{
case '<':
token[m++]=ch; //ch存入token ;
ch=prog[p++] ;// 读下一个字符 ;
//三种情况,<=或<>或<
if (ch=='>')
{
syn=21;//将<>的种别码赋给syn;
token[p++]=ch; //ch存入token ;
}
else if (ch=='=')
{
syn=22;//将<=的种别码赋给syn;
token[p++]=ch; // ch存入token ;
}
else {
syn=20;//将<的种别码赋给syn;
p--;
}
break;
case '>':
token[m++]=ch; ch=prog[p++] ;// 读下一个字符 ;
if (ch=='=')
{
syn=24;//将<=的种别码赋给syn;
token[m++]=ch; // ch存入token ;
}
else {
syn=23;//将<的种别码赋给syn;
p--;
}
break;
case ':':
token[m++]=ch; //ch存入token ;
ch=prog[p++] ;// 读下一个字符 ;
if (ch=='=')
{
syn=18;//将<=的种别码赋给syn;
token[m++]=ch; // ch存入token ;
}
else {
syn=17;//将<的种别码赋给syn;
p--;
}
break;
case '+':
token[m++]=ch;syn=13;break;
case '-':
token[m++]=ch;syn=14;break;
case '*':
token[m++]=ch;syn=15;break;
case '/':
token[m++]=ch;syn=16;break;
case '=':
token[m++]=ch;syn=25;break;
case ';':
token[m++]=ch;syn=26;break;
case '(':
token[m++]=ch;syn=27;break;
case ')':
token[m++]=ch;syn=28;break;
case '#':
token[m++]=ch;syn=0;break;
default: syn= -1;
}
token[m++]='\0';
}
int main( ){
//......
printf( "\n please input string : \n" ) ;
do{
ch=getchar( );
prog[p++]=ch ;
} while(ch!='#');
p=0;//......
do{ //循环调用scanner()函数分析prog中的字符串,直到syn为0(即#)分析结束
scaner();
switch(syn){
case 11: //根据syn的值输出(syn,sum或者token)二元组
printf("%-6d %-5d\n",sum,syn);break;
default: printf("%-6s %-5d\n",token,syn);
}
}while(syn!=0);
}
二.简单版(文本保存)
c++版
此处是自己先创建一个1.txt文件
如:
const a=10;
var b,c;
procedure p;
begin
c:=b+a
end;
begin#
#include<stdio.h>
#include<string.h>
//"begin if x>24 then s:=0 end #"
char prog[80], token[10]; //prog存放输入符号串;token存放识别出的单词
int syn, p, sum=0,m;
char ch; //syn-种别码;p-prog数组的下标;sum-识别出的整数
char str;
char *rwtab[13] = {"begin", "if", "then", "while", "do", "end","const","var","procedure","odd","call","read","write"};//关键字表置初值
FILE* pf = fopen("2.txt", "w+");
//扫描子程序
void scaner( )
{
m=0;sum=0;
for (int n=0; n<8; n++ ) token[n]=NULL; //将token清空
ch=prog[p++] ; //根据全局变量p读取下一个字符,分析下一个单词
while (ch==' '|| ch == '\n') ch=prog[p++] ;
//1.首字符为字母的情况,可能为标识符或关键字
if(ch<='z'&& ch>='a')
{ m=0;
while (ch<='z'&& ch>='a'||ch<='9'&& ch>='0')
{
token[m++]=ch;//将ch保存至token[m++]中
ch=prog[p++] ;//读取下一个字符
}
token[m++]='\0';
p--;//......
syn=30 ; //标识符,置syn=30
for (int n=0; n<13; n++ ) //判断当前标识符是否为关键字
if (strcmp( token, rwtab[n])==0)
{
syn=n+1;//关键字,置关键字syn
break ;
}
}
//2.首字符为数字的情况,为整数
else if (ch<='9'&& ch>='0')
{
while (ch<='9'&& ch>='0')
{
sum=sum*10+ch-'0'; //将ch数字字符转换成整数送入sum
ch=prog[p++] ;//读取下一个字符
}
p--;//.......
syn=31; //整数,置syn=31
}
//3.其他算符或界符等情况
else
switch(ch)
{
case '<':
token[m++]=ch; //ch存入token ;
ch=prog[p++] ;// 读下一个字符 ;
//三种情况,<=或<>或<
if (ch=='>')
{
syn=21;//将<>的种别码赋给syn;
token[m++]=ch; //ch存入token ;
}
else if (ch=='=')
{
syn=22;//将<=的种别码赋给syn;
token[p++]=ch; // ch存入token ;
}
else {
syn=20;//将<的种别码赋给syn;
p--;
}
break;
case '>':
token[m++]=ch; ch=prog[p++] ;// 读下一个字符 ;
if (ch=='=')
{
syn=24;//将<=的种别码赋给syn;
token[p++]=ch; // ch存入token ;
}
else {
syn=23;//将<的种别码赋给syn;
p--;
}
break;
case ':':
token[m++]=ch; //ch存入token ;
ch=prog[p++] ;// 读下一个字符 ;
if (ch=='=')
{
syn=18;//将:=的种别码赋给syn;
token[m++]=ch; // ch存入token ;
}
else {
syn=17;//将:的种别码赋给syn;
p--;
}
break;
case '+':
token[m++]=ch;syn=32;break;
case '-':
token[m++]=ch;syn=14;break;
case '*':
token[m++]=ch;syn=15;break;
case '/':
token[m++]=ch;syn=16;break;
case '=':
token[m++]=ch;syn=25;break;
case ';':
token[m++]=ch;syn=26;break;
case '(':
token[m++]=ch;syn=27;break;
case ')':
token[m++]=ch;syn=28;break;
case '#':
token[m++]=ch;syn=0;break;
default: syn= -1;
}
token[m++]='\0';
}
int f(int syn){
if(syn==26||syn==27||syn==28){
printf("界符");
fprintf(pf," 界符\n");
}else if((syn>=20&&syn<=25)||(syn>=14&&syn<=16)||syn==18||syn==32){
printf("运算符");
fprintf(pf," 运算符\n");
}else if(syn>=1&&syn<=13){
printf("关键字");
fprintf(pf," 关键字\n");
}else if(syn==30){
printf("标识符");
fprintf(pf," 标识符\n");
}else if(syn==17){
printf("非法");
fprintf(pf," 非法\n");
}
}
int main( ){
p=0;
FILE* pf1 = fopen("1.txt", "r");
while((str=fgetc(pf1))!=EOF)
{ //如果没有读到末尾,则继续读取信息
prog[p++]=str;
if(str=='#'){
break;
}
}
prog[p++]='\0';
p=0;
do{ //循环调用scanner()函数分析prog中的字符串,直到syn为0(即#)分析结束
scaner();
switch(syn){
case 31: //根据syn的值输出(syn,sum或者token)二元组
fprintf(pf,"%-6d ",sum);
fprintf(pf," 数字\n");
printf("%-6d 数字\n",sum);
break;
default: {
fprintf(pf,"%-6s ",token);
printf("%-6s ",token);f(syn);printf("\n");
}
}
}while(syn!=0);
fclose(pf);//关闭文件
pf=NULL;
// fclose(pf1);
// pf1=NULL;
}
运行结果:
Java版
1.txt放你要读的文法
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
/*
* 保留字13个syn赋值1-13const ,var,procedure,begin,end,odd,if,then,call, while,do, read,write
* 标识符syn赋值14
* 常数syn赋值
* 运算符+,-,*,/,= syn赋值16-20 #syn赋值为0 <,<=,>,>=,:= syn赋值21-25
* 界符( ) , ; . syn赋值26-30
* */
public class PL0 {
static String prog="";
//static String prog="begin if x>=24 then s:=0 end #";
static String token1; //做保留识别出的值
static int syn; //种别码
static int p=0; //做索引
static int sum; //做常数
static char ch; //做字符串索引下取值
static String str=" "; //做写入txt中分隔
//13个关键字
static String[] rwtab = {"const" ,"var","procedure","begin","end","odd",
"if","then","call", "while","do", "read","write"};
static void scaner()
{
token1=""; //将token1清空
sum=0; //sum清空
ch=prog.charAt(p++) ; //读字符串p索引下
while (ch==' '|| ch == '\n') ch=prog.charAt(p++) ;
//1.首字符为字母的情况,可能为标识符或关键字
if(ch<='z'&& ch>='a')
{
while (ch<='z'&& ch>='a'||ch<='9'&& ch>='0')
{
token1+=ch;
ch=prog.charAt(p++) ;//读取下一个字符
}
p--;
syn=14 ; //标识符,置syn=14
for (int n=0; n<13; n++ ) //判断当前标识符是否为关键字
if (token1.equals(rwtab[n]) )
{
syn=n+1;
break ;
}
}
//2.首字符为数字的情况,为整数
else if (ch<='9'&& ch>='0')
{
while (ch<='9'&& ch>='0')
{
sum=sum*10+ch-'0'; //将ch数字字符转换成整数送入sum,进位故sum*10,
ch=prog.charAt(p++) ;//读取下一个字符
}
p--;
syn=15; //常数,置syn=15
}
//3.其他算符或界符等情况
else
switch(ch)
{
case '+':
token1+=ch;syn=16;break;
case '-':
token1+=ch;syn=17;break;
case '*':
token1+=ch;syn=18;break;
case '/':
token1+=ch;syn=19;break;
case '=':
token1+=ch;syn=20;break;
case '#':
token1+=ch;syn=0;break;
//<与<=
case '<':
token1+=ch;
ch=prog.charAt(p++) ;
if (ch=='=')
{
syn=22;
token1+=ch;
}else{
syn=21;
p--;
}
break;
//>与>=
case '>':
token1+=ch; ch=prog.charAt(p++) ;// 读下一个字符 ;
if (ch=='=')
{
syn=24;
token1+=ch;
}
else {
syn=23;
p--;
}
break;
case ':':
token1+=ch;
ch=prog.charAt(p++) ;
if (ch=='=')
{
syn=25;
token1+=ch;
}
break;
case '(':
token1+=ch;syn=26;break;
case ')':
token1+=ch;syn=27;break;
case ',':
token1+=ch;syn=28;break;
case ';':
token1+=ch;syn=29;break;
case '.':
token1+=ch;syn=30;break;
default: syn= -1;
}
}
public static void main(String[] args) throws IOException {
//System.out.print("please input string :");
//Scanner input = new Scanner(System.in);
//prog=input.nextLine();
FileInputStream fos0;
FileOutputStream fos1;
FileOutputStream fos2;
FileOutputStream fos3;
FileOutputStream fos4;
FileOutputStream fos5;
try {
fos0=new FileInputStream("src/1.txt");
int ch=0;
while ((ch=fos0.read())!=-1){
prog+=(char)ch;
}
System.out.println(prog);
fos0.close();
fos1=new FileOutputStream("src/关键字.txt",true);
fos2=new FileOutputStream("src/标识符.txt",true);
fos3=new FileOutputStream("src/运算符.txt",true);
fos4=new FileOutputStream("src/常数.txt",true);
fos5=new FileOutputStream("src/界符.txt",true);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
do{ //循环调用scanner()函数分析prog中的字符串,直到syn为0(即#)分析结束
scaner();
if(token1!="") {
//System.out.println(token1+" "+syn);
System.out.printf("%-8s",token1+" ");
}
//关键字1-13
if(syn>=1&&syn<=13){
fos1.write((token1+str+"\n").getBytes(StandardCharsets.UTF_8));
System.out.println("基本字");
}
//标识符14
else if(syn==14){
fos2.write((token1+str+"\n").getBytes(StandardCharsets.UTF_8));
System.out.println("标识符");
}
//运算符16-25和#0
else if(syn>=16&&syn<=25||syn==0){
fos3.write((token1+str+"\n").getBytes(StandardCharsets.UTF_8));
System.out.println("运算符");
}
//常数15
else if(syn==15){
fos4.write((String.valueOf(sum)+str+"\n").getBytes(StandardCharsets.UTF_8));
//System.out.println(sum+" "+syn);
System.out.printf("%-8d",sum);
System.out.println("数字");
} else {
fos5.write((token1+str+"\n").getBytes(StandardCharsets.UTF_8));
System.out.println("界符");
}
}while(syn!=0);
fos0.close();
fos1.close();
fos2.close();
fos3.close();
fos4.close();
fos5.close();
}
}
运行结果:
三.第三版(文本保存)
c++版
#include <stdio.h>
#include <string.h>
enum symbol {
nul, ident, number, plus, minus,
times, slash, oddsym, eql, neq,
lss, leq, gtr, geq, lparen,
rparen, comma, semicolon, period, becomes,
beginsym, endsym, ifsym, thensym, whilesym,
writesym, readsym, dosym, callsym, constsym,
varsym, procsym,
};
int cc, ll;
FILE * fa1;
int err; /*错误计数器*/
FILE* fin;
int cx;
char ch;
char line[81];
#define getchdo if(-1==getch())return -1
# define al 10
char a[al + 1];
char id[al + 1];
# define norw 13
char word[norw][al];
enum symbol sym;
enum symbol wsym[norw];
# define nmax 14
int num;
enum symbol ssym[256];
char fname[al];
void init();
void error(int n);
int getch();
int getsym();
int main()
{
printf("Input pl/0 file?");
scanf("%s", fname); /* 输入PL/0源程序文件名 */
fin = fopen(fname, "r");
if(fin)
{
printf("Output pl/0 file?");
scanf("%s", fname);
fa1 = fopen(fname, "w");
init();
// err = 0;
// cc = cx = ll = 0;
// ch = ' ';
while(getsym() != -1);
}
else
{
printf("找不到文件\n");
}
printf("\n");
return 0;
}
void init()
{
int i;
/* 设置单字符符号 */
for(i=0; i<=255; i++)
{
ssym[i] = nul;
}
ssym['+'] = plus;
ssym['-'] = minus;
ssym['*'] = times;
ssym['/'] = slash;
ssym['('] = lparen;
ssym[')'] = rparen;
ssym['='] = eql;
ssym[','] = comma;
ssym['.'] = period;
ssym['#'] = neq;
ssym[';'] = semicolon;
/* 设置保留字名字,按照字母顺序,便于折半查找 */
strcpy(word[0], "begin");
strcpy(word[1], "call");
strcpy(word[2], "const");
strcpy(word[3], "do");
strcpy(word[4], "end");
strcpy(word[5], "if");
strcpy(word[6], "odd");
strcpy(word[7], "procedure");
strcpy(word[8], "read");
strcpy(word[9], "then");
strcpy(word[10], "var");
strcpy(word[11], "while");
strcpy(word[12], "write");
/* 设置保留字符号 */
wsym[0] = beginsym;
wsym[1] = callsym;
wsym[2] = constsym;
wsym[3] = dosym;
wsym[4] = endsym;
wsym[5] = ifsym;
wsym[6] = oddsym;
wsym[7] = procsym;
wsym[8] = readsym;
wsym[9] = thensym;
wsym[10] = varsym;
wsym[11] = whilesym;
wsym[12] = writesym;
}
/*
* 出错处理,打印出错位置和错误编码
*/
void error(int n)
{
char space[81];
memset(space,32,81);
space[cc-1] = 0; //出错时当前符号已经读完,所以cc-1
printf("****%s!%d\n",space,n);
fprintf(fa1,"****%s!%d\n",space,n);
err++;
}
/*
* 漏掉空格,读取一个字符。
*
* 每次读一行,存入line缓冲区,line被getsym取空后再读一行
*
* 被函数getsym调用。
*/
int getch()
{
if(cc==ll)
{
if(feof(fin))
{
printf("program incomplete");
return -1;
}
ll=0;
cc=0;
ch = ' ';
while(ch != 10)
{
if(EOF == fscanf(fin,"%c",&ch))
{
line[ll]=0;
break;
}
//fprintf(fa1,"%c", ch);
line[ll]=ch;
ll++;
}
}
ch = line[cc];
cc++;
return 0;
}
/*
* 词法分析,获取一个符号
*/
int getsym()
{
int i,j,k;
if(ch=='#'){
return -1;
}
while(ch==' ' || ch==10 || ch==9) /* 忽略空格、换行和TAB */
{
getchdo;
}
if(ch>='a' && ch<='z')
{ /* 名字或保留字以a~z开头*/
k = 0;
do{
if(k<al)
{
a[k]=ch;
k++;
}
getchdo;
}while(ch>='a'&&ch<='z' || ch>='0'&&ch<='9');
a[k] = 0;
strcpy(id,a);
i=0;
j=norw-1;
do{ /* 搜索当前符号是否为保留字 */
k=(i+j)/2;
if(strcmp(id,word[k]) <= 0)
{
j=k-1;
}
if(strcmp(id,word[k]) >= 0)
{
i=k+1;
}
}while(i<=j);
if(i-1>j)
{
printf("%s 保留字\n", id);
fprintf(fa1,"%s 保留字\n", id);
sym=wsym[k];
}
else
{
printf("%s 标识符\n", id);
fprintf(fa1,"%s 标识符\n", id);
sym=ident; /* 搜索失败,则是名字或数字 */
}
}
else
{
if(ch>='0'&&ch<='9')
{ /* 检测是否为数字:以0~9开头 */
k=0;
num=0;
sym=number;
do{
//printf("%c\n",ch);
num=10*num+ch-'0';
k++;
getchdo;
}while(ch>='0'&&ch<='9'); /* 获取数字的值 */
k--;
if(k>nmax)
{
error(30);
}
printf("%d 整数\n",num);
fprintf(fa1,"%d 整数\n", num);
}
else
{
if(ch==':') /* 检测赋值符号 */
{
getchdo;
if(ch=='=')
{
printf(":= 运算符\n");
fprintf(fa1,":= 运算符\n", id);
sym=becomes;
getchdo;
}
else
{
printf(": error\n");
sym=nul; /* 不能识别的符号 */
}
}
else
{
if(ch=='<') /* 检测小于或小于等于符号 */
{
getchdo;
if(ch=='=')
{
printf("<= 运算符\n");
fprintf(fa1,"<= 运算符\n", id);
sym=leq;
getchdo;
}
else
{
printf("< 运算符\n");
fprintf(fa1,"< 运算符\n", id);
sym=lss;
}
}
else
{
if(ch=='>') /* 检测大于或大于等于符号 */
{
getchdo;
if(ch=='=')
{
printf(">= 运算符\n");
fprintf(fa1,">= 运算符\n", id);
sym=geq;
getchdo;
}
else
{
printf("> 运算符\n");
fprintf(fa1,"> 运算符\n", id);
sym=gtr;
}
}
else
{
if(ch=='=')
{
printf("= 运算符\n");
fprintf(fa1,"= 运算符\n", id);
//getchdo;
}
if(ch=='+')
{
printf("+ 运算符\n");
fprintf(fa1,"+ 运算符\n", id);
getchdo;
}
else if(ch=='-')
{
printf("- 运算符\n");
fprintf(fa1,"- 运算符\n", id);
getchdo;
}
else if(ch=='*')
{
printf("* 运算符\n");
fprintf(fa1,"* 运算符\n", id);
getchdo;
}
else if(ch=='/')
{
printf("/ 运算符\n");
fprintf(fa1,"/ 运算符\n", id);
getchdo;
}
else if(ch=='(')
{
printf("( 运算符\n");
fprintf(fa1,"( 运算符\n", id);
getchdo;
}
else if(ch==')')
{
printf(") 运算符\n");
fprintf(fa1,") 运算符\n", id);
getchdo;
}
else if(ch==',')
{
printf(", 运算符\n");
fprintf(fa1,", 运算符\n", id);
getchdo;
}
else if(ch==';')
{
printf("; 运算符\n");
fprintf(fa1,"; 运算符\n", id);
getchdo;
}
else if(ch=='.')
{
printf(". 运算符\n");
fprintf(fa1,". 运算符\n", id);
getchdo;
}
else
{
sym=ssym[ch]; /* 当符号不满足上述条件时,全部按照单字符符号处理 */
if(sym != period)
{
getchdo;
}
}
}
}
}
}
}
return 0;
}