I&#39;ve been playing around with parser-tools and am having difficulty expressing the following language:<div><br></div><div>&quot;remember &lt;alias&gt; is &lt;email&gt;&quot;</div><div>&quot;remember &lt;fact&gt;&quot;</div>

<div><br></div><div>where &lt;alias&gt; is any string that does not contain the word &#39;is&#39;, &lt;email&gt; is a well-formed email address and &lt;fact&gt; is any string that does not match the previous constraints.</div>

<div><br></div><div>Here&#39;s (stripped down) version of what I have so far:</div><div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">#lang racket</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><br>

</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">(require parser-tools/lex</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">         parser-tools/yacc</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">         (prefix-in : parser-tools/lex-sre))</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><br></font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">(define-lex-abbrevs</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  (atext (:+ (:or alphabetic (:/ #\0 #\9) (char-set &quot;!#$%&amp;&#39;*+-/=?^_`{|}~&quot;))))</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  (dot-atom (:: atext (:* #\. atext))))</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><br></font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">(define-tokens toy-tokens (addr-spec alias fact))</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">(define-empty-tokens empty-toy-tokens (eof REMEMBER IS))</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><br></font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">(define toy-lexer</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  (lexer-src-pos</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   ; Consume whitespace</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   ((:or #\tab #\space) (return-without-pos (toy-lexer input-port)))</font></div>

<div><span class="Apple-style-span" style="font-family:&#39;courier new&#39;,monospace">   </span></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   ; Email addresses</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   ((:: dot-atom #\@ dot-atom) (token-addr-spec lexeme))</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><br></font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   ; Commands</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   (&quot;remember&quot; &#39;REMEMBER)</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   (&quot;is&quot; &#39;IS)</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   </font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   ; ??? what to lex here ???</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   ((complement (:: any-string &quot;is&quot; any-string)) (token-alias lexeme))</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   (any-string (token-fact lexeme))))</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><br></font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">(define toy-parser</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  (parser</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   (tokens toy-tokens empty-toy-tokens)</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   (start start)</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   (end eof)</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   (error (lambda (a b c d e) (display (format &quot;~a ~a ~a ~a ~a&quot; a b c</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">                                               (position-offset d)</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">                                               (position-offset e)))))</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   (src-pos)</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   </font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">   (grammar</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    (start (() #f)</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">           ((REMEMBER alias IS addr-spec) `(alias ,$2 ,$4))</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">           ((REMEMBER fact) `(fact ,$2))))))</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><br></font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">; test</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">(define (test str)</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  (let ((p (open-input-string str)))</font></div>

<div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    (port-count-lines! p)</font></div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    (toy-parser (lambda () (toy-lexer p)))))</font></div>

</div></div><div><br></div><div>The problem I&#39;m having is that the &#39;fact&#39; lexer rule always matches without giving a chance for the other rules to attempt a match. Perhaps it is my ignorance with BNF. Can this language be expressed in this way? An alternative I&#39;ve thought of is to create a lexer rule to just match &quot;remember&quot; then pass the port to another lexer that tries to look for &quot;is&quot; or (eof) and munge the result into a token. Alternatively I could try to regex the &lt;alias&gt;, &lt;email&gt; or &lt;fact&gt; clauses out and parse them separately, but I&#39;d like to compose this toy parser into a larger one if possible. Yet I feel there is a simple technique here that I&#39;ve missed in my ignorance. Any ideas?</div>

<div>Many thanks, Simon.</div><div><br></div><div><br></div>