🦔
【No.7】変数と代入文の追加
ここでは、変数と代入文を追加します。
BNFの書き換え
まずは、BNFを書き換えますね。
<program> ::= PROGRAM <command list>
<command list> ::= <command>* END | <substitution> END
<substitution> ::= <variable> = <number>
<command> ::= <repeat command> | <primitive command>
<repeat command> ::= REPEAT <number> <command list>
<primitive command> ::= GO | RIGHT | LRFT
変数(variable)は、ENDやGOみたいな予約語ではない文字列とします。
アルファベットから始まり、数字も含められるものとします。
数値しか代入できないものになっています。
変更点
それでは、変更すべき点を列挙します。
・字句解析器・・・トークンのクラスを追加、字句解析のメソッドを変更
・構文解析器・・・代入文を追加
変数名と値を保持する「名前表」(記号表)は、構文解析のクラスに含めました。
実装
変更点の詳細です。
字句解析器
Token.java
package lexer;
public abstract class Token {
public String getContents() {return "なし";}
public int getNumber() {return 0;}
//トークンの種類を判別
public boolean isNumberToken() {return false;}
public boolean isPrimitiveCommandToken(){return false;}
public boolean isRepeatToken() {return false;}
public boolean isEndProgramToken() {return false;}
public boolean isStartProgramToken() {return false;}
public boolean isVariableToken() {return false;}
public boolean isEqualToken(){return false;}
}
VariableToken.java
package lexer;
public class VariableToken extends Token{
private String variableName;
public VariableToken(String code) {
variableName = code;
}
@Override
public boolean isVariableToken() {return true;}
@Override
public String getContents() {return variableName;}
}
EqualToken.java
package lexer;
public class EqualToken extends Token {
@Override
public boolean isEqualToken(){return true;}
}
字句解析のメソッドに追加しました。
Analyzer.java
class Analyzer{
private void categorized() {
for(int i=0;i<tokens.length;i++) {
String token = tokens[i];
/*******************中略***************************/
Pattern equalPattern = Pattern.compile("=");
Matcher equalMach = equalPattern.matcher(token);
if(equalMach.find()) {
EqualToken pc =new EqualToken();
categorizedTokens.add(pc);
continue;
}
Pattern variablePattern = Pattern.compile("[A-Za-z][A-Za-z0-9]*");
Matcher variableMach = variablePattern.matcher(token);
if(variableMach.find()) {
VariableToken pc =new VariableToken(token);
categorizedTokens.add(pc);
continue;
}
}
構文解析器
Parser.java
package parser;
import lexer.Lexer;
import java.util.*;
public class Parser {
//名前表
private Map<String,Integer> nameTable = new HashMap<>();
public AstNode conduct(Lexer lexer) {
AstNode root = new ProgramNode().parse(lexer);
return root;
}
public List<String> doEval(AstNode root){
List<String> list = new ArrayList<>();
root.eval(list,nameTable);
return list;
}
public Map<String,Integer> getNameTable() {
return nameTable;
}
}
CommandList
package parser;
import lexer.Lexer;
import java.util.*;
public class CommandList implements AstNode{
private List<AstNode> children = new ArrayList<>();
@Override
public AstNode parse(Lexer lexer) {
if(lexer.getToken().isVariableToken()) {
AstNode child = new Substitution().parse(lexer);
children.add(child);
}else {
while(! lexer.getToken().isEndProgramToken()) {
AstNode child = new Command().parse(lexer);
children.add(child);
lexer.nextToken();
}
}
return this;
}
@Override
public void eval(List<String> list,Map<String,Integer> nameTable) {
children.forEach(x -> x.eval(list,nameTable));
}
}
Substitution.java
package parser;
import java.util.*;
import lexer.Lexer;
public class Substitution implements AstNode{
private Integer number;
private String variableName;
@Override
public AstNode parse(Lexer lexer) {
variableName = lexer.getToken().getContents();
lexer.nextToken();
lexer.nextToken();
number = lexer.getToken().getNumber();
return this;
}
@Override
public void eval(List<String> list, Map<String,Integer> nameTable) {
nameTable.put(variableName,number);
}
}
課題
構文解析のクラスに、責務が集中してしまっています。
現時点では、以下の3つの責務が集まっています。
・構文解析
・実行
・名前表
ちょっとこれは対応が必要ですね。
Discussion