您的位置:首页 > 编程语言 > Java开发

编译原理 - 递归向下法语法分析(Java版)

2017-12-23 15:11 387 查看
这个程序有些局限性,即不能分析任意语法。

分析的语法如下:



代码结构如下:



代码如下:

Main.java:

package cn.porkbar.recursion;

import java.io.IOException;
import java.util.Scanner;

public class Main
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
System.out.println("请输入要分析的文件路径,输入-1退出:");
String op;
RecursionDown parser;
while (sc.hasNext())
{
op = sc.next();
if (op.equals("-1"))
{
System.out.println("谢谢使用!");
break;
}
else
{
try
{
parser = new RecursionDown(op);
parser.Parser();
}
catch (IOException e)
{
System.out.println("无法打开文件!");
}

}
System.out.println("*****************************\n请输入要分析的文件路径,输入-1退出:");
}
}
}


RecursionDown.java:

/*
规则:
⑴<程序>::=begin<语句串>end
⑵<语句串>::=<语句>{;<语句>}
⑶<语句>::=<赋值语句>
⑷<赋值语句>::=ID:=<表达式>
⑸<表达式>::=<项>{+<项> | -<项>}
⑹<项>::=<因子>{*<因子> | /<因子>
⑺<因子>::=ID | NUM | (<表达式>)

syn映射表:
-1:未知的符号
0:结束符$
10:自定义变量名
1、2...9:begin和end关键字(3-9为保留串,后续可继续扩充)
11:数字
12、13、14、15:加减乘除符号
16:';'字符
17:':='字符
18、19:左右括号
*/
package cn.porkbar.recursion;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import cn.porkbar.util.Util;

public class RecursionDown
{
private File file;      //要读取的文件
static private String[] rwtab = {"begin","end"};        //关键字映射表
private char[] pro = new char[1024*1024];       //可以读取1M以内的文件
private int pos;        //扫描的位置
private int syn;        //扫描结果的特征值,对应的映射表在上面注释
private StringBuffer token;     //扫描出来的字符串
private int num;        //扫描出来的数字
public RecursionDown(String road) throws IOException
{
file = new File(road);
FileInputStream in = new FileInputStream(file);
{
int pos = 0;
int t;
while ((t = in.read()) != -1)
pro[pos++] = (char)t;

//Debug
//          System.out.println(new String(pro,0,pos));
}
in.close();
pos = 0;

System.out.println("待编译的本文为:");
System.out.println(String.valueOf(pro).trim());
}
private boolean Scan()
{
char ch;
do      //忽略空格、换行符、制表符
{
ch = pro[pos++];
}while (ch == ' ' || ch == '\t' || ch == '\n');

if (Util.isAlpha(ch))
{
token = new StringBuffer("");
token.append(ch);
while(Util.isAlpha(pro[pos]) || Util.isDigit(pro[pos]))
{
ch = pro[pos++];
token = token.append(ch);
}

//Debug
//          System.out.println(token.toString());

syn = 10;
for (int i = 0 ; i < rwtab.length ; i++)
{
if (token.toString().equals(rwtab[i]))
{
syn = i+1;
break;
}
}
return true;
}
else if (Util.isDigit(ch))
{
num = 0;
num = ch-'0';
while (Util.isDigit(pro[pos]))
num = num*10 + pro[pos++] - '0';
syn = 11;
if (Util.isAlpha(pro[pos]))     //后面如果跟上字母则出错
return false;
return true;
}
else
{
switch(ch)
{
case '+':
syn = 12;
break;
case '-':
syn = 13;
break;
case '*':
syn = 14;
break;
case '/':
syn = 15;
break;
case ';':
syn = 16;
break;
case ':':
if (pro[pos] == '=')
pos++;
else
{
syn = -1;
return false;
}
syn = 17;
break;
case '(':
syn = 18;
break;
case ')':
syn = 19;
break;
case '$':
syn = 0;
break;
default:
syn = -1;
return false;
}
return true;
}
}
private boolean SentenceAnalysis()
{
if (!Statement())
return false;
while (syn == 16)       //这个地方应该用循环,表示可以多个语句
{
Scan();
if (!Statement())
return false;
}
return true;
}
private boolean Factor()
{
if (syn == 10 || syn == 11)
{
Scan();
return true;
}
if (syn == 18)
{
Scan();
if (!Expression())
return false;
if (syn == 19)
{
Scan();
return true;
}
else
{
System.out.println("缺少')'!");
return false;
}
}
else
{
System.out.println("因子编译出错!");
return false;
}
}
private boolean Term()
{
if (!Factor())
return false;
if (syn == 14 || syn == 15)
{
Scan();
if (!Factor())
return false;
}
return true;
/*else if (syn == 16)       //若项后面没有*或/号,也可能为空,不用出错处理,给上一级扫描即可
{
Scan();
return true;
}
else
{
System.out.println("项编译出错!");
return false;
}*/
}
private boolean Expression()
{
if (!Term())
return false;
if (syn == 12 || syn == 13)
{
Scan();
if (!Term())
return false;
}
return true;
/*else if (syn == 2)        //没有+-号丢给上一级处理
{
Scan();
return true;
}
else
{
System.out.println("表达式编译出错!");
return false;
}*/
}
private boolean Statement()
{
if (syn == 10)      //自定义变量名
{
Scan();
if (syn == 17)
{
Scan();
if (!Expression())
return false;
return true;
}
else
{
System.out.println("不合法的赋值语句!");
return false;
}
}
else
{
System.out.println("不合法的变量名!");
return false;
}
}
public void Parser()
{
Scan();
if (syn == 1)
{
Scan();
if (!SentenceAnalysis())
{
return;
}
if (syn == 2)
{
Scan();
if (syn == 0)
{
System.out.println("语法分析成功!");
return;
}
else
{
System.out.println("没有找到合法的结束符!");
}
}
else
System.out.println("代码结束符end读取出错!");
}
else
{
System.out.println("代码开始符begin读取出错!");
}
}
}


Util.java:

package cn.porkbar.util;

import java.util.ArrayList;

public class Util
{
static public boolean isAlpha(char ch)      //判断是否是字母
{
if ((ch >= 'a' && ch <= 'z') || (ch >='A' && ch <= 'Z'))
return true;
return false;
}
static public boolean isDigit(char ch)
{
if (ch >= '0' && ch <= '9')
return true;
return false;
}
static public ArrayList<String> getItems(String str)
{
char[] chs = str.toCharArray();
ArrayList<String> items = new ArrayList<String>();
for (char ch : chs)
{
if (ch == '\'')
{
String t = items.get(items.size()-1) + "'";
items.remove(items.size()-1);
items.add(t);
}
else
{
String t = Character.toString(ch);
items.add(t);
}
}
return items;
}
}


然后我们运行一下看一下效果:



有兴趣的可以试试分析一下其他的语法,代码有bug欢迎指出~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 编译原理 递归