您的位置:首页 > 编程语言 > Java开发

(基于Java)编写编译器和解释器-第5A章:基于Antlr解析表达式和赋值语句及计算(连载)

2012-07-22 19:25 621 查看
本章在第3A章源代码基础上继续完善基于Antlr自动化的解析器,解释执行第5章解析的复合语句,赋值语句和表达式等相关中间码。并仿照第5章的简化标准,将一些东西简化掉,尽量能让你从最简处入手,掌握Antlr自动化构建解析器的第一步。

==>> 本章中文版源代码下载:svn co http://wci.googlecode.com/svn/branches/ch5_antlr/ 源代码使用了UTF-8编码,下载到本地请修改!

好的工具事半功倍,Antlr亦如此。antlr.org上有一个很有特色的工具antlrwors。如果使用Eclipse,可以安装插件antlrv3ide。两个工具的主要特色是可视化的创建EBNF语法,就如同你在前面章节看到的语法图一样。对于我来说,比较习惯antlrworks,它有良好的调试功能和DFA分析功能。

1 带AST构造的语法

program:
compound_statement DOT!;
compound_statement:
BEGIN statement_list END ->^(COMPOUND statement_list);
assignment_statement:
ID ASSIGN expression -> ^(ASSIGN ID expression);
statement:
compound_statement | assignment_statement;
statement_list:
statement (SEMI statement)* SEMI? -> statement+;
expression:
simple_expression (rel_ops^ simple_expression)?;
rel_ops:
LT | LE | GT | GE | NOT_EQUAL;
simple_expression:
signedterm (add_ops^ term)*;
signedterm:
(a=PLUS | a=MINUS)? term ->{a!=null&&a.getType()==MINUS}?^(NEGATE term)->term;
add_ops:
PLUS | MINUS | OR;
term:
factor (mul_ops^ factor)*;
mul_ops:
STAR | SLASH | DIV | MOD | AND;
factor:
ID | NUMBER | STRING | NOT^ factor | LPAREN! expression RPAREN!;

目前的程序program由一个复合语句+结束的点"."组成。这个antlr语句基本与第五章的语法图5-1 和图5-2 类似。

2 计算Token值

填充第三章中关于计算常量token的值类ValueComputer,目前只对整数,字符串,浮点数token算值,算值逻辑与PascalStringToken和PascalNumberToken基本类似。

详细参见代码ValueComputer,这里不再显示。

3 引入符号表

这里复用第5章的符号表。需要使用符号表的地方有两个,一个是赋值语句的左边变量作为定义出现,另外一个是表达式中的标识符作为引用出现。在Antlr分析中,一般符号表必须要在语法树构建完成后才能进行,因为语法树构建过程中的节点是不清晰的。在Antlr中构建完AST之后,将使用Antlr树语法(Tree Grammar)去遍历语法,这个过程中我们可以加入符号表操作,也可以执行动作和生成代码。

4 执行赋值语句及计算语句

我原本想只想演示一下相关分析树,但是发现过于简单,于是就干脆执行算了,执行第5章的分析树是第6章内容,所有没有6A章了。

详细语法如下表:

tree grammar PascalVisitor;
options{
tokenVocab=Pascal;
ASTLabelType=PascalNode;
}
@header{
package com.lifesting.book.wci;
import wci.intermediate.*;
import wci.intermediate.symtabimpl.SymTabKeyImpl;
}
@members{
protected SymTabStack symtabStack = SymTabFactory.createSymTabStack();
public SymTabStack getSymbolTableStack(){
  return this.symtabStack;
}
}
 program : 
compound;
compound :
^(COMPOUND stmt+);
stmt:
compound | assign;
assign:
^(ASSIGN i=ID e=expr){
  String var = $i.text.toLowerCase();
  SymTabEntry id_entry = symtabStack.lookup(var) ;
  if (id_entry == null)
  {
 id_entry = symtabStack.enterLocal(var);
}
  id_entry.setAttribute(SymTabKeyImpl.DATA_VALUE,e);
};
expr returns[Object value]:
s=simple{value=s;} 
| ^(r=rel_ops e1=expr e2=expr){
  if (e1 instanceof Number && e2 instanceof Number){
 double de1 = ((Number)e1).doubleValue();
 double de2 = ((Number)e2).doubleValue();
 switch (r){
case 1:
  value = de1 < de2;
  break;
case 2:
  value = de1 <= de2;
  break;
case 3:
  value = de1 > de2;
  break;
case 4:
  value = de1 >= de2;
  break;
case 5:
  value = de1 != de2;
  break;
default:
  break;
}
}else{
 System.err.println("无法执行比较:"+e1+"["+r+"]"+e2);
}
};
simple returns[Object value]:
s=term{value=s;} 
| ^(o=add_ops f1=negterm f2=simple) 
{
  double df1 = Double.parseDouble(f1.toString());
  if (f2 instanceof Number){
 double df2 = Double.parseDouble(f2.toString());
 switch (o)
 {
case 1:
  value = df1+df2;
  break;
case 2:
  value = df1-df2;
  break;
}
}else{
 System.err.println("不是一个数值:"+f2);
}
}
| ^(o=add_ops f1=simple f2=simple){
if (f1 instanceof Number && f2 instanceof Number){
double df1 = Double.parseDouble(f1.toString());
double df2 = Double.parseDouble(f2.toString());
switch (o){
  case 1:
 value = df1+df2;
 break;
  case 2:
 value = df1-df2;
 break;
  default:
 break;
}
}else if (f1 instanceof Boolean && f2 instanceof Boolean){
  value= ((Boolean)f1).booleanValue() || ((Boolean)f2).booleanValue();
}else{
  System.err.println("不能执行simple运算,f1="+f1+",f2="+f2);
}
};
negterm returns[Object value]:
^(NEGATE n=term) {
  if(n instanceof Number){
 return -Double.parseDouble(n.toString());
}else{
 System.err.println("不是一个数值:"+n);
 value = 0.0;
}
};
term returns[Object value]:
f0=factor{value=f0;} 
| ^(t=mul_ops f1=factor f2=factor){
  if (f1 instanceof Number && f2 instanceof Number){
 double df1 = Double.parseDouble(f1.toString());
 double df2 = Double.parseDouble(f2.toString());
 switch (t){
case 1:
  value= df1*df2;
  break;
case 2:
case 3:
  value= df1/df2;
case 4:
  value=df1 \% df2;
default:
  break;
}
}else if (f1 instanceof Boolean && f2 instanceof Boolean){
 value= ((Boolean)f1).booleanValue() && ((Boolean)f2).booleanValue();
}else{
 System.err.println("不能执行term运算,f1="+f1+",f2="+f2);
}
};
factor returns[Object value]:
i = ID{
  String var = $i.text.toLowerCase();
  SymTabEntry id_entry = symtabStack.lookup(var);
  if (id_entry == null){
 System.err.println("使用不存在的变量:"+var);
}else{
 value = id_entry.getAttribute(SymTabKeyImpl.DATA_VALUE);
}
} 
| n=NUMBER{value =((PascalAntlrToken)$n.getToken()).getValue();} 
| r=NUMBER_REAL{value = ((PascalAntlrToken)$r.getToken()).getValue();}
| s=STRING {value =((PascalAntlrToken)$s.getToken()).getValue();}
| ^(NOT f=factor) { 
 if (f instanceof Boolean){
value = !((Boolean)f).booleanValue();
}else{
System.err.println("不是一个布尔值:"+f);
}
}
| ^(NESTEXPR e = expr){
 value = e;
}; 
rel_ops returns [int type]:
LT{type =1;} | LE{type = 2;} | GT{type=3;} | GE{type=4;} | NOT_EQUAL{type=5;};
add_ops returns [int type]:
PLUS{type=1;} | MINUS{type=2;} | OR{type=3;}; 
mul_ops returns [int type]:
STAR{type = 1;} | SLASH{type=2;} | DIV{type=3;} | MOD{type=4;} | AND{type=5;};

测试程序:

public final class SimpleInterpreter {
  public static void main(String[] args) throws IOException, RecognitionException {
//第5章示例Pascal
InputStreamReader stream = new InputStreamReader(ShowToken.class.getResourceAsStream("/assignments.txt"));
ANTLRReaderStream reader = new ANTLRReaderStream(stream);
//词法分析器
PascalLexer lexer = new PascalLexer(reader);
CommonTokenStream token_stream = new CommonTokenStream(lexer);
//语法分析器并带自己的TreeAdaptor,转换成自己的PascalNode
PascalParser parser = new PascalParser(token_stream);
parser.setTreeAdaptor(new PascalNodeAdaptor());
program_return prog = parser.program();
//遍历树并运算
TreeNodeStream node_stream  = new CommonTreeNodeStream(prog.getTree());
PascalVisitor interpreter = new PascalVisitor(node_stream);
interpreter.program();
SymTabStack stack = interpreter.getSymbolTableStack();
SymTabEntry five_entry = stack.lookup("five");
System.out.println("Five = "+five_entry.getAttribute(SymTabKeyImpl.DATA_VALUE));
SymTabEntry str_entry = stack.lookup("str");
System.out.println("str = "+str_entry.getAttribute(SymTabKeyImpl.DATA_VALUE));
SymTabEntry  fahrenheit_entry = stack.lookup("fahrenheit");
System.out.println("fahrenheit = "+fahrenheit_entry.getAttribute(SymTabKeyImpl.DATA_VALUE));
SymTabEntry centigrade_entry = stack.lookup("centigrade");
System.out.println("centigrade = "+centigrade_entry.getAttribute(SymTabKeyImpl.DATA_VALUE));
}
}

最后的输出结果:

Five = 5.0
str = 'hello, world'
fahrenheit = 32.0
centigrade = 25
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐