栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如何在语法上实现JJTree

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何在语法上实现JJTree

使用JavaCC创建AST看起来很像创建“常规”解析器(在

jj
文件中定义)。如果您已有语法,那么(相对)容易:)

以下是创建AST所需的步骤:

  1. 将您的
    jj
    语法文件重命名为
    jjt
  2. __用 根标签 修饰 它(斜体字是我自己的术语…)
  3. 调用
    jjtree
    您的
    jjt
    语法,它将
    jj
    为您生成一个文件
  4. 调用
    javacc
    您生成的
    jj
    语法
  5. 编译生成的
    java
    源文件
  6. 测试一下

这是一个快速的分步教程,假定您使用的是MacOS或*
nix,并将

javacc.jar
文件与语法文件放在同一目录中,
java
并且
javac
位于系统的PATH上:

1个

假设您的

jj
语法文件名为
TestParser.jj
,将其重命名:

mv TestParser.jj TestParser.jjt

2

现在最棘手的部分是: 装饰 语法,以便创建正确的AST结构。您可以通过在AST(或节点或生产规则(全部相同))之后添加,后跟一个标识符来 修饰
AST(或节点或生产规则)。在最初的问题中,您有很多不同的产品,这意味着您要针对不同的生产规则创建相同类型的AST:这不是您想要的。

#``:``#void

如果您不 装饰 产品,则将产品名称用作节点的类型(因此,您可以删除

#void
):

void decl() :{}{     var_decl()  |  const_decl()}

现在,该规则仅返回该AST

var_decl()
或返回的任何AST
const_decl()

现在让我们看一下(简化的)

var_decl
规则:

void var_decl() #VAR :{}{  <VAR> id() <COL> id() <EQ> expr() <SCOL>}void id() #ID :{}{  <ID>}void expr() #EXPR :{}{  <ID>}

我用这种

#VAR
类型装饰。现在这意味着该规则将返回以下树结构:

    VAR    / |   /  |  ID  ID  EXPR

如您所见,终端从AST中被丢弃了!这也意味着

id
expr
规则会松开其
<ID>
终端匹配的文本。当然,这不是您想要的。对于需要使终端的内部文本保持匹配的规则,您需要
.value
将树的显式设置
.image
为匹配的终端的:

void id() #ID :{Token t;}{  t=<ID> {jjtThis.value = t.image;}}void expr() #EXPR :{Token t;}{  t=<ID> {jjtThis.value = t.image;}}

使输入

"var x : int = i;"
看起来像这样:

       VAR         |    .---+------.   /    |         /     |        ID["x"] ID["int"] EXPR["i"]

这就是您为AST创建合适的结构的方式。下面是一个小的语法,它是您自己的语法的非常简单的版本,其中包括一个

main
测试所有语法的小方法:

// TestParser.jjtPARSER_BEGIN(TestParser)public class TestParser {  public static void main(String[] args) throws ParseException {    TestParser parser = new TestParser(new java.io.StringReader(args[0]));    SimpleNode root = parser.program();    root.dump("");  }}PARSER_END(TestParser)TOKEN :{   < OPAR  : "(" >  | < CPAR  : ")" > | < OBR   : "{" > | < CBR   : "}" > | < COL   : ":" > | < SCOL  : ";" > | < COMMA : "," > | < VAR   : "var" > | < EQ    : "=" >  | < ConST : "const" > | < ID    : ("_" | <LETTER>) ("_" | <ALPHANUM>)* >}TOKEN :{   < #DIGIT    : ["0"-"9"] > | < #LETTER   : ["a"-"z","A"-"Z"] > | < #ALPHANUM : <LETTER> | <DIGIT> >}SKIP : { " " | "t" | "r" | "n" }SimpleNode program() #PROGRAM :{}{  (decl())* (function())* <EOF> {return jjtThis;}}void decl() :{}{     var_decl()  |  const_decl()}void var_decl() #VAR :{}{  <VAR> id() <COL> id() <EQ> expr() <SCOL>}void const_decl() #ConST :{}{  <CONST> id() <COL> id() <EQ> expr() <SCOL>}void function() #FUNCTION :{}{  type() id() <OPAR> params() <CPAR> <OBR>  <CBR>}void type() #TYPE :{Token t;}{  t=<ID> {jjtThis.value = t.image;}}void id() #ID :{Token t;}{  t=<ID> {jjtThis.value = t.image;}}void params() #PARAMS :{}{  (param() (<COMMA> param())*)?}void param() #PARAM :{Token t;}{  t=<ID> {jjtThis.value = t.image;}}void expr() #EXPR :{Token t;}{  t=<ID> {jjtThis.value = t.image;}}

3

jjtree
该类(包含在中
javacc.jar
jj
为您创建一个文件:

java -cp javacc.jar jjtree TestParser.jjt

4

上一步已创建文件

TestParser.jj
(如果一切正常)。让
javacc
(也存在于中
javacc.jar
)对其进行处理:

java -cp javacc.jar javacc TestParser.jj

5

要编译所有源文件,请执行以下操作:

javac -cp .:javacc.jar *.java

(在Windows上,做的:

javac -cp .;javacc.jar *.java

6

关键时刻已经到来:让我们看看一切是否真的有效!要让解析器处理输入:

var n : int = I;const x : bool = B;double f(a,b,c) { }

执行以下命令:

java -cp . TestParser "var n : int = I; const x : bool = B; double f(a,b,c) { }"

并且应该在控制台上看到以下内容:

程序 删除  VAR   ID   ID   EXPR 删除  ConST   ID   ID   EXPR 功能  类型  ID  参数   参数   参数   参数

请注意,您看不到

ID
匹配的文本,但请相信我,它们在那里。该方法
dump()
只是不显示它。

高温超导

编辑

对于包含表达式的有效语法,您可以看一下我的以下表达式评估器:https://github.com/bkiers/Curta(语法在中

src/grammar
)。您可能想看看在二进制表达式的情况下如何创建根节点。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/463936.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号