自编Basic脚本 用BasicIntepreter执行 打印九九乘法表

时间:2021-09-10 10:20:06

源码下载:https://files.cnblogs.com/files/heyang78/BasicInterpreter2-20200601-2.rar

用编程语言打印九九乘法表不难,用自编解释器运行自编脚本打印九九乘法表难度就多了那么一丢丢。本例就是讲述我编的这个程序:

输入脚本:

for x= to
for y= to x
z=x*y
print(x)
print("*")
print(y)
print("=")
print(z)
print(" ")
next newline()
next print("end")

输出:

原文=for x= to     for y= to x        z=x*y        print(x)        print("*")        print(y)        print("=")        print(z)        print(" ")    next       newline() next  print("end")
Tokens:
Index Type No Text Type Desc
------------------------------------------------------------------------------------
for for
x Variable
= =
DIGITAL
to to
DIGITAL
for for
y Variable
= =
DIGITAL
to to
x Variable
z Variable
= =
x Variable
* *
y Variable
print Function
( (
x Variable
) )
print Function
( (
"*" String
) )
print Function
( (
y Variable
) )
print Function
( (
"=" String
) )
print Function
( (
z Variable
) )
print Function
( (
" " String
) )
next next
newline Function
( (
) )
next next
print Function
( (
"end" String
) ) 执行结果: 1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81

end

脚本稍微改改:

for x=1 to 9
for y=1 to x
z=x*y
print(y)
print("*")
print(x)
print("=")
print(z)
print(" ")
next newline()
next print("end")

输出:

原文=for x=1 to 9    for y=1 to x        z=x*y        print(y)        print("*")        print(x)        print("=")        print(z)        print(" ")    next       newline() next  print("end")
Tokens:
执行结果: 1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81

end

核心类:

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_DIGITAL=4; // \d+[.]?\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
public static final int TYPE_LESSEUQALTHAN=15; // <=
public static final int TYPE_BIGGEREQUALTHAN=16; // >=
public static final int TYPE_PLUS=17; // +
public static final int TYPE_MINUS=18; // -
public static final int TYPE_MULTI=19; // *
public static final int TYPE_DIVIDE=20; // /
public static final int TYPE_ENDIF=21; // endif
public static final int TYPE_ELSE=22; // else 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_DIGITAL) {
return "DIGITAL";
}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";
}else if(type==TYPE_LESSEUQALTHAN) {
return "<=";
}else if(type==TYPE_BIGGEREQUALTHAN) {
return ">=";
}else if(type==TYPE_PLUS) {
return "+";
}else if(type==TYPE_MINUS) {
return "-";
}else if(type==TYPE_MULTI) {
return "*";
}else if(type==TYPE_DIVIDE) {
return "/";
}else if(type==TYPE_ENDIF) {
return "endif";
}else if(type==TYPE_ELSE) {
return "else";
} 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 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_PLUS));
} else if (c == '-') {
addTextToList(swallowed);
swallowed=""; tokens.add(new Token(c, Token.TYPE_MINUS));
}else if (c == '*') {
addTextToList(swallowed);
swallowed=""; tokens.add(new Token(c, Token.TYPE_MULTI));
}else if (c == '/') {
addTextToList(swallowed);
swallowed=""; tokens.add(new Token(c, Token.TYPE_DIVIDE));
}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 == '>') {
int next=i+1;
if(next<text.length() && text.charAt(next)=='=') {
// >=
addTextToList(swallowed);
swallowed="";
tokens.add(new Token(">=",Token.TYPE_BIGGEREQUALTHAN));
i++;
}else {
addTextToList(swallowed);
swallowed="";
tokens.add(new Token(c, Token.TYPE_BIGGERTHAN));
}
}else if (c == '<') {
int next=i+1; if(next<text.length() && text.charAt(next)=='=') {
// <=
addTextToList(swallowed);
swallowed="";
tokens.add(new Token("<=",Token.TYPE_LESSEUQALTHAN));
}else {
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("endif".equalsIgnoreCase(text)) {
tokens.add(new Token(text, Token.TYPE_ENDIF));
}else if("else".equalsIgnoreCase(text)) {
tokens.add(new Token(text, Token.TYPE_ELSE));
}else if(isFunction(text)) {
tokens.add(new Token(text, Token.TYPE_FUNCTION));
}else if(isNumber(text)) {
tokens.add(new Token(text, Token.TYPE_DIGITAL));
}else if(isVarable(text)) {
tokens.add(new Token(text, Token.TYPE_VARIABLE));
}
} private boolean isFunction(String text) {
if("print".equalsIgnoreCase(text)) {
return true;
}else if("newline".equalsIgnoreCase(text)){
return true;
} return false;
} private boolean isNumber(String code) {
final String patternStr = "(\\d+)([.]?)(\\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","\n"));
sb.append(continuousStar + "\n");
int index=0;
for(Token token:tokens) {
sb.append(String.format(layout, String.valueOf(index),String.valueOf(token.getType()), token.getText(),token.getTypeStr(),"\n"));
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 getCompactText() {
StringBuilder sb=new StringBuilder(); for (Token t : tokens) {
sb.append(t.getText());
} return sb.toString();
} public List<Token> getTokens() {
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,double limit,int startLocation) {
this.loopValueName=loopValueName;
this.limit=limit;
this.startLocation=startLocation;
} String loopValueName;
double limit;
int startLocation;
} public class InterPreter {
private List<Token> tokens;
private int tokenIdx;
private Map<String,Double> varMap;// 用于存放变量的变量表
private Stack<LoopInfo> loopStack;// 用于存放循环的栈 public InterPreter(List<Token> tokens){
this.tokens=tokens;
this.tokenIdx=0;
varMap=new HashMap<String,Double>();
loopStack=new Stack<LoopInfo>();
} // 执行程序
public void execute() throws Exception{
Token token;
for(;;) {
token=fetchToken();
if(token==null) {
return;
} if(token.getType()==Token.TYPE_VARIABLE) {
returnToken();
doAssignment();
}else if(token.getType()==Token.TYPE_FUNCTION) {
String fname=token.getText(); if("print".equalsIgnoreCase(fname)) {
doPrint();
}if("newline".equalsIgnoreCase(fname)) {
doNewline();
}
}else if(token.getType()==Token.TYPE_IF) {
returnToken();
doIf();
}else if(token.getType()==Token.TYPE_ELSE) {
doElse();
}else if(token.getType()==Token.TYPE_FOR) {
doFor();
}else if(token.getType()==Token.TYPE_NEXT) {
doNext();
}
}
} private void doNext() throws Exception{
LoopInfo info=loopStack.pop();
String varName=info.loopValueName;
Double value=loadVariable(varName);
if(value==null) {
throw new Exception("Not found variable:'"+varName);
} double variableValue=value+1;
saveVariable(info.loopValueName, variableValue); if(variableValue>info.limit) {
//
}else {
loopStack.push(info);
tokenIdx=info.startLocation;
}
} private void doFor() throws Exception{
Token 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_DIGITAL) {
double value=Double.parseDouble(token.getText());
saveVariable(varibleName, value);
}
}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);
} double limit;
token=fetchToken();
if(token.getType()==Token.TYPE_DIGITAL) {
limit=Double.parseDouble(token.getText());
}else if(token.getType()==Token.TYPE_VARIABLE) {
String varName=token.getText();
Double value=loadVariable(varName);
if(value==null) {
throw new Exception("Not found variable:'"+varName+" token:"+token);
} limit=value;
}else {
throw new Exception("Expected:digital/variable actual:"+token.getText()+" "+token);
} double variableValue=loadVariable(varibleName); if(variableValue<=limit) {
loopStack.push(new LoopInfo(varibleName,limit,tokenIdx));
}else {
fetchToken();
}
} private void doElse() throws Exception{
// 走到这里说明是if的肯定分支,因此需要跳过去
Token token;
do {
token=fetchToken();
}while(token.getType()!=Token.TYPE_ENDIF) ;
} private void doIf() throws Exception{
Token token=fetchToken();
if(token.getType()!=Token.TYPE_IF) {
throw new Exception("Expected:if actual:"+token.getText()+" "+token);
} double left;
token=fetchToken();
if(token.getType()==Token.TYPE_DIGITAL) {
left=Double.parseDouble(token.getText());
}else if(token.getType()==Token.TYPE_VARIABLE) {
String varName=token.getText();
Double value=loadVariable(varName);
if(value==null) {
throw new Exception("Not found variable:'"+varName+" token:"+token);
} left=value;
}else {
throw new Exception("Expected:digital/variable actual:"+token.getText()+" "+token);
} String oprand;
token=fetchToken();
if(token.getType()!=Token.TYPE_EQUAL &&
token.getType()!=Token.TYPE_LESSTHAN &&
token.getType()!=Token.TYPE_LESSEUQALTHAN &&
token.getType()!=Token.TYPE_BIGGERTHAN &&
token.getType()!=Token.TYPE_BIGGEREQUALTHAN
) {
throw new Exception("Expected:comparison symbol, actual:"+token.getText()+" "+token);
}
oprand=token.getText(); double right;
token=fetchToken();
if(token.getType()==Token.TYPE_DIGITAL) {
right=Double.parseDouble(token.getText());
}else if(token.getType()==Token.TYPE_VARIABLE) {
String varName=token.getText();
Double value=loadVariable(varName);
if(value==null) {
throw new Exception("Not found variable:'"+varName+" token:"+token);
} right=value;
}else {
throw new Exception("Expected:digital/variable actual:"+token.getText()+" "+token);
} if(compare(left,oprand,right)) {
token=fetchToken();
if(token.getType()!=Token.TYPE_THEN) {
throw new Exception("Expected:'then' actual:"+token.getText()+" "+token);
}
}else {
do {
token=fetchToken();
}while(token.getType()!=Token.TYPE_ENDIF && token.getType()!=Token.TYPE_ELSE) ;
}
} private boolean compare(double vLeft,String oprand,double vRight){
if("==".equals(oprand)) {
return vLeft==vRight;
}else if(">".equals(oprand)) {
return vLeft>vRight;
}else if(">=".equals(oprand)) {
return vLeft>=vRight;
}else if("<".equals(oprand)) {
return vLeft<vRight;
}else if("<=".equals(oprand)) {
return vLeft<=vRight;
}else {
return false;
}
} private void doNewline() throws Exception{
Token token=fetchToken();
if(token.getType()!=Token.TYPE_OPEN_PARENTHESIS) {
throw new Exception("Expected:'(' actual:"+token.getText()+" "+token);
} System.out.println(); token=fetchToken();
if(token.getType()!=Token.TYPE_CLOSE_PARENTHESIS) {
throw new Exception("Expected:')' actual:"+token.getText()+" "+token);
}
} private void doPrint() throws Exception{
Token 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(); for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i); if(c!='"'){
System.out.print(c);
}
}
}else if(token.getType()==Token.TYPE_VARIABLE) {
String varName=token.getText();
Double value=loadVariable(varName);
if(value==null) {
throw new Exception("Not found variable:'"+varName+" token:"+token);
} try {
int i=value.intValue();
System.out.print(i);
}catch(Exception ex) {
System.out.print(value);
} } token=fetchToken();
if(token.getType()!=Token.TYPE_CLOSE_PARENTHESIS) {
throw new Exception("Expected:')' actual:"+token.getText()+" "+token);
}
} // 赋值
private void doAssignment() throws Exception{
Token token=fetchToken();
if(token.getType()!=Token.TYPE_VARIABLE) {
throw new Exception("Expected:variable actual:"+token.getText()+" "+token);
}
String varName=token.getText(); token=fetchToken();
if(token.getType()!=Token.TYPE_ASSIGN) {
throw new Exception("Expected:= actual:"+token.getText()+" "+token);
} double varValue=parse_expression();
saveVariable(varName,varValue);
} // 解析表达式
private double parse_expression() throws Exception{
double left,right;
Token currentToken; left=parse_term();
for(;;) {
currentToken=fetchToken();
if(currentToken==null) {
return left;
} if(currentToken.getType()!=Token.TYPE_PLUS && currentToken.getType()!=Token.TYPE_MINUS) {
returnToken();
break;
} right=parse_term(); if(currentToken.getType()==Token.TYPE_PLUS) {
left+= right;
}else if(currentToken.getType()==Token.TYPE_MINUS) {
left-= right;
}else {
returnToken();
}
} return left;
} // 解析乘除
private double parse_term() throws Exception{
double left,right;
Token currentToken; left=parse_primary_exp();
for(;;) {
currentToken=fetchToken();
if(currentToken==null) {
return left;
} if(currentToken.getType()!=Token.TYPE_MULTI && currentToken.getType()!=Token.TYPE_DIVIDE) {
returnToken();
break;
} right=parse_primary_exp(); if(currentToken.getType()==Token.TYPE_MULTI) {
left*= right;
}else if(currentToken.getType()==Token.TYPE_DIVIDE) {
left/= right;
}
} return left;
} // 解析数字/变量/表达式
private double parse_primary_exp() throws Exception{
Token token;
double retval=0.0; token=fetchToken();
if(token==null) {
return 0;
} if(token.getType()==Token.TYPE_DIGITAL) {
retval= Double.parseDouble(token.getText());
return retval;
}else if(token.getType()==Token.TYPE_VARIABLE) {
String varName=token.getText();
Double d=loadVariable(varName);
if(d==null) {
throw new Exception("Not found variable:'"+varName+" token:"+token);
} return d;
}else if(token.getType()==Token.TYPE_OPEN_PARENTHESIS){
retval=parse_expression(); token=fetchToken();
if(token==null) {
return retval;
} if(token.getType()!=Token.TYPE_CLOSE_PARENTHESIS) {
throw new Exception("missing )");
} return retval;
}else {
throw new Exception(token+" should be a digital.");
}
} // 取标记
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--;
}
} // 保存变量进变量表
private void saveVariable(String name,double value) {
varMap.put(name, value);
} // 取得变量值从变量表
private Double loadVariable(String name) {
if(varMap.containsKey(name)) {
return varMap.get(name);
}else {
return null;
}
}
}

EnterPoint:

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\\12.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);
System.out.println("Tokens:");
lex.printTokens(); // Execute
System.out.println("执行结果:\n");
InterPreter ip=new InterPreter(lex.getTokens());
ip.execute();
}catch(Exception ex) {
System.out.println(Renderer.paintBrown(ex.getMessage()));
ex.printStackTrace();
}
}
}

今天是六一儿童节,我也因为此程序的研制成功感受到了儿童那纯洁天真的快乐。

--2020年6月1日--