0

私が作ったプログラミング言語の言語インタプリタに取り組んでいます。これは、動作するはずのコードの例ですが、Syntax error at offset 45.このテストケースを読むと現在停止しています。

{
  foo = { "min" : 1 ,"max" : 5};
  foo["min"]
}

正しい解釈は、最初の行で foo を使用してマップを作成し、それを foo という名前の変数に格納し、2 行目でレコード foo のフィールド min の値を検索し、開始/終了のカーリーをセミコロンで囲みます。 2 つの式を 1 つのexpr_seq(つまり、ブロック) に変換すると、その中の最後のものと同じものに評価されexprます。

私の parser.mly の簡略版は次のとおりです。

%token <int> INT
%token <string> VAR
%token SEMI COMMA COLON ASSIGN QUOTE
%token LBRACK RBRACK LCURL RCURL
%token EOF

%start <int> main

%%

main:
| EOF
    { failwith "empty input" }
| e = exp EOF
    { e }

exp:
| INT
    { 0 }
| e = exp LBRACK v = q_var RBRACK
    { (* map lookup *) 0 }
| v = VAR ASSIGN e = exp
    { (* assign to var *) 0 }
| v = VAR LBRACK f = q_var RBRACK ASSIGN e = exp
    { (* assign to map field *) 0 }
| v = VAR
    { Printf.printf "lookup %s\n" v; 0 }
| LCURL e = expr_seq RCURL
    { (* Block expression *) 0 }
| LCURL f = fields RCURL
    { (* map literal *)0 }

fields:
| v = q_var COLON e = exp
    { [(v, e)] }
| v = q_var COLON e = exp COMMA vt = fields
    { (v, e) :: vt }

q_var:
| QUOTE v = VAR QUOTE
    { Printf.printf "qvar %s\n" v; v }

expr_seq:
| e = exp
    {[e]}
|e1 = exp SEMI e2 = expr_seq
    {e1 :: e2} 

自分でデバッグしようとすると、次の| v = VAR LBRACK f = q_var RBRACK ASSIGN e = expものを削除すると解析されて正しく実行されることがわかりましたが、マップに設定できるようにしたいと思っています。

問題が mly ファイルにあることは 98% 確信していますが、単純化したバージョンの lexer.mll は次のようになります。

{
  open Parser
  open Printf
}

rule token = parse
| [' ' '\t' '\n']
    { token lexbuf }
| "="
    {ASSIGN}
| ['1'-'9']['0'-'9']* as i
    { INT (int_of_string i) }
| ['a'-'z']+ as v
    { printf "var %s\n" v;VAR v }
| '{'
    { LCURL }
| '}'
    { RCURL }
| '['
    { printf "["; LBRACK }
| ']'
    { printf "]"; RBRACK }
| ';'
    { SEMI }
| ':'
    { COLON }
| ','
    { COMMA }
| '"'
    { QUOTE }
| eof
    { EOF }
| _
    { raise (Failure (sprintf "At offset %d: unexpected character.\n" 
                       (Lexing.lexeme_start lexbuf))) }

シンプルな ml ファイルは次のとおりです。

open Core.Std
open Printf

let rec read_all ic =
  try
    let ln = input_line ic in
      ln ^ read_all ic
  with End_of_file -> "";;

let () =
  let linebuf = Lexing.from_string (read_all stdin) in
  try
    Parser.main Lexer.token linebuf;
    printf "Done"
  with
  | Failure msg ->
      fprintf stderr "%s%!" msg
  | Parser.Error ->
      fprintf stderr "Syntax error at offset %d.\n%!"   
        (Lexing.lexeme_start linebuf)

編集: ここに Makefile があります。parser.mly、lexer.mll、および interpreter.ml は、上記の 2 番目、3 番目、および 4 番目のファイルです。

all: HB lexer.cmx parser.cmx interpreter.cmx
    @true

HB: interpreter.cmx
    ocamlfind ocamlopt -o HB -linkpkg -package core -package core_kernel \
    -thread -w -10 parser.cmx lexer.cmx interpreter.cmx

interpreter.cmx: lexer.cmx
    ocamlfind ocamlopt -package core -package core_kernel -thread -w   -10 \
    -c interpreter.ml

lexer.cmx: lexer.ml parser.cmx
    ocamlfind ocamlopt    -c lexer.ml

parser.cmx: parser.mly
    menhir --ocamlc "ocamlfind ocamlc" --infer --base parser  parser.mly
    ocamlfind ocamlc -c parser.mli
    ocamlfind ocamlopt -c parser.ml

lexer.ml: lexer.mll
    ocamllex lexer.mll

clean:
    @rm HB *.o *.cmi *.cmx lexer.ml parser.ml parser.mli 2>/dev/null || true

ここで、test.in が上記の最初のものです。

$ mk;HB < test.in
ocamllex lexer.mll
menhir --ocamlc "ocamlfind ocamlc" --infer --base parser  parser.mly
15 states, 286 transitions, table size 1234 bytes
Warning: 3 states have shift/reduce conflicts.
Warning: 3 shift/reduce conflicts were arbitrarily resolved.
ocamlfind ocamlc -c parser.mli
ocamlfind ocamlopt -c parser.ml
ocamlfind ocamlopt    -c lexer.ml
ocamlfind ocamlopt -package core -package core_kernel -thread -w -10 \
    -c interpreter.ml
ocamlfind ocamlopt -o HB -linkpkg -package core -package core_kernel \
    -thread -w -10 parser.cmx lexer.cmx interpreter.cmx
Syntax error at offset 45.
var foo
var min
qvar min
var max
qvar max
var foo
[var min
]qvar min

編集2:| e = VAR LBRACK v = q_var RBRACK { GetMap(v,LookupVar(e)) } パーサーに特別なケースとして追加するだけになりました。それで、問題は解決しましたか?

4

2 に答える 2

1

私はあなたの言語で遊んでみましたが、パーサーに同意するようになりました.あなたの入力は悪いです.あなたの「マップフィールドへの割り当て」ルールを見てください:

v = VAR LBRACK f = q_var RBRACK ASSIGN e = exp

このノイズの多い変数を削除すると(使用する必要はありません):

VAR LBRACK q_var RBRACK ASSIGN exp

つまり、ルールは次のことを想定しています。

VAR, '[' '"' VAR '"' ']' '=' exp

例えば

foo["min"] = 42

以下は完全に受け入れられます

{
  foo = { "min" : 1 ,"max" : 5};
  foo["min"] = 42
}
于 2015-04-23T11:16:38.983 に答える
0

これを振り返ってみると、それが機能しない理由は、文法が LR(1) ではないため、Menhir で正確に解析できないためだと思います。がまたは isfoo["min"]の開始点であるかどうかを判断するには、 4 つほどのシンボルを先読みする必要があり、LR(1) パーサーとしての Menhir は 1 つだけ先読みします。v = VAR LBRACK f = q_var RBRACK ASSIGN e = expe = exp LBRACK v = q_var RBRACK

于 2015-05-16T04:21:27.797 に答える