0

在尝试为类似 Scheme 的语言定义语法时,我发现使用 java 后端的 kompiled 文件的运行结果

kompile --backend java scheme.k -d .

llvm 后端的行为不同

kompile --backend llvm scheme.k -d .

这是我的 scheme.k 代码:

module SCHEME-COMMON
  imports DOMAINS-SYNTAX

  syntax Name ::= "+" | "-" | "*" | "/"
                | "display" | "newline"

  syntax Names ::= List{Name," "}

  syntax Exp ::= Int | Bool | String | Name
               | "[" Name Exps "]"                 [strict(2)]

  syntax Exps  ::= List{Exp," "}                   [strict]
  syntax Val
  syntax Vals ::= List{Val," "}
  syntax Bottom
  syntax Bottoms ::= List{Bottom," "}

  syntax Pgm ::= Exp Pgm            [strict(1)] 
               | "eof"

endmodule


module SCHEME-SYNTAX
  imports SCHEME-COMMON
  imports BUILTIN-ID-TOKENS

  syntax Name ::= r"[a-z][_a-zA-Z0-9]*"           [token, prec(2)]
                | #LowerId                        [token]
endmodule


module SCHEME-MACROS
  imports SCHEME-COMMON

endmodule


module SCHEME
  imports SCHEME-COMMON
  imports SCHEME-MACROS
  imports DOMAINS

  configuration <T color="yellow">
                  <k color="green"> $PGM:Pgm </k>
                  <env color="violet"> .Map </env>
                  <store color="white"> .Map </store>
                  <input color="magenta" stream="stdin"> .List </input>
                  <output color="brown" stream="stdout"> .List </output>
                </T>

  syntax Val ::= Int | Bool | String
  syntax Exp ::= Val
  syntax Exps ::= Vals
  syntax Vals ::= Bottoms
  syntax Exps ::= Names
  syntax Names ::= Bottoms
  syntax KResult ::= Vals | Val

  rule _:Val P:Pgm => P
    when notBool(P ==K eof)
  rule V:Val eof => V

  rule [+ I1 I2 Vals] => [+ (I1 +Int I2) Vals]              [arith]
  rule [+ I .Vals] => I                                     [arith]
  rule [- I1 I2 Vals] => [- (I1 -Int I2) Vals]              [arith]
  rule [- I .Vals] => I                                     [arith]
  rule [* I1 I2 Vals] => [* (I1 *Int I2) Vals]              [arith]
  rule [* I .Vals] => I                                     [arith]
  rule [/ I1 I2 Vals] => [/ (I1 /Int I2) Vals]
    when I2 =/=K 0                                          [arith]
  rule [/ I .Vals] => I                                     [arith]

  rule <k> [newline .Exps] => "" ...</k>
       <output>... .List => ListItem("\n") </output>        [io]

  rule <k> [display V:Val] => "" ...</k>
       <output>... .List => ListItem(V) </output>           [io]

endmodule

这是我要运行的测试文件:

[display 8]
eof

奇怪的是,使用java的kompiled版本可以正常运行这个测试用例,而使用llvm的kompiled版本卡在

<k>
    8  .Bottoms ~> #freezer[__]_SCHEME-COMMON_Exp_Name_Exps0_ ( display ) ~> #freezer___SCHEME-COMMON_Pgm_Exp_Pgm1_ ( eof )
</k>

可能的原因是什么?kompile 的版本信息是

RV-K version 1.0-SNAPSHOT
Git revision: a7c2937
Git branch: UNKNOWN  
Build date: Wed Feb 12 09:46:03 CST 2020
4

1 回答 1

1

在 LLVM 和 Haskell 后端中,当两个产生式共享相同的 arity 和 klabel 属性并且一个产生式的所有参数类型小于或等于另一个产生式的参数类型时,就说两个产生式相互重载,并且结果排序第一个的结果小于另一个的结果。在匹配重载术语时要特别考虑:例如,在您的示例中,如果说 Exps 列表和 Vals 列表重载,那么如果您有一个 pattern V:Vals,它将匹配术语V:Val, .Expssort Exps

默认情况下,Java 后端假定具有子排序关系的排序之间的所有列表都重载。但是,LLVM 和 Haskell 后端不做这个假设。因此,如果您为您的 Exps 列表和您的 Vals 列表提供相同的 klabel 属性,您的示例将起作用。我们不会在 llvm 后端做同样的事情,因为我们发现它往往会导致你的语法在你不期望的地方出现严重的歧义。

例如:

module SCHEME-COMMON
  imports DOMAINS-SYNTAX

  syntax Name ::= "+" | "-" | "*" | "/"
                | "display" | "newline"

  syntax Names ::= List{Name," "}                  [klabel(exps)]

  syntax Exp ::= Int | Bool | String | Name
               | "[" Name Exps "]"                 [strict(2)]

  syntax Exps  ::= List{Exp," "}                   [strict, klabel(exps)]
  syntax Val
  syntax Vals ::= List{Val," "}                    [klabel(exps)]
  syntax Bottom
  syntax Bottoms ::= List{Bottom," "}              [klabel(exps)]

  syntax Pgm ::= Exp Pgm            [strict(1)] 
               | "eof"

endmodule
于 2020-04-30T20:47:21.123 回答