basicInterpreter1.02 增加对for循环的支持

源码下载:https://files.cnblogs.com/files/heyang78/basicInterpreter102-20200531-2.rar

输入:

for x=1 to 10
    print(x)
next

print("")

for y=10 to 20
    print(y)
next

print("程序结束")

输出:

原文=  for x=1 to 10     print(x) next  print("")  for y=10 to 20     print(y) next  print("程序结束") 
Index                Type No              Text                 Type Desc            
------------------------------------------------------------------------------------
0                    12                   for                  for                  
1                    6                    x                    Variable             
2                    2                    =                    =                    
3                    4                    1                    Number               
4                    13                   to                   to                   
5                    4                    10                   Number               
6                    7                    print                Function             
7                    0                    (                    (                    
8                    6                    x                    Variable             
9                    1                    )                    )                    
10                   14                   next                 next                 
11                   7                    print                Function             
12                   0                    (                    (                    
13                   5                    ""                   String               
14                   1                    )                    )                    
15                   12                   for                  for                  
16                   6                    y                    Variable             
17                   2                    =                    =                    
18                   4                    10                   Number               
19                   13                   to                   to                   
20                   4                    20                   Number               
21                   7                    print                Function             
22                   0                    (                    (                    
23                   6                    y                    Variable             
24                   1                    )                    )                    
25                   14                   next                 next                 
26                   7                    print                Function             
27                   0                    (                    (                    
28                   5                    "程序结束"               String               
29                   1                    )                    )                    

执行结果:

1
2
3
4
5
6
7
8
9
10
""
10
11
12
13
14
15
16
17
18
19
20
"程序结束"

以下是核心类:

Token类:

package com.heyang;

public class Token {
    public static final int TYPE_OPEN_PARENTHESIS=0;        // (
    public static final int TYPE_CLOSE_PARENTHESIS=1;        // (
    public static final int TYPE_ASSIGN=2;                    // =
    public static final int TYPE_NUMBER=4;                    // d+
    public static final int TYPE_STRING=5;                    // w+
    public static final int TYPE_VARIABLE=6;                // Variable
    public static final int TYPE_FUNCTION=7;                // Function
    public static final int TYPE_EQUAL=8;                    // ==
    public static final int TYPE_IF=9;                        // if
    public static final int TYPE_THEN=10;                    // then
    public static final int TYPE_LESSTHAN=10;                // <
    public static final int TYPE_BIGGERTHAN=11;                // >
    public static final int TYPE_FOR=12;                    // For
    public static final int TYPE_TO=13;                        // To
    public static final int TYPE_NEXT=14;                    // Next
    
    private int type;
    private String text;
    private int index;// Used to remember location
    
    public Token(char c,int type) {
        this.text=String.valueOf(c);
        this.type=type;
    }
    
    public Token(String word,int type) {
        this.text=word;
        this.type=type;
    }
    
    public String toString() {
        return String.format("token(text=%s,type=%s,index=%d)", text,getTypeStr(),index);
    }
    
    public String getTypeStr() {
        if(type==TYPE_OPEN_PARENTHESIS) {
            return "(";
        }else if(type==TYPE_CLOSE_PARENTHESIS) {
            return ")";
        }else if(type==TYPE_ASSIGN) {
            return "=";
        }else if(type==TYPE_NUMBER) {
            return "Number";
        }else if(type==TYPE_STRING) {
            return "String";
        }else if(type==TYPE_VARIABLE) {
            return "Variable";
        }else if(type==TYPE_FUNCTION) {
            return "Function";
        }else if(type==TYPE_EQUAL) {
            return "==";
        }else if(type==TYPE_IF) {
            return "if";
        }else if(type==TYPE_THEN) {
            return "then";
        }else if(type==TYPE_LESSTHAN) {
            return "<";
        }else if(type==TYPE_BIGGERTHAN) {
            return ">";
        }else if(type==TYPE_FOR) {
            return "for";
        }else if(type==TYPE_TO) {
            return "to";
        }else if(type==TYPE_NEXT) {
            return "next";
        }
        
        return null;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
}

Lexer类:

package com.heyang;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Parse json string to tokens
 * @author Heyang
 *
 */
public class Lexer {
    private List<Token> tokens;

    public Lexer(String text) {
        tokens = new ArrayList<Token>();

        String swallowed = "";
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);

            if (Character.isWhitespace(c)) {
                addTextToList(swallowed);
                swallowed="";
                continue;
            } else if (c == '(') {
                addTextToList(swallowed);
                swallowed="";
                
                tokens.add(new Token(c, Token.TYPE_OPEN_PARENTHESIS));
            } else if (c == ')') {
                addTextToList(swallowed);
                swallowed="";
                
                tokens.add(new Token(c, Token.TYPE_CLOSE_PARENTHESIS));
            }else if (c == '>') {
                addTextToList(swallowed);
                swallowed="";
                
                tokens.add(new Token(c, Token.TYPE_BIGGERTHAN));
            }else if (c == '<') {
                addTextToList(swallowed);
                swallowed="";
                
                tokens.add(new Token(c, Token.TYPE_LESSTHAN));
            } else if (c == '=') {
                int next=i+1;
                if(next<text.length() && text.charAt(next)=='=') {
                    // ==
                    addTextToList(swallowed);
                    swallowed="";
                    tokens.add(new Token("==",Token.TYPE_EQUAL));
                    i++;
                }else {
                    // =
                    addTextToList(swallowed);
                    swallowed="";
                    tokens.add(new Token(c, Token.TYPE_ASSIGN));
                }
            } else if(c == '"') {
                addTextToList(swallowed);
                swallowed="";
                
                int idx=i+1;
                
                while(idx<text.length()) {
                    char cEnd = text.charAt(idx);
                    
                    if (cEnd == '"') {
                        break;
                    }
                    
                    idx++;
                }
                
                String sub=text.substring(i, idx+1);
                tokens.add(new Token(sub, Token.TYPE_STRING));
                i=idx;
            } else {
                swallowed += c;
            }
        }
        
        setTokenIndexes();
    }
    
    private void addTextToList(String text) {
        if("if".equalsIgnoreCase(text)) {
            tokens.add(new Token(text, Token.TYPE_IF));
        }else if("then".equalsIgnoreCase(text)) {
            tokens.add(new Token(text, Token.TYPE_THEN));
        }else if("for".equalsIgnoreCase(text)) {
            tokens.add(new Token(text, Token.TYPE_FOR));
        }else if("to".equalsIgnoreCase(text)) {
            tokens.add(new Token(text, Token.TYPE_TO));
        }else if("next".equalsIgnoreCase(text)) {
            tokens.add(new Token(text, Token.TYPE_NEXT));
        }else if(isFunction(text)) {
            tokens.add(new Token(text, Token.TYPE_FUNCTION));
        }else if(isNumber(text)) {
            tokens.add(new Token(text, Token.TYPE_NUMBER));
        }else if(isVarable(text)) {
            tokens.add(new Token(text, Token.TYPE_VARIABLE));
        } 
    }
    
    private boolean isFunction(String text) {
        if("print".equalsIgnoreCase(text)) {
            return true;
        }
        
        return false;
    }
    
    private boolean isNumber(String code) {
        final String patternStr = "\d+";
        return Pattern.matches(patternStr, code);
    }
    
    private boolean isVarable(String code) {
        final String patternStr = "([a-zA-Z_])\w*";
        return Pattern.matches(patternStr, code);
    }
    
    public void printTokens() {
        final String continuousStar = createRepeatedStr("-", 84);
        final String layout = "%-20s %-20s %-20s %-20s %s";
        StringBuilder sb = new StringBuilder();

        sb.append(String.format(layout, "Index", "Type No","Text","Type Desc","
"));
        sb.append(continuousStar + "
");
        int index=0;
        for(Token token:tokens) {
            sb.append(String.format(layout, String.valueOf(index),String.valueOf(token.getType()), token.getText(),token.getTypeStr(),"
"));
            index++;
        }
        
        System.out.println(sb.toString());
    }
    
    private static String createRepeatedStr(String seed, int n) {
        return String.join("", Collections.nCopies(n, seed));
    }

    public void setTokenIndexes() {
        int idx = 0;
        for (Token t : tokens) {
            idx++;
            t.setIndex(idx);
        }
    }
    
    public String getCompactJsonTxt() {
        StringBuilder sb=new StringBuilder();
        
        for (Token t : tokens) {
            sb.append(t.getText());
        }
        
        return sb.toString();
    }
    
    public List<Token> getTokenList() {
        return tokens;
    }
}

Interpreter类:

package com.heyang;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

class LoopInfo{
    public LoopInfo(String loopValueName,int limit,int startLocation) {
        this.loopValueName=loopValueName;
        this.limit=limit;
        this.startLocation=startLocation;
    }
    
    String loopValueName;
    int limit;
    int startLocation;
}
public class Interpreter {
    private List<Token> tokens;
    private int tokenIdx;
    private Map<String,Integer> varmap;
    private Stack<LoopInfo> loopStack;
    
    public Interpreter(List<Token> tokens) throws Exception{
        this.tokens=tokens;
        this.tokenIdx=0;
        varmap=new HashMap<String,Integer>();
        loopStack=new Stack<LoopInfo>();
        
        execute();
    }
    
    private void execute() throws Exception{
        
        Token token;
        for(;;) {
            token=fetchToken();
            if(token==null) {
                return;
            }
            
            if(token.getType()==Token.TYPE_VARIABLE) {
                String varibleName=token.getText();
                
                token=fetchToken();
                if(token.getType()==Token.TYPE_ASSIGN) {
                    token=fetchToken();
                    
                    if(token.getType()==Token.TYPE_NUMBER) {
                        int variableValue=Integer.parseInt(token.getText());
                        
                        // 赋值核心语句
                        varmap.put(varibleName, variableValue);
                    }
                }else {
                    throw new Exception("Expected:'=' actual:"+token.getText()+" "+token);
                }
            }else if(token.getType()==Token.TYPE_FUNCTION) {
                String functionName=token.getText();
                
                if("print".equalsIgnoreCase(functionName)) {
                    token=fetchToken();
                    if(token.getType()!=Token.TYPE_OPEN_PARENTHESIS) {
                        throw new Exception("Expected:'(' actual:"+token.getText()+" "+token);
                    }
                    
                    token=fetchToken();
                    if(token.getType()==Token.TYPE_STRING) {
                        // 打印字符串
                        String str=token.getText();
                        System.out.println(str);
                    }else if(token.getType()==Token.TYPE_VARIABLE) {
                        String varibleName=token.getText();
                        
                        // 打印变量
                        if(varmap.containsKey(varibleName)) {
                            int value=varmap.get(varibleName);
                            System.out.println(value);
                        }else {
                            System.out.println("Variable:'"+varibleName+"' was not assigned.");
                        }
                    }
                }
            }else if(token.getType()==Token.TYPE_IF) {
                int vLeft,vRight;
                String oprand;
                
                // get left value
                token=fetchToken();                
                if(token.getType()==Token.TYPE_VARIABLE) {
                    String varibleName=token.getText();
                    
                    if(varmap.containsKey(varibleName)) {
                        vLeft=varmap.get(varibleName);
                    }else {
                        throw new Exception("Variable:'"+varibleName+"' was not assigned.");
                    }
                }else if(token.getType()==Token.TYPE_NUMBER) {
                    vLeft=Integer.parseInt(token.getText());
                }else {
                    throw new Exception("Expected:number/variable actual:"+token.getText()+" "+token);
                }
                
                // get ==,<,>
                token=fetchToken();                
                if(token.getType()!=Token.TYPE_EQUAL && token.getType()!=Token.TYPE_LESSTHAN && token.getType()!=Token.TYPE_BIGGERTHAN) {
                    throw new Exception("Expected:'== or > or <' actual:"+token.getText()+" "+token);
                }
                oprand=token.getText();
                
                // get right
                token=fetchToken();                
                if(token.getType()==Token.TYPE_VARIABLE) {
                    String varibleName=token.getText();
                    
                    if(varmap.containsKey(varibleName)) {
                        vRight=varmap.get(varibleName);
                    }else {
                        throw new Exception("Variable:'"+varibleName+"' was not assigned.");
                    }
                }else if(token.getType()==Token.TYPE_NUMBER) {
                    vRight=Integer.parseInt(token.getText());
                }else {
                    throw new Exception("Expected:number/variable actual:"+token.getText()+" "+token);
                }
                
                // Compare
                if(compare(vLeft,oprand,vRight)) {
                    // get then
                    token=fetchToken();                
                    if(token.getType()!=Token.TYPE_THEN) {
                        throw new Exception("Expected:'then' actual:"+token.getText()+" "+token);
                    }
                }else {
                    // 跳过两个token(then及后面的dosth)
                    fetchToken();        
                    fetchToken();        
                }
            }
            else if(token.getType()==Token.TYPE_FOR) {
                token=fetchToken();
                if(token.getType()!=Token.TYPE_VARIABLE) {
                    throw new Exception("Expected:variable actual:"+token.getText()+" "+token);
                }
                String varibleName=token.getText();
                
                token=fetchToken();
                if(token.getType()==Token.TYPE_ASSIGN) {
                    token=fetchToken();
                    
                    if(token.getType()==Token.TYPE_NUMBER) {
                        int variableValue=Integer.parseInt(token.getText());
                        
                        // 赋值核心语句
                        varmap.put(varibleName, variableValue);
                    }
                }else {
                    throw new Exception("Expected:'=' actual:"+token.getText()+" "+token);
                }
                
                token=fetchToken();
                if(token.getType()!=Token.TYPE_TO) {
                    throw new Exception("Expected:to actual:"+token.getText()+" "+token);
                }
                
                token=fetchToken();
                if(token.getType()!=Token.TYPE_NUMBER) {
                    throw new Exception("Expected:number actual:"+token.getText()+" "+token);
                }
                
                int limit=Integer.parseInt(token.getText());
                int variableValue=varmap.get(varibleName);
                
                if(variableValue<=limit) {
                    loopStack.push(new LoopInfo(varibleName,limit,tokenIdx));
                }else {
                    fetchToken();
                }

            }
            else if(token.getType()==Token.TYPE_NEXT) {
                doNext();
            }
        }
    }
            
    private void doNext() {
        LoopInfo info=loopStack.pop();
        int variableValue=varmap.get(info.loopValueName)+1;
        varmap.put(info.loopValueName, variableValue);
        
        if(variableValue>info.limit) {
            //
        }else {
            loopStack.push(info);
            tokenIdx=info.startLocation;
        }
    }
    
    private boolean compare(int vLeft,String oprand,int vRight) throws Exception{
        if("==".equals(oprand)) {
            return vLeft==vRight;
        }else if(">".equals(oprand)) {
            return vLeft>vRight;
        }else if("<".equals(oprand)) {
            return vLeft<vRight;
        }else {
            throw new Exception("oprand should be == or > or < but not.");
        }
    }
    
    private Token fetchToken() {
        if(tokenIdx>=tokens.size()) {
            return null;
        }else {
            Token t=tokens.get(tokenIdx);
            tokenIdx++;
            return t;
        }        
    }
    
    private void returnToken() {
        if(tokenIdx>0) {
            tokenIdx--;
        }
    }
}

入口类:

package com.heyang;

import com.heyang.util.BracketChecker;
import com.heyang.util.CommonUtil;
import com.heyang.util.Renderer;

public class EntryPoint {
    public static void main(String[] args) {
        try {
            // Read context from file
            String text=CommonUtil.readTextFromFile("C:\hy\files\basic\05.basic");
            System.out.println("原文="+text);
            
            // Is brackets balanced
            BracketChecker checker=new BracketChecker();
            boolean isBalanced=checker.isBalanced(text);
            if(isBalanced==false) {
                System.out.println(Renderer.paintBrown(checker.getErrMsg()));
                return;
            }
            
            // lex text to tokens
            Lexer lex=new Lexer(text);
            lex.printTokens();
            
            // Execute
            System.out.println("执行结果:
");
            new Interpreter(lex.getTokenList());
        }catch(Exception ex) {
            System.out.println(Renderer.paintBrown(ex.getMessage()));
            ex.printStackTrace();
        }
    }
}

--2020年5月31日--

原文地址:https://www.cnblogs.com/heyang78/p/13021451.html