PL/0语言编译预处理c++语言实现

1. 预处理的任务

预处理作为实现词法分析器的前提。

(1)合并空白符:把原始程序中相邻的空格、制表符、回车等空白符合并成一个空格,便于后续处理

(2)消除注释:消除原始程序中的注释内容

        单行注释:“//”引导内容,与C++语言中单行注释一致

        多行注释:“(*”和“*)”之间内容

2. PL/0示例程序

        

3. 思路

将预处理分为两个部分来完成:消除注释和合并空白符

(1)首先是消除注释:先将注释所在的行置为空行,再将空行去除。

注释有单行注释和多行注释:多行注释比较简单,只需要找到位置即可;单行注释分为整行都是注释,或者一行当中前一部分是代码,后一部分是注释。

(2)合并空白符

借鉴了其它博主的思想,将合并空白符转化为提取字符串,即将连续的字符串提取出来,再用空格做间隔。

4. 其它

在代码实现中使用了读文件和写文件操作。这个是参考其他博主的。下面附上链接。

首先读入文件pl0.txt,将文件内容存入一个字符串数组buffer[];将处理之后的结果存入字符串数组buffer1[],再写入文件pl0_txt

C++文件操作_Ant_Davis的博客-CSDN博客_c++文件操作文件操作程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放通过文件可以将数据持久化C++中对文件操作需要包含头文件 < fstream >文件类型分为两种:文本文件 - 文件以文本的ASCII码形式存储在计算机中二进制文件 - 文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们操作文件的三大类:ofstream:写操作ifstream: 读操作fstream : 读写操作1.1文本文件1.1.1写文件写文件步骤如下:包含https://blog.csdn.net/flyersboy/article/details/118090183?spm=1001.2014.3001.5506

5.代码实现

代码中的一些注释掉的输出语句,是用来调试程序的。

其中要注意在进行字符串提取时,要在每一行的末尾加上一个空格。

具体实现见代码和注释,如下。

#include<iostream>
#include<fstream>
#include<string.h>
using namespace std;

/**
	预处理程序的主要功能包括两部分:
	(1)合并空白符:把原始程序中相邻的空格、制表符、回车等空白符合并成一个空格,便于后续处理 
	(2)消除注释:消除原始程序中的注释内容。
		单行注释:“//”引导内容
		多行注释:“(*”和“*)”之间的内容 
**/

int main()
{
	ifstream ifs;
	ifs.open("pl0.txt");
	
	//读取:将文件读取到字符串数组buffer中
	string buf;
	string buffer[20]; //存储文件 
	int n=0;
	while(getline(ifs,buf)) 
	{
		int length=buf.length();
		if(length!=0) //将非空行存储到buffer中 
		{
			buffer[n]=buf;
			n++;
		}
	}//共存入n行 
	ifs.close();
	
	//消除单行注释:有两种情况
	//1.整行都是注释:将该行置为空行
	//2.代码+注释:删除注释部分 
	for(int i=0;i<n;i++)
	{
		int position=buffer[i].find("//");
		if(position!=-1) //有注释的行 
		{
			buffer[i]=buffer[i].substr(0,position);//截取前一部分(这个时候可能产生空行) 
		}
	}
	//消除多行注释:将多行注释置为空行
	int begin=-1; //"(*"所在的行 
	int end=-1; //"*)"所在的行 
	for(int i=0;i<n;i++)
	{
		if(buffer[i].find("(*")!=-1) begin=i;
		if(buffer[i].find("*)")!=-1) end=i;
		if(begin!=-1 && end!=-1)
		{
			for(int j=begin;j<=end;j++)
				buffer[j]="";
			begin=-1;
			end=-1;
		}
	}
	
	//将生成的空行删除,并合并空白符,结果另存于buffer1
	string buffer1[20];
	int m=0;
	for(int i=1;i<n;i++)
	{
		int length=buffer[i].length();
		if(length!=0) //对非空行进行保存 
		{
//			cout<<"第"<<i<<"行,长度为:"<<length<<endl;
			buffer[i]+=" "; //最后加一个空格便于截取子串 
//			cout<<"第"<<i<<"行,长度为:"<<buffer[i].length()<<endl;
			//对每一行当中的子串进行提取,通过空格间隔,存放入s中,最后将s存放入buffer1中
			string s="";
			int beg=-1; //每个子串的开始 
			int en=-1;  //每个子串的结束 
			for(int j=0;j<buffer[i].length();j++) //对每一个非空行进行遍历 
			{
				if(buffer[i][j]!=' ' && beg==-1) 
				{
					beg=j;
//					cout<<"字串开始于"<<beg<<endl;
				}
				if(buffer[i][j]==' ' && beg!=-1)
				{
					en=j;
//					cout<<"子串结束于"<<en<<endl;
					//截取子串
					string s1=buffer[i].substr(beg,en-beg); 
					s=s+s1+" ";
					beg=-1;
					en=-1;
				}	
			}
//			cout<<s<<endl;
			buffer1[m]=s;
			m++;
		}
	}//此时,buffer1中存放的是预处理后的程序,共有m行,每一行最后一个字符都是空格 
	
	
	//将预处理后的程序写入文件pl0_.txt 
	ofstream ofs;
	ofs.open("pl0_.txt");
	for(int i=0;i<m;i++)
	{
		ofs<<buffer1[i]<<endl;
	}
//	ofs<<"zww"<<endl;
	cout<<"预处理完毕!";
	ofs.close();
	return 0;
}

6. 生成的pl0_txt文件

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
program PL0 (input,output); (*PL/0 compiler with code generation*) (*Program 5.6 in Algorithms + Data Structures = Programs*) (*Almost identical with the version in Compilerbau*) (*Author: Niklaus Wirth*) label 99; (*定义标号*) const (*定义常量*) norw = 11; (*保留字最大长度*) txmax = 100; (*符号表最大记录数*) nmax = 14; (*数值型数据所含字符的最大长度*) al = 10; (*标识符最大长度*) amax = 2047; (*最大地址*) levmax = 3; (*分程序最大递归深度*) cxmax = 200; (*目标代码数组大小*) type (*定义类型*) 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,dosym,callsym,constsym,varsym,procsym); (*单词符号机内表示*) alfa = packed array[1..al] of char; (*标识符类型*) object = (constant,variable,procedure); (*类型标识符*) symset = set of symbol; (*式后字集合类型*) fct = (lit,opr,lod,sto,cal,int,jmp,jpc); (*目标代码中的操作码类型*) instruction = packed record f: fct; (*操作码*) l: 0..levmax; (*层差*) a: 0..amax; (*相对地址*) end; (* lit 0,a: 取常量a opr 0,a: 执行a 运算 lod l,a: 取变量(相对地址为a ,层差为l) sto l,a: 存变量 (相对地址为a ,层差为l) cal l,a: 调用过程(入口地址为a ,层差为l) int 0,a: 运行栈S 的指针值增加 a jmp 0,a: 转移到指令地址a 处 jpc 0,a: 条件转移到指令地址a 处*) var ch: char; (*当前字符*) sym: symbol; (*当前单词符号*) id: alfa; (*当前标识符*) num: integer;(*当前数*) cc: integer; (*行字符计数*) ll: integer; (*行长*) kk,err: integer; cx: integer; (*目标代码存放数组下标*) line: array[1..81] of char; (*行缓冲区*) a: alfa; code: array[0..cxmax] of instruction; (*目标代码区*) word: array[1..norw] of alfa; (*保留字表*) wsym: array[1..norw] of symbol; (*保留字机内表示表*) ssym: array[char] of symbol; (*运算符、界限符机内表示表*) mnemonic: array[fct] of packed array[1..5] of char; declbegsys,statbegsys,facbegsys: symset; table: array[0..txmax] of record name: alfa; case kind: object of constant: (val: integer); variable,procedure: (level,adr: integer) end; (*符号表*) procedure error(n: integer); (*报错程序*) begin writeln('****',' ':cc-1,'^',n:2); err:= err+1 end; (*error*)
C语言是一种通用的编程语言,它非常适合用于开发系统软件和应用程序。PL/0是一种简单的编程语言,用于教学和学习目的。下面是一个简单的C语言实现PL/0词法分析器的介绍: 1. 词法分析器的作用: 词法分析器负责将源代码分解为一个个的词法单元(Token),每个词法单元代表着语言中的一个符号,例如关键字、标识符、运算符等。 2. 实现PL/0词法分析器的步骤: - 定义Token的数据结构:可以使用结构体来定义Token,包含类型和值等信息。 - 读取源代码文件:使用C语言提供的文件操作函数,读取源代码文件内容。 - 实现词法分析函数:根据PL/0语言的语法规则,逐个读取字符并进行判断,生成相应的Token。 - 输出Token序列:将生成的Token序列输出到文件或者控制台。 3. 示例代码: 下面是一个简单的示例代码,用C语言实现PL/0词法分析器的基本功能: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> // 定义Token类型 typedef struct { int type; // Token类型 char value[100]; // Token值 } Token; // 词法分析函数 Token* lexer(const char* source_code) { // TODO: 实现词法分析逻辑 // 根据PL/0语言的语法规则,逐个读取字符并进行判断,生成相应的Token } int main() { const char* source_code = "BEGIN a:=1; END."; // 调用词法分析函数获取Token序列 Token* tokens = lexer(source_code); // 输出Token序列 for (int i = 0; tokens[i].type != -1; i++) { printf("Token: type=%d, value=%s\n", tokens[i].type, tokens[i].value); } // 释放内存 free(tokens); return 0; } ``` 这只是一个简单的示例,实际的PL/0词法分析器还需要考虑更多细节和语法规则。你可以根据自己的需求和PL/0语言的定义进行扩展和完善。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值