Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的ANTLR基本示例_Java_Compiler Construction_Antlr - Fatal编程技术网

Java中的ANTLR基本示例

Java中的ANTLR基本示例,java,compiler-construction,antlr,Java,Compiler Construction,Antlr,在过去的几个小时里,我一直在网上搜索,试图学习一个使用ANTLR的简单示例。但是我很难理解这些示例。是否有任何主体有简单的示例可以用Java输出: 如果我的输入是 printf(“你好世界”) 输出应为: 你好,世界 如果我的输入是 inx=1 它应该给出一个错误消息 我试图用java创建C++编译器(从词汇开始直到语义部分),我很想知道我应该做什么。 grammar Expr; @header { package test; import java.util.HashMap; } @lex

在过去的几个小时里,我一直在网上搜索,试图学习一个使用ANTLR的简单示例。但是我很难理解这些示例。是否有任何主体有简单的示例可以用Java输出:

如果我的输入是
printf(“你好世界”)

输出应为:

你好,世界

如果我的输入是

inx=1

它应该给出一个错误消息

<>我试图用java创建C++编译器(从词汇开始直到语义部分),我很想知道我应该做什么。
grammar Expr;

@header {
package test;
import java.util.HashMap;
}

@lexer::header {package test;}

@members {
/** Map variable name to Integer object holding value */
HashMap memory = new HashMap();
}

prog:   stat+ ;

stat:   expr NEWLINE {System.out.println($expr.value);}
    |   ID '=' expr NEWLINE
        {memory.put($ID.text, new Integer($expr.value));}
    |   NEWLINE
    ;

expr returns [int value]
    :   e=multExpr {$value = $e.value;}
        (   '+' e=multExpr {$value += $e.value;}
        |   '-' e=multExpr {$value -= $e.value;}
        )*
    ;

multExpr returns [int value]
    :   e=atom {$value = $e.value;} ('*' e=atom {$value *= $e.value;})*
    ; 

atom returns [int value]
    :   INT {$value = Integer.parseInt($INT.text);}
    |   ID
        {
        Integer v = (Integer)memory.get($ID.text);
        if ( v!=null ) $value = v.intValue();
        else System.err.println("undefined variable "+$ID.text);
        }
    |   '(' e=expr ')' {$value = $e.value;}
    ;

    ID  :   ('a'..'z'|'A'..'Z')+ ;
    INT :   '0'..'9'+ ;
    NEWLINE:'\r'? '\n' ;
    WS  :   (' '|'\t')+ {skip();} ;
但是正如我在我的评论中提到的,C++很难正确解析。有很多不明确之处,需要一定的前瞻性(ANTLR确实提供了这一点)。因此,以任何有效的形式进行这项工作都是复杂的。这就是为什么我建议实现类似的东西,它是为学生编写第一个编译器而设计的。这也是一个良好的开端。这两种方法都可以实现,而无需使用ANTLR之类的工具。我在1000行中实现了这两种方法(分别在C++和C语言中)。 不过,ANTLR是一个很棒的工具,尤其是当您开始关注递归下降时,您可能希望升级到一个更强大的解析器。我推荐特伦斯·帕尔的两本书,还有。ANTLR的书会告诉你关于ANTLR的一切(还有一些)你想知道的。第二本书将教你所有关于解析器和编译器的知识,从递归下降到黑魔法回溯


可以找到类似问题的更多资源。如果您喜欢Lisp或Scheme,您可以查看,它是用Java编写的(我相信不到1000行)。

这里有一个语法,它几乎可以满足您的需要:

grammar PrintLang;

sentence 
    :    statement
    ;

statement 
    :   functionCall '(' argument ')' ';'
    { 
      if ($functionCall.funName.equals("printf")) {
        System.out.println($argument.arg);
      }
    }
    ;

functionCall returns [String funName]
    :    ID 
    { $funName = $ID.text; }
    ;

argument returns [String arg]
    :   STRING
    { $arg = $STRING.text; }
    ;

ID  :   ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;

STRING
    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
    ;

fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;

fragment
OCTAL_ESC
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;

fragment
UNICODE_ESC
    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ;
我在AntlWorks中生成了这个。所有的令牌规则都是为我生成的

下面是测试它的java文件

import org.antlr.runtime.*;


public class PrintIt {
  public static void main(String args[]) {
    String inputString = "printf(\"HelloWorld\");";

    // Create an input character stream from standard in
    ANTLRStringStream input = new ANTLRStringStream(inputString); 
    // Create an ExprLexer that feeds from that stream 
    PrintLangLexer lexer = new PrintLangLexer(input);
    // Create a stream of tokens fed by the lexer 
    CommonTokenStream tokens = new CommonTokenStream(lexer); 
    // Create a parser that feeds off the token stream 
    PrintLangParser plParser = new PrintLangParser(tokens);
    try {
        plParser.sentence();
    } catch (Exception e) {
        e.printStackTrace();
    }
  }
}
您会注意到,这段java代码几乎是Antlr网站示例的逐字复制/粘贴(我甚至不相信我更改了注释,这就是注释在中引用标准的原因,但代码实际上使用了字符串)。这是我用来做这件事的命令行

bash$ java -cp ./antlr-3.4-complete.jar org.antlr.Tool PrintLang.g
bash$ javac -cp ./:./antlr-3.4-complete.jar PrintIt.java 
bash$ java -cp antlr-3.4-complete.jar:. PrintIt
"HelloWorld"
哎呀,我忘了我要打印的字符串不是匹配的标记(“HelloWorld”,包括引号),而是引号中的字符串

另外,您会注意到我将printf的查找硬编码为字符串比较。实际上,您需要一个包含在给定范围内可访问的符号的环境(相关的,请参阅antlr的“范围”构造。更困难的,尽管有时有用:创建一个传递给每个解析规则的环境)


最重要的是:通过搜索更多的antlr问题来找到巴特·基尔斯的答案。他举了很好的例子。

你输入的语法是什么?你的输入都是一个标记吗??如果是这样,那很容易!如果你想把它像C一样解析,那么它离“简单”很远。对于记录来说,C++是很难正确解析的。它是上下文敏感的。你提到你的输出。。。那么你是在写解释器,而不是编译器?@Austinenley是这样吗?那么你能推荐一种替代编程语言,让我的语法更简单吗?Python是一种好的编程语言吗?@Austinenley我实际上计划创建一个解释器,如果我的输入通过了所有的分析部分,我将把它移植到一个现成的输出生成器,如C:%gcc-C中所示