簡單的語法制導翻譯
第一步 文法
模擬寫出文法匹配過程
package Project;
import java.util.HashSet;
import java.util.Set;
public class simpleTranslation {
public static void main(String[] args) {
String str = "2+3-5+5";
caculate caculate = new caculate(str);
caculate.expr();
}
}
class caculate{
//向前看符號
char lookahead;
//儲存數字終結符
Set<Integer> dight = new HashSet<>();
//待匹配的串
String syntax;
//向前看指針,用於移動改變向前看符號
int index;
public caculate(String str){
syntax = str;
if(syntax==null||syntax.length()<=0){
System.out.println("syntax is null");
}
lookahead = syntax.charAt(0);
for (int i=0;i<10;i++){
dight.add(i);
}
}
public void expr(){
term();
rest();
}
/**
* p匹配0-9的數字
*/
public void term(){
if(dight.contains(Integer.parseInt(lookahead+""))){
char t = lookahead;//因爲match會改變向前看符號,所有需要保存數字
match(lookahead);
System.out.print(t);
}
}
/**
* 匹配表達式
*/
public void rest(){
switch (lookahead){
case '+':
match('+');//這裏寫死的打印+所以不需要保存
term();
System.out.print('+');
rest();
break;
case '-':
match('-');
term();
System.out.print('-');
rest();
break;
default:
break;
}
}
/**
* 匹配並移動向前看符號
* @param c 向前看符號
*/
public void match(char c){
if(lookahead==c){
if(index>=syntax.length()-1){
return;
}
lookahead =syntax.charAt(++index);
}
else
System.out.println("Syntax error");
}
}
優化
如果一個過程體執行的最後一條語句是對該過程的遞歸調用,那麼這個調用稱爲尾遞歸。
對應沒有參數的過程,一個尾遞歸調用可以被替換爲跳轉到開頭的語句,即變爲循環。
package Project;
import java.util.HashSet;
import java.util.Set;
public class simpleTranslation {
public static void main(String[] args) {
String str = "2+3-5+5";
caculate caculate = new caculate(str);
caculate.expr();
}
}
class caculate{
//向前看符號
char lookahead;
//儲存數字終結符
Set<Integer> dight = new HashSet<>();
//待匹配的串
String syntax;
//向前看指針,用於移動改變向前看符號
int index;
public caculate(String str){
syntax = str;
if(syntax==null||syntax.length()<=0){
System.out.println("syntax is null");
}
lookahead = syntax.charAt(0);
for (int i=0;i<10;i++){
dight.add(i);
}
}
public void expr(){
term();
rest();
}
/**
* p匹配0-9的數字
*/
public void term(){
if(dight.contains(Integer.parseInt(lookahead+""))){
char t = lookahead;//因爲match會改變向前看符號,所有需要保存數字
match(lookahead);
System.out.print(t);
}
}
/**
* 優化尾遞歸
*/
public void rest(){
while (true){
switch (lookahead){
case '+':
match('+');//這裏寫死的打印+所以不需要保存
term();
System.out.print('+');
rest();
continue;
case '-':
match('-');
term();
System.out.print('-');
rest();
continue;
default:
break;
}
break;
}
}
/**
* 匹配並移動向前看符號
* @param c 向前看符號
*/
public void match(char c){
if(lookahead==c){
if(index>=syntax.length()-1){
return;
}
lookahead =syntax.charAt(++index);
}
else
System.out.println("Syntax error");
}
}
一個簡單的詞法分析器
package Project;
//詞素類,用整型數字作爲ID
public class Token {
public final int tag;
public Token(int t){
tag=t;
}
@Override
public String toString() {
return "Token{" +
"tag=" + tag +
'}';
}
}
package Project;
//以字符串記錄值
public class Word extends Token {
public final String lexme;
public Word(int t,String str){
super(t);
lexme = new String(str);
}
@Override
public String toString() {
return "Word{" +
"laxme='" + lexme + '\'' +
", tag=" + tag +
'}';
}
}
package Project;
//枚舉常量
public class Tag {
public final static int
NUM = 256,ID=257,TRUE=258,FALSE=259;
}
第一版詞法分析器,可擴展
package Project;
import com.rabbitmq.client.AMQP;
import java.util.*;
public class Lexer {
//待分析字符串。
public String syntax;
//儲存詞素。
public Map<String,Token> map = new HashMap<>();
//記錄下一個char或空白。
public char peek;
//索引
public int index=0;
//行數
public int line = 0;
public Lexer(String s){
syntax = s;
reserve(new Word(Tag.TRUE,"true"));
reserve(new Word(Tag.FALSE,"false"));
}
private void reserve (Word w){
map.put(w.lexme,w);
}
/**
*
* @return 返回一個詞素,只有在是字符串時纔會加入map集合中
*/
public Token scan(){
clearTab();
Token cur = analysisNum();
if(cur!=null){
return cur;
}
cur = analysisWord();
if(cur!=null){
return cur;
}
Token t = new Token(peek);
index++;
return t;
}
/**
*
* @return Token of word or null
*/
public Token analysisWord(){
//處理單詞
if(Character.isLetter(peek)){
StringBuffer sb = new StringBuffer();
do{
index++;
sb.append(peek);
if(index>syntax.length()-1)
break;
peek = syntax.charAt(index);
}while (Character.isLetterOrDigit(peek));
String str = sb.toString();
Word w = (Word) map.get(str);
if(w!=null){//區分保留字與描述符
return w;
}
w = new Word(Tag.ID,str);
map.put(str,w);
return w;
}
return null;
}
/**
*
* @return Token of Num or null
*/
public Token analysisNum(){
//處理數字
if(Character.isDigit(peek)){
int value = 0;
do{
index++;
value = 10*value+Character.digit(peek,10);
if(index>syntax.length()-1)
break;
peek = syntax.charAt(index);
}while (Character.isDigit(peek));
return new Num(value);
}
return null;
}
/**
* 清除空格以及製表符
*/
public void clearTab(){
//剔除空白,製表符,換行符
for (;;){
if(index>syntax.length()-1)
return ;
peek = syntax.charAt(index);
if(peek==' '||peek=='\t'){
index++;
continue;
}else if(peek=='\n'){
index++;
line++;
}else {
break;
}
}
}
public void analysis(){
while (index<syntax.length()){
System.out.println(scan());
}
for (Map.Entry<String,Token> item:map.entrySet()){
System.out.println(item.getValue());
}
}
}