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.

; Le vecteur d'etats contient la table de transition du nfa.
; Chaque entree contient les arcs partant de l'etat correspondant.
; Les arcs sont stockes dans une liste.
; Chaque arc est une paire (class . destination).
; Les caracteres d'une classe sont enumeres par ranges.
; Les ranges sont donnes dans une liste,
;   chaque element etant une paire (debut . fin).
; Le symbole eps peut remplacer une classe.
; L'acceptation est decrite par une paire (acc-if-eol . acc-if-no-eol).

; Quelques variables globales
(define r2n-counter 0)
(define r2n-v-arcs '#(#f))
(define r2n-v-acc '#(#f))
(define r2n-v-len 1)

; Initialisation des variables globales
(define r2n-init
  (lambda ()
    (set! r2n-counter 0)
    (set! r2n-v-arcs (vector '()))
    (set! r2n-v-acc (vector #f))
    (set! r2n-v-len 1)))

; Agrandissement des vecteurs
(define r2n-extend-v
  (lambda ()
    (let* ((new-len (* 2 r2n-v-len))
	   (new-v-arcs (make-vector new-len '()))
	   (new-v-acc (make-vector new-len #f)))
      (let loop ((i 0))
	(if (< i r2n-v-len)
	    (begin
	      (vector-set! new-v-arcs i (vector-ref r2n-v-arcs i))
	      (vector-set! new-v-acc i (vector-ref r2n-v-acc i))
	      (loop (+ i 1)))))
      (set! r2n-v-arcs new-v-arcs)
      (set! r2n-v-acc new-v-acc)
      (set! r2n-v-len new-len))))

; Finalisation des vecteurs
(define r2n-finalize-v
  (lambda ()
    (let* ((new-v-arcs (make-vector r2n-counter))
	   (new-v-acc (make-vector r2n-counter)))
      (let loop ((i 0))
	(if (< i r2n-counter)
	    (begin
	      (vector-set! new-v-arcs i (vector-ref r2n-v-arcs i))
	      (vector-set! new-v-acc i (vector-ref r2n-v-acc i))
	      (loop (+ i 1)))))
      (set! r2n-v-arcs new-v-arcs)
      (set! r2n-v-acc new-v-acc)
      (set! r2n-v-len r2n-counter))))

; Creation d'etat
(define r2n-get-state
  (lambda (acc)
    (if (= r2n-counter r2n-v-len)
	(r2n-extend-v))
    (let ((state r2n-counter))
      (set! r2n-counter (+ r2n-counter 1))
      (vector-set! r2n-v-acc state (or acc (cons #f #f)))
      state)))

; Ajout d'un arc
(define r2n-add-arc
  (lambda (start chars end)
    (vector-set! r2n-v-arcs
		 start
		 (cons (cons chars end) (vector-ref r2n-v-arcs start)))))

; Construction de l'automate a partir des regexp
(define r2n-build-epsilon
  (lambda (re start end)
    (r2n-add-arc start 'eps end)))

(define r2n-build-or
  (lambda (re start end)
    (let ((re1 (get-re-attr1 re))
	  (re2 (get-re-attr2 re)))
      (r2n-build-re re1 start end)
      (r2n-build-re re2 start end))))

(define r2n-build-conc
  (lambda (re start end)
    (let* ((re1 (get-re-attr1 re))
	   (re2 (get-re-attr2 re))
	   (inter (r2n-get-state #f)))
      (r2n-build-re re1 start inter)
      (r2n-build-re re2 inter end))))

(define r2n-build-star
  (lambda (re start end)
    (let* ((re1 (get-re-attr1 re))
	   (inter1 (r2n-get-state #f))
	   (inter2 (r2n-get-state #f)))
      (r2n-add-arc start 'eps inter1)
      (r2n-add-arc inter1 'eps inter2)
      (r2n-add-arc inter2 'eps end)
      (r2n-build-re re1 inter2 inter1))))

(define r2n-build-plus
  (lambda (re start end)
    (let* ((re1 (get-re-attr1 re))
	   (inter1 (r2n-get-state #f))
	   (inter2 (r2n-get-state #f)))
      (r2n-add-arc start 'eps inter1)
      (r2n-add-arc inter2 'eps inter1)
      (r2n-add-arc inter2 'eps end)
      (r2n-build-re re1 inter1 inter2))))

(define r2n-build-question
  (lambda (re start end)
    (let ((re1 (get-re-attr1 re)))
      (r2n-add-arc start 'eps end)
      (r2n-build-re re1 start end))))

(define r2n-build-class
  (lambda (re start end)
    (let ((class (get-re-attr1 re)))
      (r2n-add-arc start class end))))

(define r2n-build-char
  (lambda (re start end)
    (let* ((c (get-re-attr1 re))
	   (class (list (cons c c))))
      (r2n-add-arc start class end))))

(define r2n-build-re
  (let ((sub-function-v (vector r2n-build-epsilon
				r2n-build-or
				r2n-build-conc
				r2n-build-star
				r2n-build-plus
				r2n-build-question
				r2n-build-class
				r2n-build-char)))
    (lambda (re start end)
      (let* ((re-type (get-re-type re))
	     (sub-f (vector-ref sub-function-v re-type)))
	(sub-f re start end)))))

; Construction de l'automate relatif a une regle
(define r2n-build-rule
  (lambda (rule ruleno nl-start no-nl-start)
    (let* ((re (get-rule-regexp rule))
	   (bol? (get-rule-bol? rule))
	   (eol? (get-rule-eol? rule))
	   (rule-start (r2n-get-state #f))
	   (rule-end (r2n-get-state (if eol?
					(cons ruleno #f)
					(cons ruleno ruleno)))))
      (r2n-build-re re rule-start rule-end)
      (r2n-add-arc nl-start 'eps rule-start)
      (if (not bol?)
	  (r2n-add-arc no-nl-start 'eps rule-start)))))

; Construction de l'automate complet
(define re2nfa
  (lambda (rules)
    (let ((nb-of-rules (vector-length rules)))
      (r2n-init)
      (let* ((nl-start (r2n-get-state #f))
	     (no-nl-start (r2n-get-state #f)))
	(let loop ((i 0))
	  (if (< i nb-of-rules)
	      (begin
		(r2n-build-rule (vector-ref rules i)
				i
				nl-start
				no-nl-start)
		(loop (+ i 1)))))
	(r2n-finalize-v)
	(let ((v-arcs r2n-v-arcs)
	      (v-acc r2n-v-acc))
	  (r2n-init)
	  (list nl-start no-nl-start v-arcs v-acc))))))