程序设计实验1 词法分析
一、实验目的:
通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
二、实验内容
编制一个单词获取程序,从文件输入的源程序中,识别出各个具有独立意义的单词,即关键字、标识符、整数、小数、字符串、字符、分隔符、运算符等八大类。
三、实验要求
1、词法规则
关键字: void、var、int、float、string、begin、end 、if、then、else、while、do、call、read、write、and、or
单词类别:1 注意:关键字大小敏感(区分大小写)。
标识符: 字母或 “ $ ” 打头、由字母、数字串或“$”组成的任意长度的符号串。
单词类别:2 注意:标识符大小敏感(区分大小写)。
整数: 数字串。
单词类别:3
小数: 数字串1. 数字串2
单词类别:4 注意:数字串1不能为空,数字串2可以为空,例如:23.
字符串: 由一对“”括起来的任意长度的符号串。注意:可以多行。
单词类别:5
字符: 由一对单引号括起来的单个字母。如:‘a’、‘5’、‘+’
单词类别:6
分隔符: {、}、(、)、;、空格
单词类别:7
运算符: ==、=、<、<=、>、>=、<>、+、-、*、/
单词类别:8
注释: 支持单行注释和多行注释(注释语法同C语言)。
为了实现的编译程序实用,这里规定源程序可采用自由书写格式,即一行内可以书写多个语句,一个语句也可以占领多行书写。
2、设计要求
(1)设计一个主程序,通过人机交互的方式或命令行参数获得需要分析的源代码文件,打开待分析的源程序,通过反复调用词法分析程序逐个获得源代码中的所有单词并输出。
整个程序的总体流程见图1-1。
(2)设计一个词法分析器,其输入为要分析的源文件,每次调用顺序识别出源文件中的下一个单词。每个单词需要输出:单词本身、单词类别、单词所在的行列号。遇到错误时可显示“Error”,然后跳过错误部分继续显示。
注意:在主程序中输出单词的信息,词法分析中不能输出单词信息,只能通过返回值或全局变量返回所提取的单词信息。
(3)实验结束后提交源代码、测试数据、实验报告至:
ftp://编译原理/程序设计1
本次实验提交的截止日期:2023-04-15 晚22:00 前.
(4)实验报告内容:(具体参见“编译原理程序设计实验报告模版.docx”)
(a) 有关词法分析器设计的说明。详细说明词法分析器的实现原理,包括软件结构设计说明、功能模块说明、关键数据结构说明、关键算法实现等。
(b) 给出词法分析器源程序清单,并标记出每个模块的功能;
© 说明词法分析器中可能存在的问题;
(d) 经验总结,如果重做一遍,你会有哪些新的改进?
四、实验过程和指导
(一)准备:
1、阅读课本有关章节,明确语言的语法,写出基本保留字、标识符、常数、运算符、分隔符和程序例。
2、初步编制好程序。
3、准备好多组测试数据,包括正确的输入和错误的输入。
(二)程序要求:
程序输入/输出示例:
如源程序为C语言。输入如下一段:
void main()
{
int a,b;
a = 10;
b = a + 20;
}
要求输出如下所示,每个单词输出:单词类型、单词本身、行号、列号。
(1,void,1, 1)
(2,main, 1, 6)
(7, ( ,1,10)
(7, ),1,11)
(7, { ,2, 1)
(1, int,3, 4)
(2, a ,3, 8)
(…
(三)设计指导:
词法分析程序的主要工作为:
(1)从源程序文件中逐个读入字符。
(2)统计行数和列数用于错误单词的定位。
(3)删除空格类字符,包括回车、制表符空格。
(4)根据每个单词的首字符确定该单词的类型,按构词规则从源文件中逐个读入字符检查该字符是否该单词的允许输入。
在编写词法分析程序时,用重复调用词法分析子程序取一单词的方法得到整个源程序的单词序列。
整个程序的总体流程见图1-1。
词法分析程序的流程图见图1-2。
取字符和统计字符行列位置子程序见图1-3。
注意:图1-2、图1-3仅供参考,并不完全符合本次实验的要求,仅仅说明整个词法分析程序的总体框架。因此,实验报告中不能直接贴图1-1、图1-2、图1-3,否则实验报告以无效处理。
图1-1
源代码:
import java.util.Arrays;
import java.util.Scanner;
import java.util.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.regex.Pattern;
class Results{
boolean rig;
int type;
String res;
int li=0,co=0;
}
public class Main {
static final int N=101;
static int a[]=new int [N];
static boolean ok=false;
static boolean mark=false;
static boolean biu=false;
static int blank=0;
static int k=0,lines,cols;
static int num=0;
static boolean words=false;
static String strs="";
static Results RE[]=new Results[N];
static String keyWord[]={"void","var","int","float","string","begin","end","if",
"then","else","while","do","call","read","write","and","or"};
static String symbol[]={"{","}","(",")",";"," "};
static String operation[]={"==","=","<","<=",">",">=","<>","+","-","*","/"};
static ArrayList<String> keyWords=null;
static ArrayList<String> symbols=null;
static ArrayList<String> operations=null;
public static void letterCheck(String str){
cols=k+1;
String token= String.valueOf(str.charAt(k++));
char ch;
for( ;k<str.length();k++){
ch=str.charAt(k);
if (!Character.isLetterOrDigit(ch)&&ch!='$')
break;
else
token+=ch;
}
if(ok)
cols+=blank;
if (keyWords.contains(token)){
RE[num].rig=true;RE[num].type=1;
RE[num].res=token;RE[num].li=lines;RE[num].co=cols;
++num;
}
else{
RE[num].rig=true;RE[num].type=2;
RE[num].res=token;RE[num].li=lines;RE[num].co=cols;
++num;
}
if (k!=str.length()-1||(k==str.length()-1&&(!Character.isLetterOrDigit(str.charAt(k))&&str.charAt(k)!='$')))
k--;
}
public static void digitCheck(String str){
cols=k+1;
String token= String.valueOf(str.charAt(k++));
int flag=0;
boolean err=false;
char ch;
for( ;k<str.length();k++){
ch=str.charAt(k);
if(ch==' '||(!Character.isLetterOrDigit(ch)&&ch!='.')||
symbols.contains(ch)||operations.contains(ch))
break;
else if (err)
token+=ch;
else{
token+=ch;
if (ch == '.') {
if(flag>=1)
err=true;
flag++;
}
else if (Character.isLetter(ch))
err=true;
}
}
if(token.charAt(token.length()-1)=='.'&&flag>=2)
err=true;
if(err){
RE[num].rig=false;RE[num].type=-1;
RE[num].res=token;RE[num].li=lines;RE[num].co=cols;
++num;
}
else{
if(ok)
cols+=blank;
if(flag==0) {
RE[num].rig=true;RE[num].type=3;
RE[num].res=token;RE[num].li=lines;RE[num].co=cols;
++num;
}
else{
RE[num].rig=true;RE[num].type=4;
RE[num].res=token;RE[num].li=lines;RE[num].co=cols;
++num;
}
}
if(k!=str.length()-1||(k==str.length()-1&&!Character.isDigit(str.charAt(k))))
k--;
}
public static void stringCheck(String str){
cols=k+1;
String token=String.valueOf(str.charAt(k++));
char ch;
int n=str.length();
if(!words){
for(int i=0;i<n;++i){
if(str.charAt(i)=='"'){
RE[num].li=lines;
RE[num].co=i+1+(ok==true?blank:0);
break;
}
}
}
for( ;k<n;++k){
ch=str.charAt(k);
token+=ch;
if(words==true&&ch=='"'){
strs+=token;
token=strs;
words=false;
break;
}
if(ch=='"')
break;
}
if(token.charAt(token.length()-1)!='"') {
words=true;
strs+=token;
return;
}
else{
RE[num].type=5;
RE[num].res=token;
++num;
}
}
public static void charCheck(String str){
cols=k+1;
String token=String.valueOf(str.charAt(k++));
char ch;
int n=str.length();
for( ;k<n;++k){
ch=str.charAt(k);
token+=ch;
if(ch=='\'')
break;
}
if(token.charAt(token.length()-1)!='\'') {
RE[num].rig=false;RE[num].type=-1;
RE[num].res=token;RE[num].li=lines;RE[num].co=cols;
++num;
}
else {
if(ok)
cols+=blank;
RE[num].rig=true;RE[num].type=6;
RE[num].res=token;RE[num].li=lines;RE[num].co=cols;
++num;
}
}
public static void symbolCheck(String str){
cols=k+1;
String token= String.valueOf(str.charAt(k++));
char ch;
if (symbols.contains(token)){
if(ok)
cols+=blank;
RE[num].rig=true;RE[num].type=7;
RE[num].res=token;RE[num].li=lines;RE[num].co=cols;
++num;
k--;
}
else {
if (operations.contains(token)){
if (k<str.length()){
ch=str.charAt(k);
if(str.charAt(k)=='/'&&str.charAt(k-1)=='/'){
mark=true;
return;
}
if(str.charAt(k-1)=='/'&&str.charAt(k)=='*'){
biu=true;
}
if(biu){
for(int i=k;i<str.length();++i){
if(str.charAt(i)=='*'&&str.charAt(i+1)=='/'){
biu=false;
k=i+1;
return;
}
}
return;
}
if (operations.contains(token+ch)){
token+=ch;
if(ok)
cols+=blank;
RE[num].rig=true;RE[num].type=8;
RE[num].res=token;RE[num].li=lines;RE[num].co=cols;
++num;
}
else {
k--;
if(ok)
cols+=blank;
if(mark==false&&biu==false){
RE[num].rig=true;RE[num].type=8;
RE[num].res=token;RE[num].li=lines;RE[num].co=cols;
++num;
}
}
}
}
else {
k--;
if(ok)
cols+=blank;
RE[num].rig=false;RE[num].type=-1;
RE[num].res=token;RE[num].li=lines;RE[num].co=cols;
++num;
}
}
}
public static void init(){
keyWords=new ArrayList<>();
operations=new ArrayList<>();
symbols=new ArrayList<>();
Collections.addAll(keyWords,keyWord);
Collections.addAll(symbols,symbol);
Collections.addAll(operations,operation);
}
public static void analyze(String str){
k=0;
char ch;
str=str.trim();
int n=str.length();
if(biu){
for(int i=0;i<n-1;++i){
if(str.charAt(i)=='*'&&str.charAt(i+1)=='/'){
biu=false;
k=i+2;
break;
}
}
}
if(biu)
return;
for ( ;k<str.length();k++){
ch=str.charAt(k);
if (Character.isDigit(ch))
digitCheck(str);
else if((words==false)&&(Character.isLetter(ch)||ch=='$'))
letterCheck(str);
else if (words==true||ch=='"')
stringCheck(str);
else if(ch=='\'')
charCheck(str);
else if (ch==' ')
continue;
else {
symbolCheck(str);
if(mark||biu)
return;
}
}
}
public static void main(String[] args) {
init();
File file=new File("D:\\Java_code\\Beijing\\src\\score3.txt");
try(Scanner in=new Scanner(file)) {
while (in.hasNextLine()){
String str=in.nextLine();
cols=0;
ok=false;
mark=false;
if(!words){
num=0;
for(int i=0;i<N;++i){
RE[i]=new Results();
RE[i].rig=true;RE[i].type=0;
RE[i].res="";RE[i].li=0;RE[i].co=0;
}
}
int len=str.length();
a[++lines]=len;
if(str.trim().length()!=a[lines]) {
blank=(a[lines] - str.trim().length());
ok=true;
}
analyze(str);
for(int i=0;i<num;++i){
if(RE[i].rig)
System.out.println("("+RE[i].type+","+RE[i].res+","+RE[i].li+","+RE[i].co+")");
else
System.out.println(RE[i].li+"line"+": "+RE[i].res+" Error");
}
}
}
catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
}
图1-1 总体架构设计
图1-2 词法分析程序
图1-3 取字符和统计字符行列位置
时间:2023年5月12日17:12:42
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)