; 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))))))