I&#39;m finally getting serious about using complex macros for (properly) parsing and processing domain specific languages in PLT Scheme. To date, I have just been using syntax-rules to do the minimum parsing needed to break out the basic elements of a construct and generate code that passes them to the code that does the real work at run-time. This is relatively easy to write, but pretty much limits error messages to &#39;bad syntax&#39;, which isn&#39;t real useful. But, I haven&#39;t found any really good tutorial material to help me get started.<br>
<br>So first, can anyone point me to some good material to get started with syntax-case, define-for-syntax, and so on for doing this right? I&#39;ve gotten started by looking at things like package.ss (in the scheme collection) that have some complex macros.<br>
<br>An example of what I would like to do is the define-rule macro in the inference collection.<br><br>Here is a contrived example of a forward-chaining rule:<br><br><font face="courier new,monospace">(define-rule (test-rule-1 test-rule)<br>
    (class1 ?a b c)<br>    ?class2 &lt;- (class2 ?a b c)<br>    (or (and (class3 ?a b c)<br>             (class4 ?a b c))<br>        (class5 ?a b c))<br>  ==&gt;<br>    (retract ?class2)<br>    (printf &quot;a = ~s~n&quot; ?a))<br>
</font><br>And, here is an example of a backward-chaining rule:<br><br><font face="courier new,monospace">(define-rule (example-rule ancestor-rules)<br>    (ancestor ?x &gt;y)<br>  &lt;==<br>    (ancestor ?x ?z)<br>    (ancestor ?z ?y))<br>
</font><br>In the current (not so good) implementation, the define-rule macro just breaks the rule clauses into goal clauses, pattern clauses, and action expressions using &lt;== and &gt;== as delimiters. Then, it just passes those raw chunks in the run-time code to actually parse and process them.<br>
<br>I would like to do is to do all of the parsing and checking at expansion time and provide decent error messages. So, at expansion time, I&#39;d like to (1) parse out the clauses, (2) check the syntax of the goal and pattern clauses, (3) normalize the form of the pattern clauses to (or (and . atomic-patterns) ...), and (4) generate the appropriate code. (Note that the action expressions are &#39;just code&#39; that will be generated into a procedural object and &#39;checked&#39; that way.) I am comfortable with (1) and (4) - at least with syntax-rules - and I have a working version using syntax-case with error checking at that level (e.g., the rule name must be an identifier; there can&#39;t be multiple &lt;== or ==&gt;; if both &lt;== and ==&gt; are present, they must be in that order). I can do (2) in run-time code, but don&#39;t know how to convert that into expansion-time code - maybe it&#39;s easy, maybe not. Finally, (3) is some pretty complex run-time code with several mutually recursive procedures doing the normalization. I don&#39;t even know where to start doing this (in something other than brute force pattern matching with syntax-rule/syntax case, but there are several dozens of cases and there has to be a better way).<br>
<br>So, can someone point me in the right direction to get started? Good examples in the current PLT Scheme code base would work.<br><br>And, just for the curious, here is a real example of a forward-chaining rule to show what they can look like.<br>
<br><span style="font-family: courier new,monospace;">;;; If a cell is numbered, remove that number from any other cell in the<br>;;; same row, col, or box.<br>(define-rule (rule-5 sudoku-rules)</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">    (cell ?row ?col ?box </span><span style="font-family: courier new,monospace;">?value : (number? ?value))<br>    cell-1 &lt;- (or (cell ?row-1 : (= ?row-1 ?row)<br>                        ?col-1 : (not (= ?col-1 ?col))<br>
                        ?box-1<br>                        ?value-1 : (and (pair? ?value-1)<br>                                        (memv ?value ?value-1)))<br></span><span style="font-family: courier new,monospace;">                  (cell ?row-1 : (not = (= ?row-1 ?row))<br>

                        ?col-1 : (= ?col-1 ?col)<br>
                        ?box-1<br>
                        ?value-1 : (and (pair? ?value-1)<br>
                                        (memv ?value ?value-1)))</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">                  (cell ?row-1<br>
                        ?col-1<br>
                        ?box-1 : (and (= ?box-1 ?box)<br>                                      (or (not (= ?row-1 ?row)<br>                                          (not (= ?col-1 ?col))))<br>
                        ?value-1 : (and (pair? ?value-1)<br>
                                        (memv ?value ?value-1)))</span>)<br>  ==&gt;<br>    (replace ?cell-1 `(cell ,?row-1 ,?col-1 ,?box-1 ,(delete ?value ?value-1))))<br style="font-family: courier new,monospace;">
<br>As always, thanks in advance for any advice, directions, mentoring, ...<br>Doug<br>