aboutsummaryrefslogtreecommitdiff
; SILex - Scheme Implementation of Lex
; Copyright (C) 2001  Danny Dube'
; 
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation; either version 2
; of the License, or (at your option) any later version.
; 
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
; 
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

;
; Nettoie les actions en enlevant les lignes blanches avant et apres
;

(define out-split-in-lines
  (lambda (s)
    (let ((len (string-length s)))
      (let loop ((i 0) (start 0))
	(cond ((= i len)
	       '())
	      ((char=? (string-ref s i) #\newline)
	       (cons (substring s start (+ i 1))
		     (loop (+ i 1) (+ i 1))))
	      (else
	       (loop (+ i 1) start)))))))

(define out-empty-line?
  (lambda (s)
    (let ((len (- (string-length s) 1)))
      (let loop ((i 0))
	(cond ((= i len)
	       #t)
	      ((char-whitespace? (string-ref s i))
	       (loop (+ i 1)))
	      (else
	       #f))))))

; Enleve les lignes vides dans une liste avant et apres l'action
(define out-remove-empty-lines
  (lambda (lines)
    (let loop ((lines lines) (top? #t))
      (if (null? lines)
	  '()
	  (let ((line (car lines)))
	    (cond ((not (out-empty-line? line))
		   (cons line (loop (cdr lines) #f)))
		  (top?
		   (loop (cdr lines) #t))
		  (else
		   (let ((rest (loop (cdr lines) #f)))
		     (if (null? rest)
			 '()
			 (cons line rest))))))))))

; Enleve les lignes vides avant et apres l'action
(define out-clean-action
  (lambda (s)
    (let* ((lines (out-split-in-lines s))
	   (clean-lines (out-remove-empty-lines lines)))
      (apply string-append clean-lines))))




;
; Pretty-printer pour les booleens, la liste vide, les nombres,
; les symboles, les caracteres, les chaines, les listes et les vecteurs
;

; Colonne limite pour le pretty-printer (a ne pas atteindre)
(define out-max-col 76)

(define out-flatten-list
  (lambda (ll)
    (let loop ((ll ll) (part-out '()))
      (if (null? ll)
	  part-out
	  (let* ((new-part-out (loop (cdr ll) part-out))
		 (head (car ll)))
	    (cond ((null? head)
		   new-part-out)
		  ((pair? head)
		   (loop head new-part-out))
		  (else
		   (cons head new-part-out))))))))

(define out-force-string
  (lambda (obj)
    (if (char? obj)
	(string obj)
	obj)))

; Transforme une liste impropre en une liste propre qui s'ecrit
; de la meme facon
(define out-regular-list
  (let ((symbolic-dot (string->symbol ".")))
    (lambda (p)
      (let ((tail (cdr p)))
	(cond ((null? tail)
	       p)
	      ((pair? tail)
	       (cons (car p) (out-regular-list tail)))
	      (else
	       (list (car p) symbolic-dot tail)))))))

; Cree des chaines d'espaces de facon paresseuse
(define out-blanks
  (let ((cache-v (make-vector 80 #f)))
    (lambda (n)
      (or (vector-ref cache-v n)
	  (let ((result (make-string n #\space)))
	    (vector-set! cache-v n result)
	    result)))))

; Insere le separateur entre chaque element d'une liste non-vide
(define out-separate
  (lambda (text-l sep)
    (if (null? (cdr text-l))
	text-l
	(cons (car text-l) (cons sep (out-separate (cdr text-l) sep))))))

; Met des donnees en colonnes.  Retourne comme out-pp-aux-list
(define out-pp-columns
  (lambda (left right wmax txt&lens)
    (let loop1 ((tls txt&lens) (lwmax 0) (lwlast 0) (lines '()))
      (if (null? tls)
	  (vector #t 0 lwmax lwlast (reverse lines))
	  (let loop2 ((tls tls) (len 0) (first? #t) (prev-pad 0) (line '()))
	    (cond ((null? tls)
		   (loop1 tls
			  (max len lwmax)
			  len
			  (cons (reverse line) lines)))
		  ((> (+ left len prev-pad 1 wmax) out-max-col)
		   (loop1 tls
			  (max len lwmax)
			  len
			  (cons (reverse line) lines)))
		  (first?
		   (let ((text     (caar tls))
			 (text-len (cdar tls)))
		     (loop2 (cdr tls)
			    (+ len text-len)
			    #f
			    (- wmax text-len)
			    (cons text line))))
		  ((pair? (cdr tls))
		   (let* ((prev-pad-s (out-blanks prev-pad))
			  (text     (caar tls))
			  (text-len (cdar tls)))
		     (loop2 (cdr tls)
			    (+ len prev-pad 1 text-len)
			    #f
			    (- wmax text-len)
			    (cons text (cons " " (cons prev-pad-s line))))))
		  (else
		   (let ((prev-pad-s (out-blanks prev-pad))
			 (text     (caar tls))
			 (text-len (cdar tls)))
		     (if (> (+ left len prev-pad 1 text-len) right)
			 (loop1 tls
				(max len lwmax)
				len
				(cons (reverse line) lines))
			 (loop2 (cdr tls)
				(+ len prev-pad 1 text-len)
				#f
				(- wmax text-len)
				(append (list text " " prev-pad-s)
					line)))))))))))

; Retourne un vecteur #( multiline? width-all width-max width-last text-l )
(define out-pp-aux-list
  (lambda (l left right)
    (let loop ((l l) (multi? #f) (wall -1) (wmax -1) (wlast -1) (txt&lens '()))
      (if (null? l)
	  (cond (multi?
		 (vector #t wall wmax wlast (map car (reverse txt&lens))))
		((<= (+ left wall) right)
		 (vector #f wall wmax wlast (map car (reverse txt&lens))))
		((<= (+ left wmax 1 wmax) out-max-col)
		 (out-pp-columns left right wmax (reverse txt&lens)))
		(else
		 (vector #t wall wmax wlast (map car (reverse txt&lens)))))
	  (let* ((obj (car l))
		 (last? (null? (cdr l)))
		 (this-right (if last? right out-max-col))
		 (result (out-pp-aux obj left this-right))
		 (obj-multi? (vector-ref result 0))
		 (obj-wmax   (vector-ref result 1))
		 (obj-wlast  (vector-ref result 2))
		 (obj-text   (vector-ref result 3)))
	    (loop (cdr l)
		  (or multi? obj-multi?)
		  (+ wall obj-wmax 1)
		  (max wmax obj-wmax)
		  obj-wlast
		  (cons (cons obj-text obj-wmax) txt&lens)))))))

; Retourne un vecteur #( multiline? wmax wlast text )
(define out-pp-aux
  (lambda (obj left right)
    (cond ((boolean? obj)
	   (vector #f 2 2 (if obj '("#t") '("#f"))))
	  ((null? obj)
	   (vector #f 2 2 '("()")))
	  ((number? obj)
	   (let* ((s (number->string obj))
		  (len (string-length s)))
	     (vector #f len len (list s))))
	  ((symbol? obj)
	   (let* ((s (symbol->string obj))
		  (len (string-length s)))
	     (vector #f len len (list s))))
	  ((char? obj)
	   (cond ((char=? obj #\space)
		  (vector #f 7 7 (list "#\\space")))
		 ((char=? obj #\newline)
		  (vector #f 9 9 (list "#\\newline")))
		 (else
		  (vector #f 3 3 (list "#\\" obj)))))
	  ((string? obj)
	   (let loop ((i (- (string-length obj) 1))
		      (len 1)
		      (text '("\"")))
	     (if (= i -1)
		 (vector #f (+ len 1) (+ len 1) (cons "\"" text))
		 (let ((c (string-ref obj i)))
		   (cond ((char=? c #\\)
			  (loop (- i 1) (+ len 2) (cons "\\\\" text)))
			 ((char=? c #\")
			  (loop (- i 1) (+ len 2) (cons "\\\"" text)))
			 (else
			  (loop (- i 1) (+ len 1) (cons (string c) text))))))))
	  ((pair? obj)
	   (let* ((l (out-regular-list obj))
		  (result (out-pp-aux-list l (+ left 1) (- right 1)))
		  (multiline? (vector-ref result 0))
		  (width-all  (vector-ref result 1))
		  (width-max  (vector-ref result 2))
		  (width-last (vector-ref result 3))
		  (text-l     (vector-ref result 4)))
	     (if multiline?
		 (let* ((sep (list #\newline (out-blanks left)))
			(formatted-text (out-separate text-l sep))
			(text (list "(" formatted-text ")")))
		   (vector #t
			   (+ (max width-max (+ width-last 1)) 1)
			   (+ width-last 2)
			   text))
		 (let* ((sep (list " "))
			(formatted-text (out-separate text-l sep))
			(text (list "(" formatted-text ")")))
		   (vector #f (+ width-all 2) (+ width-all 2) text)))))
	  ((and (vector? obj) (zero? (vector-length obj)))
	   (vector #f 3 3 '("#()")))
	  ((vector? obj)
	   (let* ((l (vector->list obj))
		  (result (out-pp-aux-list l (+ left 2) (- right 1)))
		  (multiline? (vector-ref result 0))
		  (width-all  (vector-ref result 1))
		  (width-max  (vector-ref result 2))
		  (width-last (vector-ref result 3))
		  (text-l     (vector-ref result 4)))
	     (if multiline?
		 (let* ((sep (list #\newline (out-blanks (+ left 1))))
			(formatted-text (out-separate text-l sep))
			(text (list "#(" formatted-text ")")))
		   (vector #t
			   (+ (max width-max (+ width-last 1)) 2)
			   (+ width-last 3)
			   text))
		 (let* ((sep (list " "))
			(formatted-text (out-separate text-l sep))
			(text (list "#(" formatted-text ")")))
		   (vector #f (+ width-all 3) (+ width-all 3) text)))))
	  (else
	   (display "Internal error: out-pp")
	   (newline)))))

; Retourne la chaine a afficher
(define out-pp
  (lambda (obj col)
    (let* ((list-rec-of-strings-n-chars
	    (vector-ref (out-pp-aux obj col out-max-col) 3))
	   (list-of-strings-n-chars
	    (out-flatten-list list-rec-of-strings-n-chars))
	   (list-of-strings
	    (map out-force-string list-of-strings-n-chars)))
      (apply string-append list-of-strings))))




;
; Nice-printer, plus rapide mais moins beau que le pretty-printer
;

(define out-np
  (lambda (obj start)
    (letrec ((line-pad
	      (string-append (string #\newline)
			     (out-blanks (- start 1))))
	     (step-line
	      (lambda (p)
		(set-car! p line-pad)))
	     (p-bool
	      (lambda (obj col objw texts hole cont)
		(let ((text (if obj "#t" "#f")))
		  (cont (+ col 2) (+ objw 2) (cons text texts) hole))))
	     (p-number
	      (lambda (obj col objw texts hole cont)
		(let* ((text (number->string obj))
		       (len (string-length text)))
		  (cont (+ col len) (+ objw len) (cons text texts) hole))))
	     (p-symbol
	      (lambda (obj col objw texts hole cont)
		(let* ((text (symbol->string obj))
		       (len (string-length text)))
		  (cont (+ col len) (+ objw len) (cons text texts) hole))))
	     (p-char
	      (lambda (obj col objw texts hole cont)
		(let* ((text
			(cond ((char=? obj #\space) "#\\space")
			      ((char=? obj #\newline) "#\\newline")
			      (else (string-append "#\\" (string obj)))))
		       (len (string-length text)))
		  (cont (+ col len) (+ objw len) (cons text texts) hole))))
	     (p-list
	      (lambda (obj col objw texts hole cont)
		(p-tail obj (+ col 1) (+ objw 1) (cons "(" texts) hole cont)))
	     (p-vector
	      (lambda (obj col objw texts hole cont)
		(p-list (vector->list obj)
			(+ col 1) (+ objw 1) (cons "#" texts) hole cont)))
	     (p-tail
	      (lambda (obj col objw texts hole cont)
		(if (null? obj)
		    (cont (+ col 1) (+ objw 1) (cons ")" texts) hole)
		    (p-obj (car obj) col objw texts hole
			   (make-cdr-cont obj cont)))))
	     (make-cdr-cont
	      (lambda (obj cont)
		(lambda (col objw texts hole)
		  (cond ((null? (cdr obj))
			 (cont (+ col 1) (+ objw 1) (cons ")" texts) hole))
			((> col out-max-col)
			 (step-line hole)
			 (let ((hole2 (cons " " texts)))
			   (p-cdr obj (+ start objw 1) 0 hole2 hole2 cont)))
			(else
			 (let ((hole2 (cons " " texts)))
			   (p-cdr obj (+ col 1) 0 hole2 hole2 cont)))))))
	     (p-cdr
	      (lambda (obj col objw texts hole cont)
		(if (pair? (cdr obj))
		    (p-tail (cdr obj) col objw texts hole cont)
		    (p-dot col objw texts hole
			   (make-cdr-cont (list #f (cdr obj)) cont)))))
	     (p-dot
	      (lambda (col objw texts hole cont)
		(cont (+ col 1) (+ objw 1) (cons "." texts) hole)))
	     (p-obj
	      (lambda (obj col objw texts hole cont)
		(cond ((boolean? obj)
		       (p-bool obj col objw texts hole cont))
		      ((number? obj)
		       (p-number obj col objw texts hole cont))
		      ((symbol? obj)
		       (p-symbol obj col objw texts hole cont))
		      ((char? obj)
		       (p-char obj col objw texts hole cont))
		      ((or (null? obj) (pair? obj))
		       (p-list obj col objw texts hole cont))
		      ((vector? obj)
		       (p-vector obj col objw texts hole cont))))))
      (p-obj obj start 0 '() (cons #f #f)
	     (lambda (col objw texts hole)
	       (if (> col out-max-col)
		   (step-line hole))
	       (apply string-append (reverse texts)))))))




;
; Fonction pour afficher une table
; Appelle la sous-routine adequate pour le type de fin de table
;

; Affiche la table d'un driver
(define out-print-table
  (lambda (args-alist
	   <<EOF>>-action <<ERROR>>-action rules
	   nl-start no-nl-start arcs-v acc-v
	   port)
    (let* ((filein
	    (cdr (assq 'filein args-alist)))
	   (table-name
	    (cdr (assq 'table-name args-alist)))
	   (pretty?
	    (assq 'pp args-alist))
	   (counters-type
	    (let ((a (assq 'counters args-alist)))
	      (if a (cdr a) 'line)))
	   (counters-param-list
	    (cond ((eq? counters-type 'none)
		   ")")
		  ((eq? counters-type 'line)
		   " yyline)")
		  (else ; 'all
		   " yyline yycolumn yyoffset)")))
	   (counters-param-list-short
	    (if (char=? (string-ref counters-param-list 0) #\space)
		(substring counters-param-list
			   1
			   (string-length counters-param-list))
		counters-param-list))
	   (clean-eof-action
	    (out-clean-action <<EOF>>-action))
	   (clean-error-action
	    (out-clean-action <<ERROR>>-action))
	   (rule-op
	    (lambda (rule) (out-clean-action (get-rule-action rule))))
	   (rules-l
	    (vector->list rules))
	   (clean-actions-l
	    (map rule-op rules-l))
	   (yytext?-l
	    (map get-rule-yytext? rules-l)))

      ; Commentaires prealables
      (display ";" port)
      (newline port)
      (display "; Table generated from the file " port)
      (display filein port)
      (display " by SILex 1.0" port)
      (newline port)
      (display ";" port)
      (newline port)
      (newline port)

      ; Ecrire le debut de la table
      (display "(define " port)
      (display table-name port)
      (newline port)
      (display "  (vector" port)
      (newline port)

      ; Ecrire la description du type de compteurs
      (display "   '" port)
      (write counters-type port)
      (newline port)

      ; Ecrire l'action pour la fin de fichier
      (display "   (lambda (yycontinue yygetc yyungetc)" port)
      (newline port)
      (display "     (lambda (yytext" port)
      (display counters-param-list port)
      (newline port)
      (display clean-eof-action port)
      (display "       ))" port)
      (newline port)

      ; Ecrire l'action pour le cas d'erreur
      (display "   (lambda (yycontinue yygetc yyungetc)" port)
      (newline port)
      (display "     (lambda (yytext" port)
      (display counters-param-list port)
      (newline port)
      (display clean-error-action port)
      (display "       ))" port)
      (newline port)

      ; Ecrire le vecteur des actions des regles ordinaires
      (display "   (vector" port)
      (newline port)
      (let loop ((al clean-actions-l) (yyl yytext?-l))
	(if (pair? al)
	    (let ((yytext? (car yyl)))
	      (display "    " port)
	      (write yytext? port)
	      (newline port)
	      (display "    (lambda (yycontinue yygetc yyungetc)" port)
	      (newline port)
	      (if yytext?
		  (begin
		    (display "      (lambda (yytext" port)
		    (display counters-param-list port))
		  (begin
		    (display "      (lambda (" port)
		    (display counters-param-list-short port)))
	      (newline port)
	      (display (car al) port)
	      (display "        ))" port)
	      (if (pair? (cdr al))
		  (newline port))
	      (loop (cdr al) (cdr yyl)))))
      (display ")" port)
      (newline port)

      ; Ecrire l'automate
      (cond ((assq 'portable args-alist)
	     (out-print-table-chars
	      pretty?
	      nl-start no-nl-start arcs-v acc-v
	      port))
	    ((assq 'code args-alist)
	     (out-print-table-code
	      counters-type (vector-length rules) yytext?-l
	      nl-start no-nl-start arcs-v acc-v
	      port))
	    (else
	     (out-print-table-data
	      pretty?
	      nl-start no-nl-start arcs-v acc-v
	      port))))))

;
; Affiche l'automate sous forme d'arbres de decision
; Termine la table du meme coup
;

(define out-print-table-data
  (lambda (pretty? nl-start no-nl-start arcs-v acc-v port)
    (let* ((len (vector-length arcs-v))
	   (trees-v (make-vector len)))
      (let loop ((i 0))
	(if (< i len)
	    (begin
	      (vector-set! trees-v i (prep-arcs->tree (vector-ref arcs-v i)))
	      (loop (+ i 1)))))

      ; Decrire le format de l'automate
      (display "   'decision-trees" port)
      (newline port)

      ; Ecrire l'etat de depart pour le cas "debut de la ligne"
      (display "   " port)
      (write nl-start port)
      (newline port)

      ; Ecrire l'etat de depart pour le cas "pas au debut de la ligne"
      (display "   " port)
      (write no-nl-start port)
      (newline port)

      ; Ecrire la table de transitions
      (display "   '" port)
      (if pretty?
	  (display (out-pp trees-v 5) port)
	  (display (out-np trees-v 5) port))
      (newline port)

      ; Ecrire la table des acceptations
      (display "   '" port)
      (if pretty?
	  (display (out-pp acc-v 5) port)
	  (display (out-np acc-v 5) port))

      ; Ecrire la fin de la table
      (display "))" port)
      (newline port))))

;
; Affiche l'automate sous forme de listes de caracteres taggees
; Termine la table du meme coup
;

(define out-print-table-chars
  (lambda (pretty? nl-start no-nl-start arcs-v acc-v port)
    (let* ((len (vector-length arcs-v))
	   (portable-v (make-vector len))
	   (arc-op (lambda (arc)
		     (cons (class->tagged-char-list (car arc)) (cdr arc)))))
      (let loop ((s 0))
	(if (< s len)
	    (let* ((arcs (vector-ref arcs-v s))
		   (port-arcs (map arc-op arcs)))
	      (vector-set! portable-v s port-arcs)
	      (loop (+ s 1)))))

      ; Decrire le format de l'automate
      (display "   'tagged-chars-lists" port)
      (newline port)

      ; Ecrire l'etat de depart pour le cas "debut de la ligne"
      (display "   " port)
      (write nl-start port)
      (newline port)

      ; Ecrire l'etat de depart pour le cas "pas au debut de la ligne"
      (display "   " port)
      (write no-nl-start port)
      (newline port)

      ; Ecrire la table de transitions
      (display "   '" port)
      (if pretty?
	  (display (out-pp portable-v 5) port)
	  (display (out-np portable-v 5) port))
      (newline port)

      ; Ecrire la table des acceptations
      (display "   '" port)
      (if pretty?
	  (display (out-pp acc-v 5) port)
	  (display (out-np acc-v 5) port))

      ; Ecrire la fin de la table
      (display "))" port)
      (newline port))))

;
; Genere l'automate en code Scheme
; Termine la table du meme coup
;

(define out-print-code-trans3
  (lambda (margin tree action-var port)
    (newline port)
    (display (out-blanks margin) port)
    (cond ((eq? tree 'err)
	   (display action-var port))
	  ((number? tree)
	   (display "(state-" port)
	   (display tree port)
	   (display " " port)
	   (display action-var port)
	   (display ")" port))
	  ((eq? (car tree) '=)
	   (display "(if (= c " port)
	   (display (list-ref tree 1) port)
	   (display ")" port)
	   (out-print-code-trans3 (+ margin 4)
				  (list-ref tree 2)
				  action-var
				  port)
	   (out-print-code-trans3 (+ margin 4)
				  (list-ref tree 3)
				  action-var
				  port)
	   (display ")" port))
	  (else
	   (display "(if (< c " port)
	   (display (list-ref tree 0) port)
	   (display ")" port)
	   (out-print-code-trans3 (+ margin 4)
				  (list-ref tree 1)
				  action-var
				  port)
	   (out-print-code-trans3 (+ margin 4)
				  (list-ref tree 2)
				  action-var
				  port)
	   (display ")" port)))))

(define out-print-code-trans2
  (lambda (margin tree action-var port)
    (newline port)
    (display (out-blanks margin) port)
    (display "(if c" port)
    (out-print-code-trans3 (+ margin 4) tree action-var port)
    (newline port)
    (display (out-blanks (+ margin 4)) port)
    (display action-var port)
    (display ")" port)))

(define out-print-code-trans1
  (lambda (margin tree action-var port)
    (newline port)
    (display (out-blanks margin) port)
    (if (eq? tree 'err)
	(display action-var port)
	(begin
	  (display "(let ((c (read-char)))" port)
	  (out-print-code-trans2 (+ margin 2) tree action-var port)
	  (display ")" port)))))

(define out-print-table-code
  (lambda (counters nbrules yytext?-l
	   nl-start no-nl-start arcs-v acc-v
	   port)
    (let* ((counters-params
	    (cond ((eq? counters 'none) ")")
		  ((eq? counters 'line) " yyline)")
		  ((eq? counters 'all)  " yyline yycolumn yyoffset)")))
	   (counters-params-short
	    (cond ((eq? counters 'none) ")")
		  ((eq? counters 'line) "yyline)")
		  ((eq? counters 'all)  "yyline yycolumn yyoffset)")))
	   (nbstates (vector-length arcs-v))
	   (trees-v (make-vector nbstates)))
      (let loop ((s 0))
	(if (< s nbstates)
	    (begin
	      (vector-set! trees-v s (prep-arcs->tree (vector-ref arcs-v s)))
	      (loop (+ s 1)))))

      ; Decrire le format de l'automate
      (display "   'code" port)
      (newline port)

      ; Ecrire l'entete de la fonction
      (display "   (lambda (<<EOF>>-pre-action" port)
      (newline port)
      (display "            <<ERROR>>-pre-action" port)
      (newline port)
      (display "            rules-pre-action" port)
      (newline port)
      (display "            IS)" port)
      (newline port)

      ; Ecrire le debut du letrec et les variables d'actions brutes
      (display "     (letrec" port)
      (newline port)
      (display "         ((user-action-<<EOF>> #f)" port)
      (newline port)
      (display "          (user-action-<<ERROR>> #f)" port)
      (newline port)
      (let loop ((i 0))
	(if (< i nbrules)
	    (begin
	      (display "          (user-action-" port)
	      (write i port)
	      (display " #f)" port)
	      (newline port)
	      (loop (+ i 1)))))

      ; Ecrire l'extraction des fonctions du IS
      (display "          (start-go-to-end    " port)
      (display "(cdr (assq 'start-go-to-end IS)))" port)
      (newline port)
      (display "          (end-go-to-point    " port)
      (display "(cdr (assq 'end-go-to-point IS)))" port)
      (newline port)
      (display "          (init-lexeme        " port)
      (display "(cdr (assq 'init-lexeme IS)))" port)
      (newline port)
      (display "          (get-start-line     " port)
      (display "(cdr (assq 'get-start-line IS)))" port)
      (newline port)
      (display "          (get-start-column   " port)
      (display "(cdr (assq 'get-start-column IS)))" port)
      (newline port)
      (display "          (get-start-offset   " port)
      (display "(cdr (assq 'get-start-offset IS)))" port)
      (newline port)
      (display "          (peek-left-context  " port)
      (display "(cdr (assq 'peek-left-context IS)))" port)
      (newline port)
      (display "          (peek-char          " port)
      (display "(cdr (assq 'peek-char IS)))" port)
      (newline port)
      (display "          (read-char          " port)
      (display "(cdr (assq 'read-char IS)))" port)
      (newline port)
      (display "          (get-start-end-text " port)
      (display "(cdr (assq 'get-start-end-text IS)))" port)
      (newline port)
      (display "          (user-getc          " port)
      (display "(cdr (assq 'user-getc IS)))" port)
      (newline port)
      (display "          (user-ungetc        " port)
      (display "(cdr (assq 'user-ungetc IS)))" port)
      (newline port)

      ; Ecrire les variables d'actions
      (display "          (action-<<EOF>>" port)
      (newline port)
      (display "           (lambda (" port)
      (display counters-params-short port)
      (newline port)
      (display "             (user-action-<<EOF>> \"\"" port)
      (display counters-params port)
      (display "))" port)
      (newline port)
      (display "          (action-<<ERROR>>" port)
      (newline port)
      (display "           (lambda (" port)
      (display counters-params-short port)
      (newline port)
      (display "             (user-action-<<ERROR>> \"\"" port)
      (display counters-params port)
      (display "))" port)
      (newline port)
      (let loop ((i 0) (yyl yytext?-l))
	(if (< i nbrules)
	    (begin
	      (display "          (action-" port)
	      (display i port)
	      (newline port)
	      (display "           (lambda (" port)
	      (display counters-params-short port)
	      (newline port)
	      (if (car yyl)
		  (begin
		    (display "             (let ((yytext" port)
		    (display " (get-start-end-text)))" port)
		    (newline port)
		    (display "               (start-go-to-end)" port)
		    (newline port)
		    (display "               (user-action-" port)
		    (display i port)
		    (display " yytext" port)
		    (display counters-params port)
		    (display ")))" port)
		    (newline port))
		  (begin
		    (display "             (start-go-to-end)" port)
		    (newline port)
		    (display "             (user-action-" port)
		    (display i port)
		    (display counters-params port)
		    (display "))" port)
		    (newline port)))
	      (loop (+ i 1) (cdr yyl)))))

      ; Ecrire les variables d'etats
      (let loop ((s 0))
	(if (< s nbstates)
	    (let* ((tree (vector-ref trees-v s))
		   (acc (vector-ref acc-v s))
		   (acc-eol (car acc))
		   (acc-no-eol (cdr acc)))
	      (display "          (state-" port)
	      (display s port)
	      (newline port)
	      (display "           (lambda (action)" port)
	      (cond ((not acc-eol)
		     (out-print-code-trans1 13 tree "action" port))
		    ((not acc-no-eol)
		     (newline port)
		     (if (eq? tree 'err)
			 (display "             (let* ((c (peek-char))" port)
			 (display "             (let* ((c (read-char))" port))
		     (newline port)
		     (display "                    (new-action (if (o" port)
		     (display "r (not c) (= c lexer-integer-newline))" port)
		     (newline port)
		     (display "                                  " port)
		     (display "  (begin (end-go-to-point) action-" port)
		     (display acc-eol port)
		     (display ")" port)
		     (newline port)
		     (display "                       " port)
		     (display "             action)))" port)
		     (if (eq? tree 'err)
			 (out-print-code-trans1 15 tree "new-action" port)
			 (out-print-code-trans2 15 tree "new-action" port))
		     (display ")" port))
		    ((< acc-eol acc-no-eol)
		     (newline port)
		     (display "             (end-go-to-point)" port)
		     (newline port)
		     (if (eq? tree 'err)
			 (display "             (let* ((c (peek-char))" port)
			 (display "             (let* ((c (read-char))" port))
		     (newline port)
		     (display "                    (new-action (if (o" port)
		     (display "r (not c) (= c lexer-integer-newline))" port)
		     (newline port)
		     (display "                      " port)
		     (display "              action-" port)
		     (display acc-eol port)
		     (newline port)
		     (display "                      " port)
		     (display "              action-" port)
		     (display acc-no-eol port)
		     (display ")))" port)
		     (if (eq? tree 'err)
			 (out-print-code-trans1 15 tree "new-action" port)
			 (out-print-code-trans2 15 tree "new-action" port))
		     (display ")" port))
		    (else
		     (let ((action-var
			    (string-append "action-"
					   (number->string acc-eol))))
		       (newline port)
		       (display "             (end-go-to-point)" port)
		       (out-print-code-trans1 13 tree action-var port))))
	      (display "))" port)
	      (newline port)
	      (loop (+ s 1)))))

      ; Ecrire la variable de lancement de l'automate
      (display "          (start-automaton" port)
      (newline port)
      (display "           (lambda ()" port)
      (newline port)
      (if (= nl-start no-nl-start)
	  (begin
	    (display "             (if (peek-char)" port)
	    (newline port)
	    (display "                 (state-" port)
	    (display nl-start port)
	    (display " action-<<ERROR>>)" port)
	    (newline port)
	    (display "                 action-<<EOF>>)" port))
	  (begin
	    (display "             (cond ((not (peek-char))" port)
	    (newline port)
	    (display "                    action-<<EOF>>)" port)
	    (newline port)
	    (display "                   ((= (peek-left-context)" port)
	    (display " lexer-integer-newline)" port)
	    (newline port)
	    (display "                    (state-" port)
	    (display nl-start port)
	    (display " action-<<ERROR>>))" port)
	    (newline port)
	    (display "                   (else" port)
	    (newline port)
	    (display "                    (state-" port)
	    (display no-nl-start port)
	    (display " action-<<ERROR>>)))" port)))
      (display "))" port)
      (newline port)

      ; Ecrire la fonction principale de lexage
      (display "          (final-lexer" port)
      (newline port)
      (display "           (lambda ()" port)
      (newline port)
      (display "             (init-lexeme)" port)
      (newline port)
      (cond ((eq? counters 'none)
	     (display "             ((start-automaton))" port))
	    ((eq? counters 'line)
	     (display "             (let ((yyline (get-start-line)))" port)
	     (newline port)
	     (display "               ((start-automaton) yyline))" port))
	    ((eq? counters 'all)
	     (display "             (let ((yyline (get-start-line))" port)
	     (newline port)
	     (display "                   (yycolumn (get-start-column))" port)
	     (newline port)
	     (display "                   (yyoffset (get-start-offset)))" port)
	     (newline port)
	     (display "               ((start-automat" port)
	     (display "on) yyline yycolumn yyoffset))" port)))
      (display "))" port)

      ; Fermer les bindings du grand letrec
      (display ")" port)
      (newline port)

      ; Initialiser les variables user-action-XX
      (display "       (set! user-action-<<EOF>>" port)
      (display " (<<EOF>>-pre-action" port)
      (newline port)
      (display "                                  final-lexer" port)
      (display " user-getc user-ungetc))" port)
      (newline port)
      (display "       (set! user-action-<<ERROR>>" port)
      (display " (<<ERROR>>-pre-action" port)
      (newline port)
      (display "                                    final-lexer" port)
      (display " user-getc user-ungetc))" port)
      (newline port)
      (let loop ((r 0))
	(if (< r nbrules)
	    (let* ((str-r (number->string r))
		   (blanks (out-blanks (string-length str-r))))
	      (display "       (set! user-action-" port)
	      (display str-r port)
	      (display " ((vector-ref rules-pre-action " port)
	      (display (number->string (+ (* 2 r) 1)) port)
	      (display ")" port)
	      (newline port)
	      (display blanks port)
	      (display "                           final-lexer " port)
	      (display "user-getc user-ungetc))" port)
	      (newline port)
	      (loop (+ r 1)))))

      ; Faire retourner le lexer final et fermer la table au complet
      (display "       final-lexer))))" port)
      (newline port))))

;
; Fonctions necessaires a l'initialisation automatique du lexer
;

(define out-print-driver-functions
  (lambda (args-alist port)
    (let ((counters   (cdr (or (assq 'counters args-alist) '(z . line))))
	  (table-name (cdr (assq 'table-name args-alist))))
      (display ";" port)
      (newline port)
      (display "; User functions" port)
      (newline port)
      (display ";" port)
      (newline port)
      (newline port)
      (display "(define lexer #f)" port)
      (newline port)
      (newline port)
      (if (not (eq? counters 'none))
	  (begin
	    (display "(define lexer-get-line   #f)" port)
	    (newline port)
	    (if (eq? counters 'all)
		(begin
		  (display "(define lexer-get-column #f)" port)
		  (newline port)
		  (display "(define lexer-get-offset #f)" port)
		  (newline port)))))
      (display "(define lexer-getc       #f)" port)
      (newline port)
      (display "(define lexer-ungetc     #f)" port)
      (newline port)
      (newline port)
      (display "(define lexer-init" port)
      (newline port)
      (display "  (lambda (input-type input)" port)
      (newline port)
      (display "    (let ((IS (lexer-make-IS input-type input '" port)
      (write counters port)
      (display ")))" port)
      (newline port)
      (display "      (set! lexer (lexer-make-lexer " port)
      (display table-name port)
      (display " IS))" port)
      (newline port)
      (if (not (eq? counters 'none))
	  (begin
	    (display "      (set! lexer-get-line   (lexer-get-func-line IS))"
		     port)
	    (newline port)
	    (if (eq? counters 'all)
		(begin
		  (display
		   "      (set! lexer-get-column (lexer-get-func-column IS))"
		   port)
		  (newline port)
		  (display
		   "      (set! lexer-get-offset (lexer-get-func-offset IS))"
		   port)
		  (newline port)))))
      (display "      (set! lexer-getc       (lexer-get-func-getc IS))" port)
      (newline port)
      (display "      (set! lexer-ungetc     (lexer-get-func-ungetc IS)))))"
	       port)
      (newline port))))

;
; Fonction principale
; Affiche une table ou un driver complet
;

(define output
  (lambda (args-alist
	   <<EOF>>-action <<ERROR>>-action rules
	   nl-start no-nl-start arcs acc)
    (let* ((fileout          (cdr (assq 'fileout args-alist)))
	   (port             (open-output-file fileout))
	   (complete-driver? (cdr (assq 'complete-driver? args-alist))))
      (if complete-driver?
	  (begin
	    (out-print-run-time-lib port)
	    (newline port)))
      (out-print-table args-alist
		       <<EOF>>-action <<ERROR>>-action rules
		       nl-start no-nl-start arcs acc
		       port)
      (if complete-driver?
	  (begin
	    (newline port)
	    (out-print-driver-functions args-alist port)))
      (close-output-port port))))