私はいくつかのプログラミング言語の演習に取り組んでおり、仕様を使用して言語構文を定義して解析しようとしています。コードは以下のように簡単です。しかし、サブ式で正しく解析する方法に問題があります。
(:require [clojure.spec.alpha :as s]
[clojure.edn :as e])
(s/def ::const-exp integer?)
(s/def ::var-exp symbol?)
;; -(1,2)
(s/def ::diff-exp (s/cat :minus #{'-} :exps (s/coll-of ::expr :count 2)))
;; zero? 2
(s/def ::zero?-exp (s/cat :zero? #{'zero?} :exp1 ::expr))
;; if x then y else c
(s/def ::if-exp (s/cat :if #{'if} :exp1 ::expr :then #{'then} :exp2 ::expr :else #{'else} :exp3 ::expr))
;; let x = y in c
(s/def ::let-exp (s/cat :let #{'let} :id ::var-exp :eq #{'=} :exp1 ::expr :in #{'in} :body ::expr))
(s/def ::expr
(s/or
:const-exp ::const-exp
:diff-exp ::diff-exp
:var-exp ::var-exp
:zero?-exp ::zero?-exp
:if-exp ::if-exp
:let-exp ::let-exp))
(defn pgm [x] (e/read-string (format "[%s]" x)))
これまでのところ、基本的な式をうまく解析できます。お気に入り(s/conform ::expr (pgm "let x = 7 in x"))
しかし、 let 式の例では、最後の x を複雑な式 に変更(s/conform ::expr (pgm "let x = 7 in let y = 8 in y"))
すると、次の説明で解析が失敗します。
In: [6] val: (y = 8 in y) fails spec: :eopl.let-spec/let-exp at: [:let-exp] predicate: (cat :let #{(quote let)} :id :eopl.let-spec/var-exp :eq #{(quote =)} :exp1 :eopl.let-spec/expr :in #{(quote in)} :body :eopl.let-spec/expr), Extra input
先読みや再帰的適合を適切に行うことができないようですか?それとも、ここで構文を間違って定義していますか?
Specで正しく解析できるようにするには、これをどのように解決すればよいですか?
前もって感謝します。