源码下载: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日--