; .bp
; .NH
; IMPLEMENTATION DE CXYACC.
; .NH 2
; Structures de donne'es et utilitaires de base.
; .PP
; \fBCxyacc\fR est une tclass a` deux champs : le \fBlexical\fR, qui contient
; un objet capable de re'pondre au message \fBnext-lexres\fR, et le
; flux de sortie \fBerr-stream\fR ou` s'impriment les messages d'erreur :
(deftclass Cxyacc lexical err-stream)
; .PP
; Un analyseur lexical re'pond au message \fBnext-lexres\fR, en rendant un \fBlexres\fR,
; objet d'un lrecord ceyx a` deux champs: le champ \fBtoken\fR contenant le
; token lu (ID, STRING...), le champ \fBvalue\fR contenant la valeur lue.
; Exemple: (omakeq lexres token 'ID value 'toto)
(deflrecord lexres token value)
; Les tables de l'analyseur engendre' par cxyacc sont garde'es dans un lrecord appele'
; \fBCxyacc-tables\fR :
(deflrecord Cxyacc-tables
cyexca cyact cypact cypgo cyr1 cyr2 cychk cydef
CYERRCODE CYLAST CYNPROD)
; La fonction \fBadd-token-value\fR utilise'e lors du chargement d'un analyseur
; re'alise la liaison nom du token - valeur nume'rique, en mettant cette valeur
; dans un atome ayant pour nom le token et package' sous l'analyseur :
(dmd {Cxyacc}:add-token-value (cxyacc token valeur)
`(set (msymbol ',cxyacc ',token) ,valeur))
; Notons que le token spe'cial \fB*EOI*\fR sera toujours lie' a` 0.
; .PP
; En attendant les vrais vecteurs, voici une autre fonction qui sert au
; chargement :
(de {Cxyacc}:vector (liste)
(let ((vec (makevector (length liste) 0)))
(for (i 0 1 (1- (length liste)))
(vset vec i (nextl liste)))
vec))
; Le traitement d'erreur par de'faut :
(demethod {Cxyacc}:error (cxyacc . msgs) (err-stream)
(sendq prin err-stream
"** cxyacc : " (model cxyacc) " : ")
(while msgs
(sendq prin err-stream
(nextl msgs) " "))
(sendq terpri err-stream))
; .NH 2
; Le moteur d'exe'cution.
; .LP
; Le lanceur :
(de {Cxyacc}:parse (cxyacc)
(olet (Cxyacc-tables
(cyexca cyact cypact cypgo cyr1
cyr2 cychk cydef CYERRCODE CYNPROD CYLAST)
(eval (msymbol (model cxyacc) '$tables)))
(let((cystate 0)
(cychar -1)
(cynerrs 0)
(cyerrflag 0)
(CYFLAG -1000)
(cyn 0)
(cym 0)
(cyj 0)
(saved-v-stack nil)
(v-stack nil)
(s-stack nil)
(cylval)
(cyval))
(newl s-stack cystate)
(newl v-stack cyval)
(tag {Cxyacc}:*end*
({Cxyacc}:newstate)))))
; les fonctions auxiliaires du moteur :
(de {Cxyacc}:newstate ()
(setq cyn (vref cypact cystate))
(if (<= cyn CYFLAG)
({Cxyacc}:default)
({Cxyacc}:nextcychar)
(if (or (minusp (setq cyn (+ cyn cychar))) (>= cyn CYLAST))
({Cxyacc}:default)
(setq cyn (vref cyact cyn))
(ifn (= (vref cychk cyn) cychar)
({Cxyacc}:default)
(setq cychar -1
cyval cylval
cystate cyn)
(when (> 0 cyerrflag)
(decr cyerrflag))
(newl s-stack cystate)
(newl v-stack cyval)
({Cxyacc}:newstate)))))
(de {Cxyacc}:default ()
(selectq (setq cyn (vref cydef cystate))
(-2
({Cxyacc}:nextcychar)
(setq cyxi 0)
(until
(and (= (vref cyexca cyxi) -1)
(= (vref cyexca (1+ cyxi)) cystate))
(incr cyxi 2))
(until (or (minusp (vref cyexca (incr cyxi 2)))
(= (vref cyexca cyxi) cychar)))
(when (minusp (setq cyn (vref cyexca (1+ cyxi))))
(exit {Cxyacc}:*end* cyval)))
(0
(when (= cyerrflag 0)
(sendq error cxyacc "erreur de syntaxe"))
({Cxyacc}:errlab))
(t nil))
(setq saved-v-stack v-stack)
(let ((nbt (vref cyr2 cyn)))
(repeat nbt (nextl s-stack))
(repeat (1- nbt)(nextl v-stack))
(setq cyval (car v-stack))
(when (> nbt 0)(nextl v-stack)))
(setq cym cyn
cyn (vref cyr1 cyn)
cyj (+ (vref cypgo cyn) (car s-stack) 1))
(unless (and (< cyj CYLAST)
(= (vref cychk
(setq cystate (vref cyact cyj)))
(- cyn)))
(setq cystate (vref cyact (vref cypgo cyn))))
(sendq semantic-action cxyacc cym saved-v-stack)
(newl s-stack cystate)
(newl v-stack cyval)
({Cxyacc}:newstate))
(de {Cxyacc}:errlab ()
(incr cynerrs)
(selectq cyerrflag
((0 1 2)
(setq cyerrflag 3)
(until (null s-stack)
(setq cyn (+ (vref cypact (car s-stack))
CYERRCODE))
(when (and (plusp cyn)
(< cyn CYLAST)
(= (vref cychk (vref cyact cyn))
CYERRCODE))
(setq cystate (vref cyact cyn))
(newl s-stack cystate)
(newl v-stack cyval)
({Cxyacc}:newstate))
(setq cyn (vref cypact (car s-stack)))
(nextl s-stack) ; pop state stack
(nextl v-stack)) ; pop value stack
(exit {Cxyacc}:*end* nil)) ; abort
(3
(when (zerop cychar) (exit {Cxyacc}:*end* nil))
(setq cychar -1)
({Cxyacc}:newstate)); try again in same state
(t nil)))
(de {Cxyacc}:nextcychar ()
(when (minusp cychar)
(let ((cylexres (sendq next-lexres
({Cxyacc}:lexical cxyacc))))
(setq cychar
(if (eq ({lexres}:token cylexres) '{lexres}:CHAR)
({lexres}:value cylexres)
(eval (msymbol (model cxyacc)
({lexres}:token cylexres)))))
(setq cylval ({lexres}:value cylexres)))
(when (minusp cychar)
(setq cychar 0))))
; Pour retrouver les $i :
(dmd peek-val (x)
(selectq x
(0 '(car saved-v-stack))
(1 '(cadr saved-v-stack))
(2 '(caddr saved-v-stack))
(t `(nth ,x saved-v-stack))))
; .NH 2
; Les fonctions auxiliaires des actions se'mantiques.
; .LP
; Les analogues de YYACCEPT, YYABORT, YYERROR :
(dmd {Cxyacc}:accept (res)
`(exit {Cxyacc}:*end* ,res))
(dmd {Cxyacc}:abort ()
`(exit {Cxyacc}:*end*))
(dmd {Cxyacc}:create-error ()
`({Cxyacc}:errlab))
; les analogues de yyerrok et yyclearin :
(dmd {Cxyacc}:errok ()
'(setq cyerrflag 0))
(dmd {Cxyacc}:clearin ()
'(setq cychar -1))