【问题标题】:antlr4 array implementation : getting values of elementsantlr4 数组实现:获取元素的值
【发布时间】:2018-03-31 10:12:48
【问题描述】:

我正在尝试在 antlr4 中实现数组,但我不知道在初始化时如何获取数组的多个元素:

int array[] = {1, 2};

我正在考虑将它们放在这样的 HashMap 中,关键是索引:

public Map<Integer, Value> array_memory = new HashMap<Integer, Value>();

以下是我所遵循的语法:

grammar GaleugParserNew;

/*
 * PARSER RULES
 */

declare_var 
: INTEGER ID '[' (INT)? ']' (ASSIGN '{' array_init '}')? SCOL 
;

array_init
: INT ',' array_init
| INT 
;


/*
* LEXER RULES
*/

SCOL : ';';

ASSIGN : '=';

INTEGER : 'int';

INT : [0-9]+;

我有一个变量可以计算 declare_var 为索引访问 array_init 的次数。但是我不知道如何访问带有多个元素的array_init。

这是我的 declare_var 访客:

@Override
public Value visitDeclareArray(GaleugParserNewParser.DeclareArrayContext ctx){
    String id = ctx.ID().getText(); //gets array name

    String size = ctx.INT().getText(); //get string version of array size
    int x = Integer.parseInt(size); //convert size(String) to int

    Value elem = this.visit(ctx.array_init());

    return Value.VOID;
}

这是我的 array_init 访问者:

@Override
public Value visitArray_init(GaleugParserNewParser.Array_initContext ctx){
    index += 1;
    return new Value(Double.valueOf(ctx.getText()));
}

如果您对我如何访问 array_init 并参考我想听的变量数量有任何建议。谢谢!

【问题讨论】:

    标签: java antlr4


    【解决方案1】:

    我正在考虑将它们放在这样的 HashMap 中,关键是索引:

    public Map<Integer, Value> array_memory = new HashMap<Integer, Value>();
    

    为什么? List&lt;Value&gt; 也可以,对吧?无需自己跟踪索引。

    递归调用array_init 规则会让你的想法变得更复杂:

    array_init
     : INT ',' array_init
     | INT 
     ;
    

    我会这样做:

    array_init
     : INT ( ',' INT )*
     ;
    

    然后你可以这样做:

    import org.antlr.v4.runtime.*;
    import org.antlr.v4.runtime.tree.TerminalNode;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Main {
    
      public static void main(String[] args) {
    
        String source = "int array[] = {1, 2};";
    
        GaleugParserNewLexer lexer = new GaleugParserNewLexer(CharStreams.fromString(source));
        GaleugParserNewParser parser = new GaleugParserNewParser(new CommonTokenStream(lexer));
    
        Value value = new EvalVisitor().visit(parser.declare_var());
    
        System.out.println(value);
      }
    }
    
    class Value {
    
      final Object value;
    
      public Value(Object value) {
        this.value = value;
      }
    
      @Override
      public String toString() {
        return String.valueOf(this.value);
      }
    }
    
    class EvalVisitor extends GaleugParserNewBaseVisitor<Value> {
    
      @Override
      public Value visitDeclare_var(GaleugParserNewParser.Declare_varContext ctx) {
        List<Value> numbers = new ArrayList<>();
        if (ctx.array_init() != null) {
          for (TerminalNode tokenNode : ctx.array_init().INT()) {
            numbers.add(new Value(Integer.valueOf(tokenNode.getText())));
          }
        }
        return new Value(numbers);
      }
    }
    

    如果你运行这个Main 类,以下内容将打印到你的控制台:

    [1, 2]
    

    编辑

    但是,如果我不是专门寻找 INT,而是想在包含我的语言中所有数据类型的语法中寻找任何标记,该怎么办?我应该使用什么来代替 TerminalNode?​​p>

    像 1-2-3 一样简单,这样定义你的语法:

    array_init
     : expr ( ',' expr )*
     ;
    
    expr
     : '(' expr ')'          #nestedExpr
     | lhs=expr '+' rhs=expr #addExpr
     | INT                   #intExpr
     | ID                    #idExpr
     ;
    

    然后做这样的事情:

    import org.antlr.v4.runtime.*;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class Main {
    
      public static void main(String[] args) {
    
        String source = "int array[] = { 123456789, (1 + 2), Q };";
    
        GaleugParserNewLexer lexer = new GaleugParserNewLexer(CharStreams.fromString(source));
        GaleugParserNewParser parser = new GaleugParserNewParser(new CommonTokenStream(lexer));
    
        Map<String, Value> memory = new HashMap<String, Value>(){{
          put("Q", new Value(42));
        }};
    
        Value value = new EvalVisitor(memory).visit(parser.declare_var());
    
        System.out.println(value);
      }
    }
    
    class Value {
    
      final Object value;
    
      public Value(Object value) {
        this.value = value;
      }
    
      int asInt() {
        return (Integer) value;
      }
    
      @Override
      public String toString() {
        return String.valueOf(this.value);
      }
    }
    
    class EvalVisitor extends GaleugParserNewBaseVisitor<Value> {
    
      final Map<String, Value> memory;
    
      EvalVisitor(Map<String, Value> memory) {
        this.memory = memory;
      }
    
      @Override
      public Value visitDeclare_var(GaleugParserNewParser.Declare_varContext ctx) {
        List<Value> numbers = new ArrayList<>();
        if (ctx.array_init() != null) {
          for (GaleugParserNewParser.ExprContext expr : ctx.array_init().expr()) {
            numbers.add(super.visit(expr));
          }
        }
        return new Value(numbers);
      }
    
      @Override
      public Value visitIntExpr(GaleugParserNewParser.IntExprContext ctx) {
        return new Value(Integer.valueOf(ctx.getText()));
      }
    
      @Override
      public Value visitAddExpr(GaleugParserNewParser.AddExprContext ctx) {
        return new Value(super.visit(ctx.lhs).asInt() + super.visit(ctx.rhs).asInt());
      }
    
      @Override
      public Value visitNestedExpr(GaleugParserNewParser.NestedExprContext ctx) {
        return super.visit(ctx.expr());
      }
    
      @Override
      public Value visitIdExpr(GaleugParserNewParser.IdExprContext ctx) {
        return this.memory.get(ctx.getText());
      }
    }
    

    将打印:

    [123456789, 3, 42]
    

    【讨论】:

    • 但是,如果我不是专门寻找 INT,而是想在包含我的语言中所有数据类型的语法中查找任何标记,该怎么办?我应该用什么来代替 TerminalNode?​​span>
    • @blah 检查我的编辑
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-31
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多