词法分析
词法分析过程
- 作为第一阶段,任务是从左到右逐个字符读入。对字符流进行扫描和分解,识别出一个个单词。
分析逻辑
- 读取测试数据
- 转化为字符流
- 设计算法分析字符流,产生相应档次
以c语言为例:标识符、整数(为了简单)、分界符、运算符、注释符、关键字。
能力有限,本人只能分解出(标识符、关键字)(分界符、运算符)
核心算法实现
标识符:或字母开头,后面、字母、数字
整数:数字开始后面都是数字
思路读取一个字符,判断是 字母 、数字、、运算符
字母,判断下一个 是否是字母、、数字_ ,否则完成一个成分
数字,判断下一个 是否是数字,否则完成一成分
,与字母类似
default:则是运算符,判断下一个是否是字母数字,否则完成一成分
判断字母得出的是标识符和关键字,后期需要进行分离
public ArrayList<String> token(ArrayList<Character> c){
ArrayList<String> a = new ArrayList<String>();
String a1 = "";
ListIterator<Character> it = c.listIterator();
boolean flag=true; //标志是否完成一部分
int a2=0;
while(it.hasNext()){
if(flag==true){//判断是否开始新的识别
char c1 = ' ';
c1=it.next().charValue();
if(this.num( c1)) {
a2=1;
}
if(this.identifier(c1)) {
a2=2;
}
if(c1=='_') {
a2=3;
}
if(c1==' ') {
continue;
}
if(!(this.num(c1)|this.identifier(c1)|c1=='_'|c1==' '))
a2 =0;
it.previous();
}
switch(a2){
case 1 :
a1 = a1 + (it.next()).toString();
if(this.num(( it.next()).charValue())&&it.hasNext())
flag=false;
else {
flag=true;
a.add(a1);a1="";
}
it.previous();
break;
case 2 :
a1 = a1 + (it.next()).toString();
if(this.identifier(( it.next()).charValue())&&it.hasNext())
flag=false;
else {
flag=true;
a.add(a1);
a1="";
}
it.previous();
break;
case 3 :
a1 = a1 + (it.next()).toString();
if(this.identifier((it.next()).charValue())&&it.hasNext())
flag=false;
else {
flag=true;
a.add(a1);a1="";
}
it.previous();
break;
default :
char c3 = it.next();
a1 = a1 +(new Character(c3).toString());
char c2 = ' ';
if(it.hasNext())
c2 = it.next().charValue();
if(c2==' '|this.identifier(c2 )|this.num(c2)|!(c2=='='&&(c3=='>'|c3=='!'|c3=='=')))
{flag=true;a.add(a1);a1="";}
else {
flag=false;
}
if(!(c2==' '))
it.previous();
break;
}
}
return a;
}
源码
package temp;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.ListIterator;
interface Judge{
//判断数字
boolean num(char c);
//判断标识符
boolean identifier (char c);
//获取测试数据,转化为String,分割单个字符存储
ArrayList<Character> getString(String s);
//获取相关文件数据
HashMap<String,String> readData(String s);
//保存当前识别的单个字符
ArrayList<String> token(ArrayList<Character> c);
//获取string的name
String getN(String s, String path);
//获取种别
String getT(String s, String path,String path1);
}
class Word implements Judge{
public boolean num(char c){
if('0'<=c && c<='9')
return true;
else
return false;
}
public boolean identifier(char c){
if(c=='_'|('a'<=c && c<='z')|('A'<=c && c<='Z'))
return true;
else
return false;
}
public ArrayList<Character> getString(String s){
BufferedReader b1 = null ;
ArrayList<Character> c = new ArrayList<Character>();
try{
InputStreamReader file = new InputStreamReader(new FileInputStream(s),"utf-8");
b1 = new BufferedReader(file);
int ch ;
while((ch= b1.read())!=-1){
if(ch==10|ch==11|ch==13|ch==9)
c.add(' ');
else
c.add((char)ch);
}
}catch(IOException e){
e.printStackTrace();
}
return c;
}
public HashMap<String,String> readData(String s){
BufferedReader b1 = null;
HashMap<String,String> m = new HashMap<String,String>();
try{
InputStreamReader file = new InputStreamReader(new FileInputStream(s),"utf-8");
b1 = new BufferedReader(file);
String line;
while((line=b1.readLine()) != null){
String[] s1 = line.split(" ");
int i = 0;
while(i<s1.length){
m.put(s1[i],s1[++i]);
i++;
}
}
}catch(IOException e){
e.printStackTrace();
}
return m;
}
//将单个字符,识别成相应的字符串存储
public ArrayList<String> token(ArrayList<Character> c){
ArrayList<String> a = new ArrayList<String>();
String a1 = "";
ListIterator<Character> it = c.listIterator();
boolean flag=true; //标志是否完成一部分
int a2=0;
while(it.hasNext()){
if(flag==true){//判断是否开始新的识别
char c1 = ' ';
c1=it.next().charValue();
if(this.num( c1)) {
a2=1;
}
if(this.identifier(c1)) {
a2=2;
}
if(c1=='_') {
a2=3;
}
if(c1==' ') {
continue;
}
if(!(this.num(c1)|this.identifier(c1)|c1=='_'|c1==' '))
a2 =0;
it.previous();
}
switch(a2){
case 1 :
a1 = a1 + (it.next()).toString();
if(this.num(( it.next()).charValue())&&it.hasNext())
flag=false;
else {
flag=true;
a.add(a1);a1="";
}
it.previous();
break;
case 2 :
a1 = a1 + (it.next()).toString();
if(this.identifier(( it.next()).charValue())&&it.hasNext())
flag=false;
else {
flag=true;
a.add(a1);
a1="";
}
it.previous();
break;
case 3 :
a1 = a1 + (it.next()).toString();
if(this.identifier((it.next()).charValue())&&it.hasNext())
flag=false;
else {
flag=true;
a.add(a1);a1="";
}
it.previous();
break;
default :
char c3 = it.next();
a1 = a1 +(new Character(c3).toString());
char c2 = ' ';
if(it.hasNext())
c2 = it.next().charValue();
if(c2==' '|this.identifier(c2 )|this.num(c2)|!(c2=='='&&(c3=='>'|c3=='!'|c3=='=')))
{flag=true;a.add(a1);a1="";}
else {
flag=false;
}
if(!(c2==' '))
it.previous();
break;
}
}
return a;
}
public String getN(String s,String path){//该方法需实现识别整数、标识符、关键字(包括关键字和运算符和分隔符),首先识别集合范围小的最终得出补集(标识符)
HashMap<String,String> h =readData(path);
try { //通过是否产生异常判断整数
Integer.valueOf(s);
return "整型常量";
}catch(Exception e) {
if(h.get(s)==null)
return "标识符";
}
return h.get(s);
}
public String getT(String s,String path,String path1){
HashMap<String , String > h = readData(path);
try {
Integer.valueOf(s);
return "11";
}catch(Exception e) {
if(this.getN(s, path1)=="标识符")
return "10";
}
return h.get(s);
}
}
public class Test{
public static void main(String args[]) throws IOException{
File file = new File("Result.txt");
FileWriter f = new FileWriter(file.getName().intern(),true);
//BufferedWriter b1 = new BufferedWriter(f);
Word w = new Word();
ArrayList<Character> a = w.getString("src/temp/testdata.txt");
ArrayList<String> b = w.token(a);
ListIterator<String> i = b.listIterator();
while(i.hasNext()) {
String s = i.next();
String s1 =w.getN(s,"src/temp/name.txt")+"\t--"+w.getT(s,"src/temp/type_code.txt","src/temp/name.txt")+"\t,"+s+"\n";
System.out.print(s1);
f.write(s1);
}
f.flush();
f.close();
}
}
小结
- 思路整理:
首先判断整数常量,再判断标识符(包含关键字和标识符),最后判断符号(运算符和界符)
由于关键字和运算符、界符是有限的可以进行分离(可以采用补集的思想,先分出小集合得出大集合) - 总结
本次对于词法分析的实现,加深了编译原理里的词法规则的理解,即一个合法的单词的组成规则,理解了规则通过代码实现各种类型的判断。