第1关:词法分析程序设计与实现
任务描述
本关任务:加深对词法分析器的工作过程的理解;加强对词法分析方法的掌握;能够采用一种编程语言实现简单的词法分析程序;能够使用自己编写的分析程序对简单的程序段进行词法分析。
相关知识
为了完成本关任务,你需要掌握:词法分析程序设计与实现。
词法分析的基本知识
词法分析程序( Lexical analyzer,简称 Lexer ),负责从左到右逐个字符地对源程序进行扫描和分解,根据语言的词法规则识别出一个个的单词符号。
因此一个词法分析程序应具备如下功能:
-
从左至右扫描构成源程序的字符流
-
识别出有词法意义的单词
-
返回单词记录,或词法错误信息
由上可知词法分析中的一个重要环节为识别单词符号类型,为了便于语法分析,通常将单词符号分为五类。
-
标识符 用来命名程序中出现的变量、数组、函数、过程、标号等,通常是一个字母开头的字母数字串,如 length,nextch 等。
-
基本字 也可以成为关键字或保留字。如
if,while,for,do,goto
等。他们具有标识符的形式,但他们不是由用户而是由语言定义的,其意义是约定的。多数语言中规定,他们不能作为标识符或者标识符的前缀,即用户不能使用它们来定义用户使用的名字,故我们称它为保留字,这些语言如 Pascal 和 C 等。但也有的语言允许将基本字作为标识符或者标识符的前缀,这类语言如 Fortran 等。 -
常数 包括各种类型的常数,如整型、实型、字符型、布尔型等。如:
5
、3.1415926
、a
、TRUE
等都是常数。 -
运算符 算术运算符
+
、-
、×
、÷
;关系运算符<
,<=
,>
,>=
,==
,!=
以及逻辑运算符&&
,()
,||
或者!
等。 -
界符 如
,
、;
等单字界符和/
,/
,//
等双字界符,空白符等。
在进行词法分析后,识别出来的单词应该采用某种中间表示形式,以便为编译后续阶段方便地引用。通常一个单词用一个二元式来表示: (单词类别,单词的属性)
其中,第一元用于区分单词所属的类别,以整数编码表示。第二元用于区分该类别中的哪一个单词符号,即单词符号的值。
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
public class ex1 {
/*
* 1表示关键字
* 2表示标识符
* 3表示常数
* 4表示运算符
* 5表示界符
* 6表示字符串
* */
//关键字
static String []keyWord={"private","protected","public","abstract","class","extends","final","implements",
"interface","native","new","static","strictfp","break","continue","return","do","while","if","else","for",
"instanceof","switch","case","default","boolean","byte","char","double","float","int","long","short",
"String","null","true","false","void","this","goto"};
//运算符
static String []operation={"+","-","*","/","%","++","--","-=","*=","/=","&","|","^","~","<<",">>",">>>","==","!=",
">","<","=",">=","<=","&&","||","!","."};
//界符
static String []symbol={",",";",":","(",")","{","}"};
static ArrayList<String> keyWords=null;
static ArrayList<String> operations=null;
static ArrayList<String> symbols=null;
//指向当前所读到字符串的位置的指针
static int p,lines;
public static void main(String []args) throws FileNotFoundException {
init();
File file=new File("/data/workspace/myshixun/input.txt");
lines=1;
try(Scanner input=new Scanner(file)) {
while (input.hasNextLine()){
String str=input.nextLine();
analyze(str);
lines++;
}
}
}
//初始化把数组转换为ArrayList
public static void init(){
keyWords=new ArrayList<>();
operations=new ArrayList<>();
symbols=new ArrayList<>();
Collections.addAll(keyWords, keyWord);
Collections.addAll(operations, operation);
Collections.addAll(symbols, symbol);
}
public static void analyze(String str){
p=0;
char ch;
str=str.trim();
for (;p<str.length();p++){
ch=str.charAt(p);
if (Character.isDigit(ch)){
digitCheck(str);
}else if (Character.isLetter(ch)||ch=='_'){
letterCheck(str);
}else if (ch=='"'){
stringCheck(str);
}
else if (ch==' '){
continue;
}else {
symbolCheck(str);
}
}
}
/********Beign********/
/*数字的识别*/
public static void digitCheck(String str){
String token= String.valueOf(str.charAt(p++));
int flag=0;
boolean err=false;
char ch;
for (;p<str.length();p++) {
ch = str.charAt(p);
if (ch==' '||(!Character.isLetterOrDigit(ch)&&ch!='.')) {
break;
}else if (err){
token+=ch;
}
else {
token+=ch;
if (ch == '.') {
if (flag == 1) {
err = true;
} else {
flag++;
}
}else if (Character.isLetter(ch)){
err=true;
}
}
}
}
/********End********/
/********Beign********/
//标识符,关键字的识别
public static void letterCheck(String str){
String token= String.valueOf(str.charAt(p++));
char ch;
for (;p<str.length();p++){
ch=str.charAt(p);
if (!Character.isLetterOrDigit(ch)&&ch!='_'){
break;
}else{
token+=ch;
}
}
if (keyWords.contains(token)){
System.out.println("("+1+","+token+")");
}else {
System.out.println("("+2+","+token+")");
}
if (p!=str.length()-1||(p==str.length()-1&&(!Character.isLetterOrDigit(str.charAt(p))&&str.charAt(p)!='_'))){
p--;
}
}
/********End********/
/********Beign********/
//符号的识别
public static void symbolCheck(String str){
String token= String.valueOf(str.charAt(p++));
char ch;
if (symbols.contains(token)){
System.out.println("("+5+","+token+")");
p--;
}else {
if (operations.contains(token)){
if (p<str.length()){
ch=str.charAt(p);
if (operations.contains(token+ch)){
token+=ch;
p++;
if (p<str.length()){
ch=str.charAt(p);
if (operations.contains(token+ch)){
token+=ch;
System.out.println("("+4+","+token+")");
}else{
p--;
System.out.println("("+4+","+token+")");
}
}else{
System.out.println("("+4+","+token+")");
}
}else {
p--;
System.out.println("("+4+","+token+")");
}
}
}else {
p--;
System.out.println(lines+"line"+": "+token+" is wrong");
}
}
}
/********End********/
//字符串检查
public static void stringCheck(String str){
String token= String.valueOf(str.charAt(p++));
char ch;
for (;p<str.length();p++){
ch=str.charAt(p);
token+=ch;
if (ch=='"'){
break;
}
}
if (token.charAt(token.length()-1)!='"'){
System.out.println(lines+"line"+": "+token+" is wrong");
}else {
System.out.println("("+6+","+token+")");
}
}
}