Hi Joe,
> I can confirm that this works for me, but I feel a little uptight
> about putting this precedence in since the spec I'm working from
> says:
>
> "The +, -, *, and / operators are left associative. The comparison
> operators do not associate, e.g., a=b=c is erroneous, but a=(b=c)
> is legal."
>
> Setting %left EQ doesn't trigger an error in the a=b=c
> case... rather the opposite. I wonder how I might make "expr EQ
> expr" work but "expr EQ expr EQ expr" fail.
You're right. The solution is to give precedence and associativity
to every operators. Following is a new simple.wy grammar that works
well. Notice that the precedence level increases with each new
%nonassoc, %left or %right statement. So comparison operators have
lowest priority, and aren't associative (that is a=b=c will fail).
The next priority is given to '+' and '-', and '*', '/' have the
highest priority (I followed the normal arithmetic precedences).
;;; simple.wy -- LALR grammar for (simplified) Tiger
%package simple-wy
;; Not really necessary, as it is the default start symbol
%start expression
%type <symbol>
%token <symbol> symbol "[A-Za-z][_A-Za-z0-9]*"
%type <string>
%token <string> STRING_LITERAL
%type <punctuation>
%token <punctuation> EQ "="
%token <punctuation> NE "<>"
%token <punctuation> ADD "+"
%token <punctuation> SUB "-"
%token <punctuation> MUL "*"
%token <punctuation> DIV "/"
%nonassoc EQ NE ;; lowest precedence & non associative
%left ADD SUB ;; precedence > above and < below
%left MUL DIV ;; highest precedence
%%
;; For use with Semantic, must return valid semantic tags!
expression
: ;;Empty
| expr
(TAG "expr" 'expr :value $1)
;
expr
: symbol
| STRING_LITERAL
| expr EQ expr
(list 'EQ $1 $3)
| expr NE expr
(list 'NE $1 $3)
| expr ADD expr
(list 'ADD $1 $3)
| expr SUB expr
(list 'SUB $1 $3)
| expr MUL expr
(list 'MUL $1 $3)
| expr DIV expr
(list 'DIV $1 $3)
;
%%
(define-lex simple-lexer
"Simple lexical analyzer."
semantic-lex-ignore-whitespace
semantic-lex-ignore-newline
semantic-lex-ignore-comments
;;;; Auto-generated analyzers.
simple-wy--<keyword>-keyword-analyzer
;; From the documentation string for `semantic-lex-tokens':
;; "Always add this analyzer *after* `semantic-lex-number', or other
;; analyzers that match its regular expression." (my emphasis)
simple-wy--<symbol>-regexp-analyzer
simple-wy--<punctuation>-string-analyzer
simple-wy--<string>-sexp-analyzer
;;;;
semantic-lex-default-action)
;;; simple.wy ends here
To recognize operators as punctuations (which I think is more
appropriate than keywords), you must tell Emacs which characters are
punctuations in your `simple-mode-syntax-table'. I used the following
with success:
(defvar simple-mode-syntax-table
(let ((table (make-syntax-table (standard-syntax-table))))
(modify-syntax-entry ?\+ "." table) ;; Operator PLUS
(modify-syntax-entry ?\- "." table) ;; Operator MINUS
(modify-syntax-entry ?\= "." table) ;; Operator EQ
(modify-syntax-entry ?\> "." table) ;; Operator NE (part)
(modify-syntax-entry ?\< "." table) ;; Operator NE (part)
;; Operator MULT & 2nd char of "/*" comment-start sequence & 1st
;; char of "*/" comment-end sequence
(modify-syntax-entry ?\* ". 23" table)
;; Operator DIV & 1st char of "/*" comment-start sequence & 2nd
;; char of "*/" comment-end sequence
(modify-syntax-entry ?\/ ". 14" table)
table)
"Syntax table used in simple mode buffers.
Define operators as punctuations.")
With the above grammar, on this example:
---------[cut here]-----------------
a = "c"
"a" = b
"a" = "b"
a = b
a
"b"
A + B = C
A+B-C/D*E = X
Y = A/B + C*D - E
A = B <> C /* "A = B <>" Fails */
---------[cut here]-----------------
M-x bovinate shows:
(("expr" expr
(:value
(EQ "a" "\"c\""))
nil #<overlay from 1 to 8 in test.simple>)
("expr" expr
(:value
(EQ "\"a\"" "b"))
nil #<overlay from 9 to 16 in test.simple>)
("expr" expr
(:value
(EQ "\"a\"" "\"b\""))
nil #<overlay from 17 to 26 in test.simple>)
("expr" expr
(:value
(EQ "a" "b"))
nil #<overlay from 27 to 32 in test.simple>)
("expr" expr
(:value "a")
nil #<overlay from 33 to 34 in test.simple>)
("expr" expr
(:value "\"b\"")
nil #<overlay from 35 to 38 in test.simple>)
("expr" expr
(:value
(EQ
(ADD "A" "B")
"C"))
nil #<overlay from 39 to 48 in test.simple>)
("expr" expr
(:value
(EQ
(SUB
(ADD "A" "B")
(MUL
(DIV "C" "D")
"E"))
"X"))
nil #<overlay from 49 to 62 in test.simple>)
("expr" expr
(:value
(EQ "Y"
(SUB
(ADD
(DIV "A" "B")
(MUL "C" "D"))
"E")))
nil #<overlay from 63 to 80 in test.simple>)
("expr" expr
(:value "C")
nil #<overlay from 90 to 91 in test.simple>))
[...]
> ... will fail on `concat', because $1 and $2 aren't strings but
> semantic tags! This one should work better:
>
> (TAG "expr eq" 'expr :value (format "(equal %s %s)" $1 $3))
>
> Yes, that is better... it works! I revised that a little further to
> this:
>
> (TAG "expr eq" 'expr :value (format "(equal %s %s)"
> (car
> (cdaddr $1))
> (car
> (cdaddr $3)) ))
>
> Where the (car (cdaddr ...) is meant to extract the :value
> parameter.
Please don't do that! Use the semantic-tag API instead, like this:
(TAG "expr eq" 'expr
:value (format "(equal %s %s)"
(semantic-tag-get-attribute $1 :value)
(semantic-tag-get-attribute $3 :value)))
Enjoy!
David
|