refactor into racket/base
parent
fc1e00bc2a
commit
fd446e6013
@ -1,242 +1,240 @@
|
|||||||
|
#lang racket/base
|
||||||
;; This implements the equivalent of racket's read-syntax for R5RS scheme.
|
;; This implements the equivalent of racket's read-syntax for R5RS scheme.
|
||||||
;; It has not been thoroughly tested. Also it will read an entire file into a
|
;; It has not been thoroughly tested. Also it will read an entire file into a
|
||||||
;; list of syntax objects, instead of returning one syntax object at a time
|
;; list of syntax objects, instead of returning one syntax object at a time
|
||||||
|
|
||||||
(module read mzscheme
|
(require (for-syntax racket/base)
|
||||||
|
br-parser-tools/lex
|
||||||
(require br-parser-tools/lex
|
(prefix-in : br-parser-tools/lex-sre)
|
||||||
(prefix : br-parser-tools/lex-sre)
|
br-parser-tools/yacc
|
||||||
br-parser-tools/yacc
|
syntax/readerr)
|
||||||
syntax/readerr)
|
|
||||||
|
(define-tokens data (DATUM))
|
||||||
(define-tokens data (DATUM))
|
(define-empty-tokens delim (OP CP HASHOP QUOTE QUASIQUOTE UNQUOTE UNQUOTE-SPLICING DOT EOF))
|
||||||
(define-empty-tokens delim (OP CP HASHOP QUOTE QUASIQUOTE UNQUOTE UNQUOTE-SPLICING DOT EOF))
|
|
||||||
|
(define scheme-lexer
|
||||||
(define scheme-lexer
|
(lexer-src-pos
|
||||||
(lexer-src-pos
|
|
||||||
|
;; Skip comments, without accumulating extra position information
|
||||||
;; Skip comments, without accumulating extra position information
|
[(:or scheme-whitespace comment) (return-without-pos (scheme-lexer input-port))]
|
||||||
[(:or scheme-whitespace comment) (return-without-pos (scheme-lexer input-port))]
|
|
||||||
|
["#t" (token-DATUM #t)]
|
||||||
["#t" (token-DATUM #t)]
|
["#f" (token-DATUM #f)]
|
||||||
["#f" (token-DATUM #f)]
|
[(:: "#\\" any-char) (token-DATUM (caddr (string->list lexeme)))]
|
||||||
[(:: "#\\" any-char) (token-DATUM (caddr (string->list lexeme)))]
|
["#\\space" (token-DATUM #\space)]
|
||||||
["#\\space" (token-DATUM #\space)]
|
["#\\newline" (token-DATUM #\newline)]
|
||||||
["#\\newline" (token-DATUM #\newline)]
|
[(:or (:: initial (:* subsequent)) "+" "-" "...") (token-DATUM (string->symbol lexeme))]
|
||||||
[(:or (:: initial (:* subsequent)) "+" "-" "...") (token-DATUM (string->symbol lexeme))]
|
[#\" (token-DATUM (list->string (get-string-token input-port)))]
|
||||||
[#\" (token-DATUM (list->string (get-string-token input-port)))]
|
[#\( 'OP]
|
||||||
[#\( 'OP]
|
[#\) 'CP]
|
||||||
[#\) 'CP]
|
[#\[ 'OP]
|
||||||
[#\[ 'OP]
|
[#\] 'CP]
|
||||||
[#\] 'CP]
|
["#(" 'HASHOP]
|
||||||
["#(" 'HASHOP]
|
[num2 (token-DATUM (string->number lexeme 2))]
|
||||||
[num2 (token-DATUM (string->number lexeme 2))]
|
[num8 (token-DATUM (string->number lexeme 8))]
|
||||||
[num8 (token-DATUM (string->number lexeme 8))]
|
[num10 (token-DATUM (string->number lexeme 10))]
|
||||||
[num10 (token-DATUM (string->number lexeme 10))]
|
[num16 (token-DATUM (string->number lexeme 16))]
|
||||||
[num16 (token-DATUM (string->number lexeme 16))]
|
["'" 'QUOTE]
|
||||||
["'" 'QUOTE]
|
["`" 'QUASIQUOTE]
|
||||||
["`" 'QUASIQUOTE]
|
["," 'UNQUOTE]
|
||||||
["," 'UNQUOTE]
|
[",@" 'UNQUOTE-SPLICING]
|
||||||
[",@" 'UNQUOTE-SPLICING]
|
["." 'DOT]
|
||||||
["." 'DOT]
|
[(eof) 'EOF]))
|
||||||
[(eof) 'EOF]))
|
|
||||||
|
(define get-string-token
|
||||||
(define get-string-token
|
(lexer
|
||||||
(lexer
|
[(:~ #\" #\\) (cons (car (string->list lexeme))
|
||||||
[(:~ #\" #\\) (cons (car (string->list lexeme))
|
(get-string-token input-port))]
|
||||||
(get-string-token input-port))]
|
[(:: #\\ #\\) (cons #\\ (get-string-token input-port))]
|
||||||
[(:: #\\ #\\) (cons #\\ (get-string-token input-port))]
|
[(:: #\\ #\") (cons #\" (get-string-token input-port))]
|
||||||
[(:: #\\ #\") (cons #\" (get-string-token input-port))]
|
[#\" null]))
|
||||||
[#\" null]))
|
|
||||||
|
|
||||||
|
(define-lex-abbrevs
|
||||||
(define-lex-abbrevs
|
[letter (:or (:/ "a" "z") (:/ #\A #\Z))]
|
||||||
[letter (:or (:/ "a" "z") (:/ #\A #\Z))]
|
[digit (:/ #\0 #\9)]
|
||||||
[digit (:/ #\0 #\9)]
|
[scheme-whitespace (:or #\newline #\return #\tab #\space #\vtab)]
|
||||||
[scheme-whitespace (:or #\newline #\return #\tab #\space #\vtab)]
|
[initial (:or letter (char-set "!$%&*/:<=>?^_~@"))]
|
||||||
[initial (:or letter (char-set "!$%&*/:<=>?^_~@"))]
|
[subsequent (:or initial digit (char-set "+-.@"))]
|
||||||
[subsequent (:or initial digit (char-set "+-.@"))]
|
[comment (:: #\; (:* (:~ #\newline)) #\newline)]
|
||||||
[comment (:: #\; (:* (:~ #\newline)) #\newline)]
|
|
||||||
|
|
||||||
|
;; See ${PLTHOME}/collects/syntax-color/racket-lexer.rkt for an example of
|
||||||
;; See ${PLTHOME}/collects/syntax-color/racket-lexer.rkt for an example of
|
;; using regexp macros to avoid the cut and paste.
|
||||||
;; using regexp macros to avoid the cut and paste.
|
; [numR (:: prefixR complexR)]
|
||||||
; [numR (:: prefixR complexR)]
|
; [complexR (:or realR
|
||||||
; [complexR (:or realR
|
; (:: realR "@" realR)
|
||||||
; (:: realR "@" realR)
|
; (:: realR "+" urealR "i")
|
||||||
; (:: realR "+" urealR "i")
|
; (:: realR "-" urealR "i")
|
||||||
; (:: realR "-" urealR "i")
|
; (:: realR "+i")
|
||||||
; (:: realR "+i")
|
; (:: realR "-i")
|
||||||
; (:: realR "-i")
|
; (:: "+" urealR "i")
|
||||||
; (:: "+" urealR "i")
|
; (:: "-" urealR "i")
|
||||||
; (:: "-" urealR "i")
|
; (:: "+i")
|
||||||
; (:: "+i")
|
; (:: "-i"))]
|
||||||
; (:: "-i"))]
|
; [realR (:: sign urealR)]
|
||||||
; [realR (:: sign urealR)]
|
; [urealR (:or uintegerR (:: uintegerR "/" uintegerR) decimalR)]
|
||||||
; [urealR (:or uintegerR (:: uintegerR "/" uintegerR) decimalR)]
|
; [uintegerR (:: (:+ digitR) (:* #\#))]
|
||||||
; [uintegerR (:: (:+ digitR) (:* #\#))]
|
; [prefixR (:or (:: radixR exactness)
|
||||||
; [prefixR (:or (:: radixR exactness)
|
; (:: exactness radixR))]
|
||||||
; (:: exactness radixR))]
|
|
||||||
|
[num2 (:: prefix2 complex2)]
|
||||||
[num2 (:: prefix2 complex2)]
|
[complex2 (:or real2
|
||||||
[complex2 (:or real2
|
(:: real2 "@" real2)
|
||||||
(:: real2 "@" real2)
|
(:: real2 "+" ureal2 "i")
|
||||||
(:: real2 "+" ureal2 "i")
|
(:: real2 "-" ureal2 "i")
|
||||||
(:: real2 "-" ureal2 "i")
|
(:: real2 "+i")
|
||||||
(:: real2 "+i")
|
(:: real2 "-i")
|
||||||
(:: real2 "-i")
|
(:: "+" ureal2 "i")
|
||||||
(:: "+" ureal2 "i")
|
(:: "-" ureal2 "i")
|
||||||
(:: "-" ureal2 "i")
|
(:: "+i")
|
||||||
|
(:: "-i"))]
|
||||||
|
[real2 (:: sign ureal2)]
|
||||||
|
[ureal2 (:or uinteger2 (:: uinteger2 "/" uinteger2))]
|
||||||
|
[uinteger2 (:: (:+ digit2) (:* #\#))]
|
||||||
|
[prefix2 (:or (:: radix2 exactness)
|
||||||
|
(:: exactness radix2))]
|
||||||
|
[radix2 "#b"]
|
||||||
|
[digit2 (:or "0" "1")]
|
||||||
|
[num8 (:: prefix8 complex8)]
|
||||||
|
[complex8 (:or real8
|
||||||
|
(:: real8 "@" real8)
|
||||||
|
(:: real8 "+" ureal8 "i")
|
||||||
|
(:: real8 "-" ureal8 "i")
|
||||||
|
(:: real8 "+i")
|
||||||
|
(:: real8 "-i")
|
||||||
|
(:: "+" ureal8 "i")
|
||||||
|
(:: "-" ureal8 "i")
|
||||||
|
(:: "+i")
|
||||||
|
(:: "-i"))]
|
||||||
|
[real8 (:: sign ureal8)]
|
||||||
|
[ureal8 (:or uinteger8 (:: uinteger8 "/" uinteger8))]
|
||||||
|
[uinteger8 (:: (:+ digit8) (:* #\#))]
|
||||||
|
[prefix8 (:or (:: radix8 exactness)
|
||||||
|
(:: exactness radix8))]
|
||||||
|
[radix8 "#o"]
|
||||||
|
[digit8 (:/ "0" "7")]
|
||||||
|
|
||||||
|
[num10 (:: prefix10 complex10)]
|
||||||
|
[complex10 (:or real10
|
||||||
|
(:: real10 "@" real10)
|
||||||
|
(:: real10 "+" ureal10 "i")
|
||||||
|
(:: real10 "-" ureal10 "i")
|
||||||
|
(:: real10 "+i")
|
||||||
|
(:: real10 "-i")
|
||||||
|
(:: "+" ureal10 "i")
|
||||||
|
(:: "-" ureal10 "i")
|
||||||
(:: "+i")
|
(:: "+i")
|
||||||
(:: "-i"))]
|
(:: "-i"))]
|
||||||
[real2 (:: sign ureal2)]
|
[real10 (:: sign ureal10)]
|
||||||
[ureal2 (:or uinteger2 (:: uinteger2 "/" uinteger2))]
|
[ureal10 (:or uinteger10 (:: uinteger10 "/" uinteger10) decimal10)]
|
||||||
[uinteger2 (:: (:+ digit2) (:* #\#))]
|
[uinteger10 (:: (:+ digit10) (:* #\#))]
|
||||||
[prefix2 (:or (:: radix2 exactness)
|
[prefix10 (:or (:: radix10 exactness)
|
||||||
(:: exactness radix2))]
|
(:: exactness radix10))]
|
||||||
[radix2 "#b"]
|
[radix10 (:? "#d")]
|
||||||
[digit2 (:or "0" "1")]
|
[digit10 digit]
|
||||||
[num8 (:: prefix8 complex8)]
|
[decimal10 (:or (:: uinteger10 suffix)
|
||||||
[complex8 (:or real8
|
(:: #\. (:+ digit10) (:* #\#) suffix)
|
||||||
(:: real8 "@" real8)
|
(:: (:+ digit10) #\. (:* digit10) (:* #\#) suffix)
|
||||||
(:: real8 "+" ureal8 "i")
|
(:: (:+ digit10) (:+ #\#) #\. (:* #\#) suffix))]
|
||||||
(:: real8 "-" ureal8 "i")
|
|
||||||
(:: real8 "+i")
|
[num16 (:: prefix16 complex16)]
|
||||||
(:: real8 "-i")
|
[complex16 (:or real16
|
||||||
(:: "+" ureal8 "i")
|
(:: real16 "@" real16)
|
||||||
(:: "-" ureal8 "i")
|
(:: real16 "+" ureal16 "i")
|
||||||
(:: "+i")
|
(:: real16 "-" ureal16 "i")
|
||||||
(:: "-i"))]
|
(:: real16 "+i")
|
||||||
[real8 (:: sign ureal8)]
|
(:: real16 "-i")
|
||||||
[ureal8 (:or uinteger8 (:: uinteger8 "/" uinteger8))]
|
(:: "+" ureal16 "i")
|
||||||
[uinteger8 (:: (:+ digit8) (:* #\#))]
|
(:: "-" ureal16 "i")
|
||||||
[prefix8 (:or (:: radix8 exactness)
|
"+i"
|
||||||
(:: exactness radix8))]
|
"-i")]
|
||||||
[radix8 "#o"]
|
[real16 (:: sign ureal16)]
|
||||||
[digit8 (:/ "0" "7")]
|
[ureal16 (:or uinteger16 (:: uinteger16 "/" uinteger16))]
|
||||||
|
[uinteger16 (:: (:+ digit16) (:* #\#))]
|
||||||
[num10 (:: prefix10 complex10)]
|
[prefix16 (:or (:: radix16 exactness)
|
||||||
[complex10 (:or real10
|
(:: exactness radix16))]
|
||||||
(:: real10 "@" real10)
|
[radix16 "#x"]
|
||||||
(:: real10 "+" ureal10 "i")
|
[digit16 (:or digit (:/ #\a #\f) (:/ #\A #\F))]
|
||||||
(:: real10 "-" ureal10 "i")
|
|
||||||
(:: real10 "+i")
|
|
||||||
(:: real10 "-i")
|
[suffix (:or "" (:: exponent-marker sign (:+ digit10)))]
|
||||||
(:: "+" ureal10 "i")
|
[exponent-marker (:or "e" "s" "f" "d" "l")]
|
||||||
(:: "-" ureal10 "i")
|
[sign (:or "" "+" "-")]
|
||||||
(:: "+i")
|
[exactness (:or "" "#i" "#e")])
|
||||||
(:: "-i"))]
|
|
||||||
[real10 (:: sign ureal10)]
|
|
||||||
[ureal10 (:or uinteger10 (:: uinteger10 "/" uinteger10) decimal10)]
|
(define stx-for-original-property (read-syntax #f (open-input-string "original")))
|
||||||
[uinteger10 (:: (:+ digit10) (:* #\#))]
|
|
||||||
[prefix10 (:or (:: radix10 exactness)
|
;; A macro to build the syntax object
|
||||||
(:: exactness radix10))]
|
(define-syntax (build-so stx)
|
||||||
[radix10 (:? "#d")]
|
(syntax-case stx ()
|
||||||
[digit10 digit]
|
((_ value start end)
|
||||||
[decimal10 (:or (:: uinteger10 suffix)
|
(with-syntax ((start-pos (datum->syntax
|
||||||
(:: #\. (:+ digit10) (:* #\#) suffix)
|
#'end
|
||||||
(:: (:+ digit10) #\. (:* digit10) (:* #\#) suffix)
|
|
||||||
(:: (:+ digit10) (:+ #\#) #\. (:* #\#) suffix))]
|
|
||||||
|
|
||||||
[num16 (:: prefix16 complex16)]
|
|
||||||
[complex16 (:or real16
|
|
||||||
(:: real16 "@" real16)
|
|
||||||
(:: real16 "+" ureal16 "i")
|
|
||||||
(:: real16 "-" ureal16 "i")
|
|
||||||
(:: real16 "+i")
|
|
||||||
(:: real16 "-i")
|
|
||||||
(:: "+" ureal16 "i")
|
|
||||||
(:: "-" ureal16 "i")
|
|
||||||
"+i"
|
|
||||||
"-i")]
|
|
||||||
[real16 (:: sign ureal16)]
|
|
||||||
[ureal16 (:or uinteger16 (:: uinteger16 "/" uinteger16))]
|
|
||||||
[uinteger16 (:: (:+ digit16) (:* #\#))]
|
|
||||||
[prefix16 (:or (:: radix16 exactness)
|
|
||||||
(:: exactness radix16))]
|
|
||||||
[radix16 "#x"]
|
|
||||||
[digit16 (:or digit (:/ #\a #\f) (:/ #\A #\F))]
|
|
||||||
|
|
||||||
|
|
||||||
[suffix (:or "" (:: exponent-marker sign (:+ digit10)))]
|
|
||||||
[exponent-marker (:or "e" "s" "f" "d" "l")]
|
|
||||||
[sign (:or "" "+" "-")]
|
|
||||||
[exactness (:or "" "#i" "#e")])
|
|
||||||
|
|
||||||
|
|
||||||
(define stx-for-original-property (read-syntax #f (open-input-string "original")))
|
|
||||||
|
|
||||||
;; A macro to build the syntax object
|
|
||||||
(define-syntax (build-so stx)
|
|
||||||
(syntax-case stx ()
|
|
||||||
((_ value start end)
|
|
||||||
(with-syntax ((start-pos (datum->syntax-object
|
|
||||||
(syntax end)
|
|
||||||
(string->symbol
|
|
||||||
(format "$~a-start-pos"
|
|
||||||
(syntax-object->datum (syntax start))))))
|
|
||||||
(end-pos (datum->syntax-object
|
|
||||||
(syntax end)
|
|
||||||
(string->symbol
|
(string->symbol
|
||||||
(format "$~a-end-pos"
|
(format "$~a-start-pos"
|
||||||
(syntax-object->datum (syntax end))))))
|
(syntax->datum #'start)))))
|
||||||
(source (datum->syntax-object
|
(end-pos (datum->syntax
|
||||||
(syntax end)
|
#'end
|
||||||
'source-name)))
|
(string->symbol
|
||||||
(syntax
|
(format "$~a-end-pos"
|
||||||
(datum->syntax-object
|
(syntax->datum #'end)))))
|
||||||
#f
|
(source (datum->syntax
|
||||||
value
|
#'end
|
||||||
(list source
|
'source-name)))
|
||||||
(position-line start-pos)
|
(syntax
|
||||||
(position-col start-pos)
|
(datum->syntax
|
||||||
(position-offset start-pos)
|
#f
|
||||||
(- (position-offset end-pos)
|
value
|
||||||
(position-offset start-pos)))
|
(list source
|
||||||
stx-for-original-property))))))
|
(position-line start-pos)
|
||||||
|
(position-col start-pos)
|
||||||
(define (scheme-parser source-name)
|
(position-offset start-pos)
|
||||||
(parser
|
(- (position-offset end-pos)
|
||||||
(src-pos)
|
(position-offset start-pos)))
|
||||||
|
stx-for-original-property))))))
|
||||||
(start s)
|
|
||||||
(end EOF)
|
(define (scheme-parser source-name)
|
||||||
(error (lambda (a name val start end)
|
(parser
|
||||||
(raise-read-error
|
(src-pos)
|
||||||
"read-error"
|
|
||||||
source-name
|
(start s)
|
||||||
(position-line start)
|
(end EOF)
|
||||||
(position-col start)
|
(error (lambda (a name val start end)
|
||||||
(position-offset start)
|
(raise-read-error
|
||||||
(- (position-offset end)
|
"read-error"
|
||||||
(position-offset start)))))
|
source-name
|
||||||
(tokens data delim)
|
(position-line start)
|
||||||
|
(position-col start)
|
||||||
|
(position-offset start)
|
||||||
(grammar
|
(- (position-offset end)
|
||||||
|
(position-offset start)))))
|
||||||
(s [(sexp-list) (reverse $1)])
|
(tokens data delim)
|
||||||
|
|
||||||
(sexp [(DATUM) (build-so $1 1 1)]
|
|
||||||
[(OP sexp-list CP) (build-so (reverse $2) 1 3)]
|
(grammar
|
||||||
[(HASHOP sexp-list CP) (build-so (list->vector (reverse $2)) 1 3)]
|
|
||||||
[(QUOTE sexp) (build-so (list 'quote $2) 1 2)]
|
(s [(sexp-list) (reverse $1)])
|
||||||
[(QUASIQUOTE sexp) (build-so (list 'quasiquote $2) 1 2)]
|
|
||||||
[(UNQUOTE sexp) (build-so (list 'unquote $2) 1 2)]
|
(sexp [(DATUM) (build-so $1 1 1)]
|
||||||
[(UNQUOTE-SPLICING sexp) (build-so (list 'unquote-splicing $2) 1 2)]
|
[(OP sexp-list CP) (build-so (reverse $2) 1 3)]
|
||||||
[(OP sexp-list DOT sexp CP) (build-so (append (reverse $2) $4) 1 5)])
|
[(HASHOP sexp-list CP) (build-so (list->vector (reverse $2)) 1 3)]
|
||||||
|
[(QUOTE sexp) (build-so (list 'quote $2) 1 2)]
|
||||||
(sexp-list [() null]
|
[(QUASIQUOTE sexp) (build-so (list 'quasiquote $2) 1 2)]
|
||||||
[(sexp-list sexp) (cons $2 $1)]))))
|
[(UNQUOTE sexp) (build-so (list 'unquote $2) 1 2)]
|
||||||
|
[(UNQUOTE-SPLICING sexp) (build-so (list 'unquote-splicing $2) 1 2)]
|
||||||
(define (rs sn ip)
|
[(OP sexp-list DOT sexp CP) (build-so (append (reverse $2) $4) 1 5)])
|
||||||
(port-count-lines! ip)
|
|
||||||
((scheme-parser sn) (lambda () (scheme-lexer ip))))
|
(sexp-list [() null]
|
||||||
|
[(sexp-list sexp) (cons $2 $1)]))))
|
||||||
(define readsyntax
|
|
||||||
(case-lambda ((sn) (rs sn (current-input-port)))
|
(define (rs sn ip)
|
||||||
((sn ip) (rs sn ip))))
|
(port-count-lines! ip)
|
||||||
|
((scheme-parser sn) (lambda () (scheme-lexer ip))))
|
||||||
(provide (rename readsyntax read-syntax))
|
|
||||||
|
(define readsyntax
|
||||||
)
|
(case-lambda ((sn) (rs sn (current-input-port)))
|
||||||
|
((sn ip) (rs sn ip))))
|
||||||
|
|
||||||
|
(provide (rename-out [readsyntax read-syntax]))
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
(module lex-plt-v200 mzscheme
|
#lang racket/base
|
||||||
(require br-parser-tools/lex
|
(require (for-syntax racket/base)
|
||||||
(prefix : br-parser-tools/lex-sre))
|
br-parser-tools/lex
|
||||||
|
(prefix-in : br-parser-tools/lex-sre))
|
||||||
|
|
||||||
(provide epsilon
|
(provide epsilon ~
|
||||||
~
|
(rename-out [:* *]
|
||||||
(rename :* *)
|
[:+ +]
|
||||||
(rename :+ +)
|
[:? ?]
|
||||||
(rename :? ?)
|
[:or :]
|
||||||
(rename :or :)
|
[:& &]
|
||||||
(rename :& &)
|
[:: @]
|
||||||
(rename :: @)
|
[:~ ^]
|
||||||
(rename :~ ^)
|
[:/ -]))
|
||||||
(rename :/ -))
|
|
||||||
|
|
||||||
(define-lex-trans epsilon
|
(define-lex-trans (epsilon stx)
|
||||||
(syntax-rules ()
|
(syntax-case stx ()
|
||||||
((_) "")))
|
[(_) #'""]))
|
||||||
|
|
||||||
(define-lex-trans ~
|
|
||||||
(syntax-rules ()
|
|
||||||
((_ re) (complement re)))))
|
|
||||||
|
|
||||||
|
(define-lex-trans (~ stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ RE) #'(complement RE)]))
|
||||||
|
|
||||||
|
@ -1,119 +1,103 @@
|
|||||||
(module lex-sre mzscheme
|
#lang racket/base
|
||||||
(require br-parser-tools/lex)
|
(require (for-syntax racket/base)
|
||||||
|
br-parser-tools/lex)
|
||||||
(provide (rename sre-* *)
|
|
||||||
(rename sre-+ +)
|
(provide (rename-out [sre-* *]
|
||||||
?
|
[sre-+ +]
|
||||||
(rename sre-= =)
|
[sre-= =]
|
||||||
(rename sre->= >=)
|
[sre->= >=]
|
||||||
**
|
[sre-or or]
|
||||||
(rename sre-or or)
|
[sre-- -]
|
||||||
:
|
[sre-/ /])
|
||||||
seq
|
? ** : seq & ~ /-only-chars)
|
||||||
&
|
|
||||||
~
|
(define-lex-trans (sre-* stx)
|
||||||
(rename sre-- -)
|
(syntax-case stx ()
|
||||||
(rename sre-/ /)
|
[(_ RE ...)
|
||||||
/-only-chars)
|
#'(repetition 0 +inf.0 (union RE ...))]))
|
||||||
|
|
||||||
(define-lex-trans sre-*
|
(define-lex-trans (sre-+ stx)
|
||||||
(syntax-rules ()
|
(syntax-case stx ()
|
||||||
((_ re ...)
|
[(_ RE ...)
|
||||||
(repetition 0 +inf.0 (union re ...)))))
|
#'(repetition 1 +inf.0 (union RE ...))]))
|
||||||
|
|
||||||
(define-lex-trans sre-+
|
(define-lex-trans (? stx)
|
||||||
(syntax-rules ()
|
(syntax-case stx ()
|
||||||
((_ re ...)
|
[(_ RE ...)
|
||||||
(repetition 1 +inf.0 (union re ...)))))
|
#'(repetition 0 1 (union RE ...))]))
|
||||||
|
|
||||||
(define-lex-trans ?
|
(define-lex-trans (sre-= stx)
|
||||||
(syntax-rules ()
|
(syntax-case stx ()
|
||||||
((_ re ...)
|
[(_ N RE ...)
|
||||||
(repetition 0 1 (union re ...)))))
|
#'(repetition N N (union RE ...))]))
|
||||||
|
|
||||||
(define-lex-trans sre-=
|
(define-lex-trans (sre->= stx)
|
||||||
(syntax-rules ()
|
(syntax-case stx ()
|
||||||
((_ n re ...)
|
[(_ N RE ...)
|
||||||
(repetition n n (union re ...)))))
|
#'(repetition N +inf.0 (union RE ...))]))
|
||||||
|
|
||||||
(define-lex-trans sre->=
|
(define-lex-trans (** stx)
|
||||||
(syntax-rules ()
|
(syntax-case stx ()
|
||||||
((_ n re ...)
|
[(_ LOW #f RE ...)
|
||||||
(repetition n +inf.0 (union re ...)))))
|
#'(** LOW +inf.0 RE ...)]
|
||||||
|
[(_ LOW HIGH RE ...)
|
||||||
(define-lex-trans **
|
#'(repetition LOW HIGH (union RE ...))]))
|
||||||
(syntax-rules ()
|
|
||||||
((_ low #f re ...)
|
(define-lex-trans (sre-or stx)
|
||||||
(** low +inf.0 re ...))
|
(syntax-case stx ()
|
||||||
((_ low high re ...)
|
[(_ RE ...)
|
||||||
(repetition low high (union re ...)))))
|
#'(union RE ...)]))
|
||||||
|
|
||||||
(define-lex-trans sre-or
|
(define-lex-trans (: stx)
|
||||||
(syntax-rules ()
|
(syntax-case stx ()
|
||||||
((_ re ...)
|
[(_ RE ...)
|
||||||
(union re ...))))
|
#'(concatenation RE ...)]))
|
||||||
|
|
||||||
(define-lex-trans :
|
(define-lex-trans (seq stx)
|
||||||
(syntax-rules ()
|
(syntax-case stx ()
|
||||||
((_ re ...)
|
[(_ RE ...)
|
||||||
(concatenation re ...))))
|
#'(concatenation RE ...)]))
|
||||||
|
|
||||||
(define-lex-trans seq
|
(define-lex-trans (& stx)
|
||||||
(syntax-rules ()
|
(syntax-case stx ()
|
||||||
((_ re ...)
|
[(_ RE ...)
|
||||||
(concatenation re ...))))
|
#'(intersection RE ...)]))
|
||||||
|
|
||||||
(define-lex-trans &
|
(define-lex-trans (~ stx)
|
||||||
(syntax-rules ()
|
(syntax-case stx ()
|
||||||
((_ re ...)
|
[(_ RE ...)
|
||||||
(intersection re ...))))
|
#'(char-complement (union RE ...))]))
|
||||||
|
|
||||||
(define-lex-trans ~
|
;; set difference
|
||||||
(syntax-rules ()
|
(define-lex-trans (sre-- stx)
|
||||||
((_ re ...)
|
(syntax-case stx ()
|
||||||
(char-complement (union re ...)))))
|
[(_)
|
||||||
|
(raise-syntax-error #f
|
||||||
;; set difference
|
"must have at least one argument"
|
||||||
(define-lex-trans (sre-- stx)
|
stx)]
|
||||||
(syntax-case stx ()
|
[(_ BIG-RE RE ...)
|
||||||
((_)
|
#'(& BIG-RE (complement (union RE ...)))]))
|
||||||
(raise-syntax-error #f
|
|
||||||
"must have at least one argument"
|
(define-lex-trans (sre-/ stx)
|
||||||
stx))
|
(syntax-case stx ()
|
||||||
((_ big-re re ...)
|
[(_ RANGE ...)
|
||||||
(syntax (& big-re (complement (union re ...)))))))
|
(let ([chars
|
||||||
|
(apply append (for/list ([r (in-list (syntax->list #'(RANGE ...)))])
|
||||||
(define-lex-trans (sre-/ stx)
|
(let ([x (syntax-e r)])
|
||||||
(syntax-case stx ()
|
(cond
|
||||||
((_ range ...)
|
[(char? x) (list x)]
|
||||||
(let ((chars
|
[(string? x) (string->list x)]
|
||||||
(apply append (map (lambda (r)
|
[else
|
||||||
(let ((x (syntax-e r)))
|
(raise-syntax-error #f "not a char or string" stx r)]))))])
|
||||||
(cond
|
(unless (even? (length chars))
|
||||||
((char? x) (list x))
|
(raise-syntax-error #f "not given an even number of characters" stx))
|
||||||
((string? x) (string->list x))
|
#`(/-only-chars #,@chars))]))
|
||||||
(else
|
|
||||||
(raise-syntax-error
|
(define-lex-trans (/-only-chars stx)
|
||||||
#f
|
(syntax-case stx ()
|
||||||
"not a char or string"
|
[(_ C1 C2)
|
||||||
stx
|
#'(char-range C1 C2)]
|
||||||
r)))))
|
[(_ C1 C2 C ...)
|
||||||
(syntax->list (syntax (range ...)))))))
|
#'(union (char-range C1 C2) (/-only-chars C ...))]))
|
||||||
(unless (even? (length chars))
|
|
||||||
(raise-syntax-error
|
|
||||||
#f
|
|
||||||
"not given an even number of characters"
|
|
||||||
stx))
|
|
||||||
#`(/-only-chars #,@chars)))))
|
|
||||||
|
|
||||||
(define-lex-trans /-only-chars
|
|
||||||
(syntax-rules ()
|
|
||||||
((_ c1 c2)
|
|
||||||
(char-range c1 c2))
|
|
||||||
((_ c1 c2 c ...)
|
|
||||||
(union (char-range c1 c2)
|
|
||||||
(/-only-chars c ...)))))
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
(module token-syntax mzscheme
|
#lang racket/base
|
||||||
|
(provide make-terminals-def terminals-def-t terminals-def?
|
||||||
|
make-e-terminals-def e-terminals-def-t e-terminals-def?)
|
||||||
|
|
||||||
;; The things needed at compile time to handle definition of tokens
|
;; The things needed at compile time to handle definition of tokens
|
||||||
|
(define-struct terminals-def (t))
|
||||||
(provide make-terminals-def terminals-def-t terminals-def?
|
(define-struct e-terminals-def (t))
|
||||||
make-e-terminals-def e-terminals-def-t e-terminals-def?)
|
|
||||||
(define-struct terminals-def (t))
|
|
||||||
(define-struct e-terminals-def (t))
|
|
||||||
)
|
|
||||||
|
@ -1,92 +1,80 @@
|
|||||||
(module token mzscheme
|
#lang racket/base
|
||||||
|
(require (for-syntax racket/base "token-syntax.rkt"))
|
||||||
|
|
||||||
(require-for-syntax "token-syntax.rkt")
|
;; Defining tokens
|
||||||
|
|
||||||
;; Defining tokens
|
(provide define-tokens define-empty-tokens make-token token?
|
||||||
|
(protect-out (rename-out [token-name real-token-name]))
|
||||||
|
(protect-out (rename-out [token-value real-token-value]))
|
||||||
|
(rename-out [token-name* token-name][token-value* token-value])
|
||||||
|
(struct-out position)
|
||||||
|
(struct-out position-token)
|
||||||
|
(struct-out srcloc-token))
|
||||||
|
|
||||||
(provide define-tokens define-empty-tokens make-token token?
|
|
||||||
(protect (rename token-name real-token-name))
|
|
||||||
(protect (rename token-value real-token-value))
|
|
||||||
(rename token-name* token-name)
|
|
||||||
(rename token-value* token-value)
|
|
||||||
(struct position (offset line col))
|
|
||||||
(struct position-token (token start-pos end-pos))
|
|
||||||
(struct srcloc-token (token srcloc)))
|
|
||||||
|
|
||||||
|
;; A token is either
|
||||||
|
;; - symbol
|
||||||
|
;; - (make-token symbol any)
|
||||||
|
(define-struct token (name value) #:inspector (make-inspector))
|
||||||
|
|
||||||
;; A token is either
|
;; token-name*: token -> symbol
|
||||||
;; - symbol
|
(define (token-name* t)
|
||||||
;; - (make-token symbol any)
|
(cond
|
||||||
(define-struct token (name value) (make-inspector))
|
[(symbol? t) t]
|
||||||
|
[(token? t) (token-name t)]
|
||||||
|
[else (raise-type-error 'token-name "symbol or struct:token" 0 t)]))
|
||||||
|
|
||||||
;; token-name*: token -> symbol
|
;; token-value*: token -> any
|
||||||
(define (token-name* t)
|
(define (token-value* t)
|
||||||
(cond
|
(cond
|
||||||
((symbol? t) t)
|
[(symbol? t) #f]
|
||||||
((token? t) (token-name t))
|
[(token? t) (token-value t)]
|
||||||
(else (raise-type-error
|
[else (raise-type-error 'token-value "symbol or struct:token" 0 t)]))
|
||||||
'token-name
|
|
||||||
"symbol or struct:token"
|
|
||||||
0
|
|
||||||
t))))
|
|
||||||
|
|
||||||
;; token-value*: token -> any
|
(define-for-syntax (make-ctor-name n)
|
||||||
(define (token-value* t)
|
(datum->syntax n
|
||||||
(cond
|
(string->symbol (format "token-~a" (syntax-e n)))
|
||||||
((symbol? t) #f)
|
n
|
||||||
((token? t) (token-value t))
|
n))
|
||||||
(else (raise-type-error
|
|
||||||
'token-value
|
|
||||||
"symbol or struct:token"
|
|
||||||
0
|
|
||||||
t))))
|
|
||||||
|
|
||||||
(define-for-syntax (make-ctor-name n)
|
(define-for-syntax ((make-define-tokens empty?) stx)
|
||||||
(datum->syntax-object n
|
(syntax-case stx ()
|
||||||
(string->symbol (format "token-~a" (syntax-e n)))
|
[(_ NAME (TOKEN ...))
|
||||||
n
|
(andmap identifier? (syntax->list #'(TOKEN ...)))
|
||||||
n))
|
(with-syntax (((marked-token ...)
|
||||||
|
(map values #;(make-syntax-introducer)
|
||||||
|
(syntax->list #'(TOKEN ...)))))
|
||||||
|
(quasisyntax/loc stx
|
||||||
|
(begin
|
||||||
|
(define-syntax NAME
|
||||||
|
#,(if empty?
|
||||||
|
#'(make-e-terminals-def (quote-syntax (marked-token ...)))
|
||||||
|
#'(make-terminals-def (quote-syntax (marked-token ...)))))
|
||||||
|
#,@(map
|
||||||
|
(λ (n)
|
||||||
|
(when (eq? (syntax-e n) 'error)
|
||||||
|
(raise-syntax-error
|
||||||
|
#f
|
||||||
|
"Cannot define a token named error."
|
||||||
|
stx))
|
||||||
|
(if empty?
|
||||||
|
#`(define (#,(make-ctor-name n))
|
||||||
|
'#,n)
|
||||||
|
#`(define (#,(make-ctor-name n) x)
|
||||||
|
(make-token '#,n x))))
|
||||||
|
(syntax->list #'(TOKEN ...)))
|
||||||
|
#;(define marked-token #f) #;...)))]
|
||||||
|
[(_ ...)
|
||||||
|
(raise-syntax-error #f
|
||||||
|
"must have the form (define-tokens name (identifier ...)) or (define-empty-tokens name (identifier ...))"
|
||||||
|
stx)]))
|
||||||
|
|
||||||
(define-for-syntax (make-define-tokens empty?)
|
(define-syntax define-tokens (make-define-tokens #f))
|
||||||
(lambda (stx)
|
(define-syntax define-empty-tokens (make-define-tokens #t))
|
||||||
(syntax-case stx ()
|
|
||||||
((_ name (token ...))
|
|
||||||
(andmap identifier? (syntax->list (syntax (token ...))))
|
|
||||||
(with-syntax (((marked-token ...)
|
|
||||||
(map values #;(make-syntax-introducer)
|
|
||||||
(syntax->list (syntax (token ...))))))
|
|
||||||
(quasisyntax/loc stx
|
|
||||||
(begin
|
|
||||||
(define-syntax name
|
|
||||||
#,(if empty?
|
|
||||||
#'(make-e-terminals-def (quote-syntax (marked-token ...)))
|
|
||||||
#'(make-terminals-def (quote-syntax (marked-token ...)))))
|
|
||||||
#,@(map
|
|
||||||
(lambda (n)
|
|
||||||
(when (eq? (syntax-e n) 'error)
|
|
||||||
(raise-syntax-error
|
|
||||||
#f
|
|
||||||
"Cannot define a token named error."
|
|
||||||
stx))
|
|
||||||
(if empty?
|
|
||||||
#`(define (#,(make-ctor-name n))
|
|
||||||
'#,n)
|
|
||||||
#`(define (#,(make-ctor-name n) x)
|
|
||||||
(make-token '#,n x))))
|
|
||||||
(syntax->list (syntax (token ...))))
|
|
||||||
#;(define marked-token #f) #;...))))
|
|
||||||
((_ ...)
|
|
||||||
(raise-syntax-error
|
|
||||||
#f
|
|
||||||
"must have the form (define-tokens name (identifier ...)) or (define-empty-tokens name (identifier ...))"
|
|
||||||
stx)))))
|
|
||||||
|
|
||||||
(define-syntax define-tokens (make-define-tokens #f))
|
(define-struct position (offset line col) #:inspector #f)
|
||||||
(define-syntax define-empty-tokens (make-define-tokens #t))
|
(define-struct position-token (token start-pos end-pos) #:inspector #f)
|
||||||
|
|
||||||
(define-struct position (offset line col) #f)
|
(define-struct srcloc-token (token srcloc) #:inspector #f)
|
||||||
(define-struct position-token (token start-pos end-pos) #f)
|
|
||||||
|
|
||||||
(define-struct srcloc-token (token srcloc) #f)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
@ -1,374 +1,297 @@
|
|||||||
(module input-file-parser mzscheme
|
#lang racket/base
|
||||||
|
(require "yacc-helper.rkt"
|
||||||
|
"../private-lex/token-syntax.rkt"
|
||||||
|
"grammar.rkt"
|
||||||
|
racket/class
|
||||||
|
racket/contract
|
||||||
|
(for-template racket/base))
|
||||||
|
|
||||||
;; routines for parsing the input to the parser generator and producing a
|
;; routines for parsing the input to the parser generator and producing a
|
||||||
;; grammar (See grammar.rkt)
|
;; grammar (See grammar.rkt)
|
||||||
|
|
||||||
(require "yacc-helper.rkt"
|
|
||||||
"../private-lex/token-syntax.rkt"
|
|
||||||
"grammar.rkt"
|
|
||||||
mzlib/class
|
|
||||||
racket/contract)
|
|
||||||
(require-for-template mzscheme)
|
|
||||||
|
|
||||||
(define (is-a-grammar%? x) (is-a? x grammar%))
|
(define (is-a-grammar%? x) (is-a? x grammar%))
|
||||||
(provide/contract
|
(provide/contract
|
||||||
(parse-input ((listof identifier?) (listof identifier?) (listof identifier?)
|
[parse-input ((listof identifier?) (listof identifier?) (listof identifier?)
|
||||||
(or/c #f syntax?) syntax? any/c . -> . is-a-grammar%?))
|
(or/c #f syntax?) syntax? any/c . -> . is-a-grammar%?)]
|
||||||
(get-term-list ((listof identifier?) . -> . (listof identifier?))))
|
[get-term-list ((listof identifier?) . -> . (listof identifier?))])
|
||||||
|
|
||||||
(define stx-for-original-property (read-syntax #f (open-input-string "original")))
|
|
||||||
|
|
||||||
;; get-args: ??? -> (values (listof syntax) (or/c #f (cons integer? stx)))
|
|
||||||
(define (get-args i rhs src-pos term-defs)
|
|
||||||
(let ((empty-table (make-hash-table))
|
|
||||||
(biggest-pos #f))
|
|
||||||
(hash-table-put! empty-table 'error #t)
|
|
||||||
(for-each (lambda (td)
|
|
||||||
(let ((v (syntax-local-value td)))
|
|
||||||
(if (e-terminals-def? v)
|
|
||||||
(for-each (lambda (s)
|
|
||||||
(hash-table-put! empty-table (syntax-object->datum s) #t))
|
|
||||||
(syntax->list (e-terminals-def-t v))))))
|
|
||||||
term-defs)
|
|
||||||
(let ([args
|
|
||||||
(let get-args ((i i)
|
|
||||||
(rhs rhs))
|
|
||||||
(cond
|
|
||||||
((null? rhs) null)
|
|
||||||
(else
|
|
||||||
(let ((b (car rhs))
|
|
||||||
(name (if (hash-table-get empty-table (syntax-object->datum (car rhs)) (lambda () #f))
|
|
||||||
(gensym)
|
|
||||||
(string->symbol (format "$~a" i)))))
|
|
||||||
(cond
|
|
||||||
(src-pos
|
|
||||||
(let ([start-pos-id
|
|
||||||
(datum->syntax-object b (string->symbol (format "$~a-start-pos" i)) b stx-for-original-property)]
|
|
||||||
[end-pos-id
|
|
||||||
(datum->syntax-object b (string->symbol (format "$~a-end-pos" i)) b stx-for-original-property)])
|
|
||||||
(set! biggest-pos (cons start-pos-id end-pos-id))
|
|
||||||
`(,(datum->syntax-object b name b stx-for-original-property)
|
|
||||||
,start-pos-id
|
|
||||||
,end-pos-id
|
|
||||||
,@(get-args (add1 i) (cdr rhs)))))
|
|
||||||
(else
|
|
||||||
`(,(datum->syntax-object b name b stx-for-original-property)
|
|
||||||
,@(get-args (add1 i) (cdr rhs)))))))))])
|
|
||||||
(values args biggest-pos))))
|
|
||||||
|
|
||||||
;; Given the list of terminal symbols and the precedence/associativity definitions,
|
|
||||||
;; builds terminal structures (See grammar.rkt)
|
|
||||||
;; build-terms: symbol list * symbol list list -> term list
|
|
||||||
(define (build-terms term-list precs)
|
|
||||||
(let ((counter 0)
|
|
||||||
|
|
||||||
;;(term-list (cons (gensym) term-list))
|
(define stx-for-original-property (read-syntax #f (open-input-string "original")))
|
||||||
|
|
||||||
;; Will map a terminal symbol to its precedence/associativity
|
;; get-args: ??? -> (values (listof syntax) (or/c #f (cons integer? stx)))
|
||||||
(prec-table (make-hash-table)))
|
(define (get-args i rhs src-pos term-defs)
|
||||||
|
(define empty-table (make-hasheq))
|
||||||
;; Fill the prec table
|
(define biggest-pos #f)
|
||||||
(for-each
|
(hash-set! empty-table 'error #t)
|
||||||
(lambda (p-decl)
|
(for* ([td (in-list term-defs)]
|
||||||
(begin0
|
[v (in-value (syntax-local-value td))]
|
||||||
(let ((assoc (car p-decl)))
|
#:when (e-terminals-def? v)
|
||||||
(for-each
|
[s (in-list (syntax->list (e-terminals-def-t v)))])
|
||||||
(lambda (term-sym)
|
(hash-set! empty-table (syntax->datum s) #t))
|
||||||
(hash-table-put! prec-table term-sym (make-prec counter assoc)))
|
(define args
|
||||||
(cdr p-decl)))
|
(let get-args ([i i][rhs rhs])
|
||||||
(set! counter (add1 counter))))
|
|
||||||
precs)
|
|
||||||
|
|
||||||
;; Build the terminal structures
|
|
||||||
(map
|
|
||||||
(lambda (term-sym)
|
|
||||||
(make-term term-sym
|
|
||||||
#f
|
|
||||||
(hash-table-get prec-table term-sym (lambda () #f))))
|
|
||||||
term-list)))
|
|
||||||
|
|
||||||
;; Retrieves the terminal symbols from a terminals-def (See terminal-syntax.rkt)
|
|
||||||
;; get-terms-from-def: identifier? -> (listof identifier?)
|
|
||||||
(define (get-terms-from-def term-syn)
|
|
||||||
(let ((t (syntax-local-value term-syn (lambda () #f))))
|
|
||||||
(cond
|
(cond
|
||||||
((terminals-def? t) (syntax->list (terminals-def-t t)))
|
[(null? rhs) null]
|
||||||
((e-terminals-def? t) (syntax->list (e-terminals-def-t t)))
|
[else
|
||||||
(else
|
(define b (car rhs))
|
||||||
(raise-syntax-error
|
(define name (if (hash-ref empty-table (syntax->datum (car rhs)) #f)
|
||||||
'parser-tokens
|
(gensym)
|
||||||
"undefined token group"
|
(string->symbol (format "$~a" i))))
|
||||||
term-syn)))))
|
(cond
|
||||||
|
[src-pos
|
||||||
(define (get-term-list term-group-names)
|
(define start-pos-id
|
||||||
(remove-duplicates
|
(datum->syntax b (string->symbol (format "$~a-start-pos" i)) b stx-for-original-property))
|
||||||
(cons (datum->syntax-object #f 'error)
|
(define end-pos-id
|
||||||
(apply append
|
(datum->syntax b (string->symbol (format "$~a-end-pos" i)) b stx-for-original-property))
|
||||||
(map get-terms-from-def term-group-names)))))
|
(set! biggest-pos (cons start-pos-id end-pos-id))
|
||||||
|
(list* (datum->syntax b name b stx-for-original-property)
|
||||||
|
start-pos-id
|
||||||
|
end-pos-id
|
||||||
|
(get-args (add1 i) (cdr rhs)))]
|
||||||
|
[else
|
||||||
|
(list* (datum->syntax b name b stx-for-original-property)
|
||||||
|
(get-args (add1 i) (cdr rhs)))])])))
|
||||||
|
(values args biggest-pos))
|
||||||
|
|
||||||
(define (parse-input term-defs start ends prec-decls prods src-pos)
|
;; Given the list of terminal symbols and the precedence/associativity definitions,
|
||||||
(let* ((start-syms (map syntax-e start))
|
;; builds terminal structures (See grammar.rkt)
|
||||||
|
;; build-terms: symbol list * symbol list list -> term list
|
||||||
|
(define (build-terms term-list precs)
|
||||||
|
(define counter 0)
|
||||||
|
;;(term-list (cons (gensym) term-list))
|
||||||
|
;; Will map a terminal symbol to its precedence/associativity
|
||||||
|
(define prec-table (make-hasheq))
|
||||||
|
|
||||||
(list-of-terms (map syntax-e (get-term-list term-defs)))
|
;; Fill the prec table
|
||||||
|
(for ([p-decl (in-list precs)])
|
||||||
|
(define assoc (car p-decl))
|
||||||
|
(for ([term-sym (in-list (cdr p-decl))])
|
||||||
|
(hash-set! prec-table term-sym (make-prec counter assoc)))
|
||||||
|
(set! counter (add1 counter)))
|
||||||
|
|
||||||
(end-terms
|
;; Build the terminal structures
|
||||||
(map
|
(for/list ([term-sym (in-list term-list)])
|
||||||
(lambda (end)
|
(make-term term-sym
|
||||||
(unless (memq (syntax-e end) list-of-terms)
|
#f
|
||||||
(raise-syntax-error
|
(hash-ref prec-table term-sym (λ () #f)))))
|
||||||
'parser-end-tokens
|
|
||||||
(format "End token ~a not defined as a token"
|
|
||||||
(syntax-e end))
|
|
||||||
end))
|
|
||||||
(syntax-e end))
|
|
||||||
ends))
|
|
||||||
|
|
||||||
;; Get the list of terminals out of input-terms
|
;; Retrieves the terminal symbols from a terminals-def (See terminal-syntax.rkt)
|
||||||
|
;; get-terms-from-def: identifier? -> (listof identifier?)
|
||||||
|
(define (get-terms-from-def term-syn)
|
||||||
|
(define t (syntax-local-value term-syn #f))
|
||||||
|
(cond
|
||||||
|
[(terminals-def? t) (syntax->list (terminals-def-t t))]
|
||||||
|
[(e-terminals-def? t) (syntax->list (e-terminals-def-t t))]
|
||||||
|
[else
|
||||||
|
(raise-syntax-error
|
||||||
|
'parser-tokens
|
||||||
|
"undefined token group"
|
||||||
|
term-syn)]))
|
||||||
|
|
||||||
(list-of-non-terms
|
(define (get-term-list term-group-names)
|
||||||
(syntax-case prods ()
|
(remove-duplicates
|
||||||
(((non-term production ...) ...)
|
(cons (datum->syntax #f 'error)
|
||||||
(begin
|
(apply append (map get-terms-from-def term-group-names)))))
|
||||||
(for-each
|
|
||||||
(lambda (nts)
|
|
||||||
(if (memq (syntax-object->datum nts) list-of-terms)
|
|
||||||
(raise-syntax-error
|
|
||||||
'parser-non-terminals
|
|
||||||
(format "~a used as both token and non-terminal"
|
|
||||||
(syntax-object->datum nts))
|
|
||||||
nts)))
|
|
||||||
(syntax->list (syntax (non-term ...))))
|
|
||||||
|
|
||||||
(let ((dup (duplicate-list? (syntax-object->datum
|
(define (parse-input term-defs start ends prec-decls prods src-pos)
|
||||||
(syntax (non-term ...))))))
|
(define start-syms (map syntax-e start))
|
||||||
(if dup
|
(define list-of-terms (map syntax-e (get-term-list term-defs)))
|
||||||
(raise-syntax-error
|
(define end-terms
|
||||||
'parser-non-terminals
|
(for/list ([end (in-list ends)])
|
||||||
(format "non-terminal ~a defined multiple times"
|
(unless (memq (syntax-e end) list-of-terms)
|
||||||
dup)
|
(raise-syntax-error
|
||||||
prods)))
|
'parser-end-tokens
|
||||||
|
(format "End token ~a not defined as a token"
|
||||||
(syntax-object->datum (syntax (non-term ...)))))
|
(syntax-e end))
|
||||||
(_
|
end))
|
||||||
(raise-syntax-error
|
(syntax-e end)))
|
||||||
'parser-grammar
|
;; Get the list of terminals out of input-terms
|
||||||
"Grammar must be of the form (grammar (non-terminal productions ...) ...)"
|
(define list-of-non-terms
|
||||||
prods))))
|
(syntax-case prods ()
|
||||||
|
[((NON-TERM PRODUCTION ...) ...)
|
||||||
;; Check the precedence declarations for errors and turn them into data
|
(begin
|
||||||
(precs
|
(for ([nts (in-list (syntax->list #'(NON-TERM ...)))]
|
||||||
(syntax-case prec-decls ()
|
#:when (memq (syntax->datum nts) list-of-terms))
|
||||||
(((type term ...) ...)
|
(raise-syntax-error
|
||||||
(let ((p-terms
|
'parser-non-terminals
|
||||||
(syntax-object->datum (syntax (term ... ...)))))
|
(format "~a used as both token and non-terminal" (syntax->datum nts))
|
||||||
(cond
|
nts))
|
||||||
((duplicate-list? p-terms) =>
|
(let ([dup (duplicate-list? (syntax->datum #'(NON-TERM ...)))])
|
||||||
(lambda (d)
|
(when dup
|
||||||
|
(raise-syntax-error
|
||||||
|
'parser-non-terminals
|
||||||
|
(format "non-terminal ~a defined multiple times" dup)
|
||||||
|
prods)))
|
||||||
|
(syntax->datum #'(NON-TERM ...)))]
|
||||||
|
[_ (raise-syntax-error
|
||||||
|
'parser-grammar
|
||||||
|
"Grammar must be of the form (grammar (non-terminal productions ...) ...)"
|
||||||
|
prods)]))
|
||||||
|
;; Check the precedence declarations for errors and turn them into data
|
||||||
|
(define precs
|
||||||
|
(syntax-case prec-decls ()
|
||||||
|
[((TYPE TERM ...) ...)
|
||||||
|
(let ([p-terms (syntax->datum #'(TERM ... ...))])
|
||||||
|
(cond
|
||||||
|
[(duplicate-list? p-terms) =>
|
||||||
|
(λ (d)
|
||||||
|
(raise-syntax-error
|
||||||
|
'parser-precedences
|
||||||
|
(format "duplicate precedence declaration for token ~a" d)
|
||||||
|
prec-decls))]
|
||||||
|
[else (for ([t (in-list (syntax->list #'(TERM ... ...)))]
|
||||||
|
#:when (not (memq (syntax->datum t) list-of-terms)))
|
||||||
(raise-syntax-error
|
(raise-syntax-error
|
||||||
'parser-precedences
|
'parser-precedences
|
||||||
(format "duplicate precedence declaration for token ~a"
|
(format "Precedence declared for non-token ~a" (syntax->datum t))
|
||||||
d)
|
t))
|
||||||
prec-decls)))
|
(for ([type (in-list (syntax->list #'(TYPE ...)))]
|
||||||
(else
|
#:unless (memq (syntax->datum type) `(left right nonassoc)))
|
||||||
(for-each
|
(raise-syntax-error
|
||||||
(lambda (a)
|
'parser-precedences
|
||||||
(for-each
|
"Associativity must be left, right or nonassoc"
|
||||||
(lambda (t)
|
type))
|
||||||
(if (not (memq (syntax-object->datum t)
|
(syntax->datum prec-decls)]))]
|
||||||
list-of-terms))
|
[#f null]
|
||||||
(raise-syntax-error
|
[_ (raise-syntax-error
|
||||||
'parser-precedences
|
'parser-precedences
|
||||||
(format
|
"Precedence declaration must be of the form (precs (assoc term ...) ...) where assoc is left, right or nonassoc"
|
||||||
"Precedence declared for non-token ~a"
|
prec-decls)]))
|
||||||
(syntax-object->datum t))
|
|
||||||
t)))
|
|
||||||
(syntax->list a)))
|
|
||||||
(syntax->list (syntax ((term ...) ...))))
|
|
||||||
(for-each
|
|
||||||
(lambda (type)
|
|
||||||
(if (not (memq (syntax-object->datum type)
|
|
||||||
`(left right nonassoc)))
|
|
||||||
(raise-syntax-error
|
|
||||||
'parser-precedences
|
|
||||||
"Associativity must be left, right or nonassoc"
|
|
||||||
type)))
|
|
||||||
(syntax->list (syntax (type ...))))
|
|
||||||
(syntax-object->datum prec-decls)))))
|
|
||||||
(#f null)
|
|
||||||
(_
|
|
||||||
(raise-syntax-error
|
|
||||||
'parser-precedences
|
|
||||||
"Precedence declaration must be of the form (precs (assoc term ...) ...) where assoc is left, right or nonassoc"
|
|
||||||
prec-decls))))
|
|
||||||
|
|
||||||
(terms (build-terms list-of-terms precs))
|
|
||||||
|
|
||||||
(non-terms (map (lambda (non-term) (make-non-term non-term #f))
|
(define terms (build-terms list-of-terms precs))
|
||||||
list-of-non-terms))
|
(define non-terms (map (λ (non-term) (make-non-term non-term #f))
|
||||||
(term-table (make-hash-table))
|
list-of-non-terms))
|
||||||
(non-term-table (make-hash-table)))
|
(define term-table (make-hasheq))
|
||||||
|
(define non-term-table (make-hasheq))
|
||||||
|
|
||||||
(for-each (lambda (t)
|
(for ([t (in-list terms)])
|
||||||
(hash-table-put! term-table (gram-sym-symbol t) t))
|
(hash-set! term-table (gram-sym-symbol t) t))
|
||||||
terms)
|
|
||||||
|
|
||||||
(for-each (lambda (nt)
|
(for ([nt (in-list non-terms)])
|
||||||
(hash-table-put! non-term-table (gram-sym-symbol nt) nt))
|
(hash-set! non-term-table (gram-sym-symbol nt) nt))
|
||||||
non-terms)
|
|
||||||
|
|
||||||
(let* (
|
;; parse-prod: syntax-object -> gram-sym vector
|
||||||
;; parse-prod: syntax-object -> gram-sym vector
|
(define (parse-prod prod-so)
|
||||||
(parse-prod
|
(syntax-case prod-so ()
|
||||||
(lambda (prod-so)
|
[(PROD-RHS-SYM ...)
|
||||||
(syntax-case prod-so ()
|
(andmap identifier? (syntax->list prod-so))
|
||||||
((prod-rhs-sym ...)
|
(begin
|
||||||
(andmap identifier? (syntax->list prod-so))
|
(for ([t (in-list (syntax->list prod-so))]
|
||||||
(begin
|
#:when (memq (syntax->datum t) end-terms))
|
||||||
(for-each (lambda (t)
|
(raise-syntax-error
|
||||||
(if (memq (syntax-object->datum t) end-terms)
|
'parser-production-rhs
|
||||||
(raise-syntax-error
|
(format "~a is an end token and cannot be used in a production" (syntax->datum t))
|
||||||
'parser-production-rhs
|
t))
|
||||||
(format "~a is an end token and cannot be used in a production"
|
(for/vector ([s (in-list (syntax->list prod-so))])
|
||||||
(syntax-object->datum t))
|
(cond
|
||||||
t)))
|
[(hash-ref term-table (syntax->datum s) #f)]
|
||||||
(syntax->list prod-so))
|
[(hash-ref non-term-table (syntax->datum s) #f)]
|
||||||
(list->vector
|
[else (raise-syntax-error
|
||||||
(map (lambda (s)
|
'parser-production-rhs
|
||||||
(hash-table-get
|
(format "~a is not declared as a terminal or non-terminal" (syntax->datum s))
|
||||||
term-table
|
s)])))]
|
||||||
(syntax-object->datum s)
|
[_ (raise-syntax-error
|
||||||
(lambda ()
|
'parser-production-rhs
|
||||||
(hash-table-get
|
"production right-hand-side must have form (symbol ...)"
|
||||||
non-term-table
|
prod-so)]))
|
||||||
(syntax-object->datum s)
|
|
||||||
(lambda ()
|
|
||||||
(raise-syntax-error
|
|
||||||
'parser-production-rhs
|
|
||||||
(format
|
|
||||||
"~a is not declared as a terminal or non-terminal"
|
|
||||||
(syntax-object->datum s))
|
|
||||||
s))))))
|
|
||||||
(syntax->list prod-so)))))
|
|
||||||
(_
|
|
||||||
(raise-syntax-error
|
|
||||||
'parser-production-rhs
|
|
||||||
"production right-hand-side must have form (symbol ...)"
|
|
||||||
prod-so)))))
|
|
||||||
|
|
||||||
;; parse-action: syntax-object * syntax-object -> syntax-object
|
;; parse-action: syntax-object * syntax-object -> syntax-object
|
||||||
(parse-action
|
(define (parse-action rhs act-in)
|
||||||
(lambda (rhs act)
|
(define-values (args biggest) (get-args 1 (syntax->list rhs) src-pos term-defs))
|
||||||
(let-values ([(args biggest) (get-args 1 (syntax->list rhs) src-pos term-defs)])
|
(define act
|
||||||
(let ([act
|
(if biggest
|
||||||
(if biggest
|
(with-syntax ([(CAR-BIGGEST . CDR-BIGGEST) biggest]
|
||||||
(with-syntax ([$n-start-pos (datum->syntax-object (car biggest) '$n-start-pos)]
|
[$N-START-POS (datum->syntax (car biggest) '$n-start-pos)]
|
||||||
[$n-end-pos (datum->syntax-object (cdr biggest) '$n-end-pos)])
|
[$N-END-POS (datum->syntax (cdr biggest) '$n-end-pos)]
|
||||||
#`(let ([$n-start-pos #,(car biggest)]
|
[ACT-IN act-in])
|
||||||
[$n-end-pos #,(cdr biggest)])
|
#'(let ([$N-START-POS CAR-BIGGEST]
|
||||||
#,act))
|
[$N-END-POS CDR-BIGGEST])
|
||||||
act)])
|
ACT-IN))
|
||||||
(quasisyntax/loc act
|
act-in))
|
||||||
(lambda #,args
|
(with-syntax ([ARGS args][ACT act])
|
||||||
#,act))))))
|
(syntax/loc #'ACT (λ ARGS ACT))))
|
||||||
|
|
||||||
;; parse-prod+action: non-term * syntax-object -> production
|
;; parse-prod+action: non-term * syntax-object -> production
|
||||||
(parse-prod+action
|
(define (parse-prod+action nt prod-so)
|
||||||
(lambda (nt prod-so)
|
(syntax-case prod-so ()
|
||||||
(syntax-case prod-so ()
|
[(PROD-RHS ACTION)
|
||||||
((prod-rhs action)
|
(let ([p (parse-prod #'PROD-RHS)])
|
||||||
(let ((p (parse-prod (syntax prod-rhs))))
|
(make-prod
|
||||||
(make-prod
|
nt
|
||||||
nt
|
p
|
||||||
p
|
#f
|
||||||
#f
|
(let loop ([i (sub1 (vector-length p))])
|
||||||
(let loop ((i (sub1 (vector-length p))))
|
(if (>= i 0)
|
||||||
(if (>= i 0)
|
(let ([gs (vector-ref p i)])
|
||||||
(let ((gs (vector-ref p i)))
|
(if (term? gs)
|
||||||
(if (term? gs)
|
(term-prec gs)
|
||||||
(term-prec gs)
|
(loop (sub1 i))))
|
||||||
(loop (sub1 i))))
|
#f))
|
||||||
#f))
|
(parse-action #'PROD-RHS #'ACTION)))]
|
||||||
(parse-action (syntax prod-rhs) (syntax action)))))
|
[(PROD-RHS (PREC TERM) ACTION)
|
||||||
((prod-rhs (prec term) action)
|
(identifier? #'TERM)
|
||||||
(identifier? (syntax term))
|
(let ([p (parse-prod #'PROD-RHS)])
|
||||||
(let ((p (parse-prod (syntax prod-rhs))))
|
(make-prod
|
||||||
(make-prod
|
nt
|
||||||
nt
|
p
|
||||||
p
|
#f
|
||||||
#f
|
(term-prec
|
||||||
(term-prec
|
(cond
|
||||||
(hash-table-get
|
[(hash-ref term-table (syntax->datum #'TERM) #f)]
|
||||||
term-table
|
[else (raise-syntax-error
|
||||||
(syntax-object->datum (syntax term))
|
|
||||||
(lambda ()
|
|
||||||
(raise-syntax-error
|
|
||||||
'parser-production-rhs
|
|
||||||
(format
|
|
||||||
"unrecognized terminal ~a in precedence declaration"
|
|
||||||
(syntax-object->datum (syntax term)))
|
|
||||||
(syntax term)))))
|
|
||||||
(parse-action (syntax prod-rhs) (syntax action)))))
|
|
||||||
(_
|
|
||||||
(raise-syntax-error
|
|
||||||
'parser-production-rhs
|
'parser-production-rhs
|
||||||
"production must have form [(symbol ...) expression] or [(symbol ...) (prec symbol) expression]"
|
(format
|
||||||
prod-so)))))
|
"unrecognized terminal ~a in precedence declaration"
|
||||||
|
(syntax->datum #'TERM))
|
||||||
|
#'TERM)]))
|
||||||
|
(parse-action #'PROD-RHS #'ACTION)))]
|
||||||
|
[_ (raise-syntax-error
|
||||||
|
'parser-production-rhs
|
||||||
|
"production must have form [(symbol ...) expression] or [(symbol ...) (prec symbol) expression]"
|
||||||
|
prod-so)]))
|
||||||
|
|
||||||
;; parse-prod-for-nt: syntax-object -> production list
|
;; parse-prod-for-nt: syntax-object -> production list
|
||||||
(parse-prods-for-nt
|
(define (parse-prods-for-nt prods-so)
|
||||||
(lambda (prods-so)
|
(syntax-case prods-so ()
|
||||||
(syntax-case prods-so ()
|
[(NT PRODUCTIONS ...)
|
||||||
((nt productions ...)
|
(positive? (length (syntax->list #'(PRODUCTIONS ...))))
|
||||||
(> (length (syntax->list (syntax (productions ...)))) 0)
|
(let ([nt (hash-ref non-term-table (syntax->datum #'NT))])
|
||||||
(let ((nt (hash-table-get non-term-table
|
(map (λ (p) (parse-prod+action nt p)) (syntax->list #'(PRODUCTIONS ...))))]
|
||||||
(syntax-object->datum (syntax nt)))))
|
[_ (raise-syntax-error
|
||||||
(map (lambda (p) (parse-prod+action nt p))
|
'parser-productions
|
||||||
(syntax->list (syntax (productions ...))))))
|
"A production for a non-terminal must be (non-term right-hand-side ...) with at least 1 right hand side"
|
||||||
(_
|
prods-so)]))
|
||||||
(raise-syntax-error
|
|
||||||
'parser-productions
|
|
||||||
"A production for a non-terminal must be (non-term right-hand-side ...) with at least 1 right hand side"
|
|
||||||
prods-so))))))
|
|
||||||
|
|
||||||
(for-each
|
(for ([sstx (in-list start)]
|
||||||
(lambda (sstx ssym)
|
[ssym (in-list start-syms)]
|
||||||
(unless (memq ssym list-of-non-terms)
|
#:unless (memq ssym list-of-non-terms))
|
||||||
(raise-syntax-error
|
(raise-syntax-error
|
||||||
'parser-start
|
'parser-start
|
||||||
(format "Start symbol ~a not defined as a non-terminal" ssym)
|
(format "Start symbol ~a not defined as a non-terminal" ssym)
|
||||||
sstx)))
|
sstx))
|
||||||
start start-syms)
|
|
||||||
|
|
||||||
(let* ((starts (map (lambda (x) (make-non-term (gensym) #f)) start-syms))
|
(define starts (map (λ (x) (make-non-term (gensym) #f)) start-syms))
|
||||||
(end-non-terms (map (lambda (x) (make-non-term (gensym) #f)) start-syms))
|
(define end-non-terms (map (λ (x) (make-non-term (gensym) #f)) start-syms))
|
||||||
(parsed-prods (map parse-prods-for-nt (syntax->list prods)))
|
(define parsed-prods (map parse-prods-for-nt (syntax->list prods)))
|
||||||
(start-prods
|
(define start-prods (for/list ([start (in-list starts)]
|
||||||
(map (lambda (start end-non-term)
|
[end-non-term (in-list end-non-terms)])
|
||||||
(list (make-prod start (vector end-non-term) #f #f
|
(list (make-prod start (vector end-non-term) #f #f #'values))))
|
||||||
(syntax (lambda (x) x)))))
|
(define new-prods
|
||||||
starts end-non-terms))
|
(append start-prods
|
||||||
(prods
|
(for/list ([end-nt (in-list end-non-terms)]
|
||||||
`(,@start-prods
|
[start-sym (in-list start-syms)])
|
||||||
,@(map
|
(for/list ([end (in-list end-terms)])
|
||||||
(lambda (end-nt start-sym)
|
(make-prod end-nt
|
||||||
(map
|
(vector
|
||||||
(lambda (end)
|
(hash-ref non-term-table start-sym)
|
||||||
(make-prod end-nt
|
(hash-ref term-table end))
|
||||||
(vector
|
#f
|
||||||
(hash-table-get non-term-table start-sym)
|
#f
|
||||||
(hash-table-get term-table end))
|
#'values)))
|
||||||
#f
|
parsed-prods))
|
||||||
#f
|
|
||||||
(syntax (lambda (x) x))))
|
|
||||||
end-terms))
|
|
||||||
end-non-terms start-syms)
|
|
||||||
,@parsed-prods)))
|
|
||||||
|
|
||||||
(make-object grammar%
|
(make-object grammar%
|
||||||
prods
|
new-prods
|
||||||
(map car start-prods)
|
(map car start-prods)
|
||||||
terms
|
terms
|
||||||
(append starts (append end-non-terms non-terms))
|
(append starts (append end-non-terms non-terms))
|
||||||
(map (lambda (term-name)
|
(map (λ (term-name) (hash-ref term-table term-name)) end-terms)))
|
||||||
(hash-table-get term-table term-name))
|
|
||||||
end-terms)))))))
|
|
||||||
|
@ -1,277 +1,252 @@
|
|||||||
(module lalr mzscheme
|
#lang racket/base
|
||||||
|
(require "lr0.rkt"
|
||||||
;; Compute LALR lookaheads from DeRemer and Pennello 1982
|
"grammar.rkt"
|
||||||
|
racket/list
|
||||||
(require "lr0.rkt"
|
racket/class)
|
||||||
"grammar.rkt"
|
|
||||||
mzlib/list
|
;; Compute LALR lookaheads from DeRemer and Pennello 1982
|
||||||
mzlib/class)
|
|
||||||
|
(provide compute-LA)
|
||||||
(provide compute-LA)
|
|
||||||
|
;; compute-DR: LR0-automaton * grammar -> (trans-key -> term set)
|
||||||
;; compute-DR: LR0-automaton * grammar -> (trans-key -> term set)
|
;; computes for each state, non-term transition pair, the terminals
|
||||||
;; computes for each state, non-term transition pair, the terminals
|
;; which can transition out of the resulting state
|
||||||
;; which can transition out of the resulting state
|
;; output term set is represented in bit-vector form
|
||||||
;; output term set is represented in bit-vector form
|
(define ((compute-DR a g) tk)
|
||||||
(define (compute-DR a g)
|
(define r (send a run-automaton (trans-key-st tk) (trans-key-gs tk)))
|
||||||
(lambda (tk)
|
(term-list->bit-vector
|
||||||
(let ((r (send a run-automaton (trans-key-st tk) (trans-key-gs tk))))
|
(filter (λ (term) (send a run-automaton r term)) (send g get-terms))))
|
||||||
(term-list->bit-vector
|
|
||||||
(filter
|
;; compute-reads:
|
||||||
(lambda (term)
|
;; LR0-automaton * grammar -> (trans-key -> trans-key list)
|
||||||
(send a run-automaton r term))
|
(define (compute-reads a g)
|
||||||
(send g get-terms))))))
|
(define nullable-non-terms (filter (λ (nt) (send g nullable-non-term? nt)) (send g get-non-terms)))
|
||||||
|
(λ (tk)
|
||||||
;; compute-reads:
|
(define r (send a run-automaton (trans-key-st tk) (trans-key-gs tk)))
|
||||||
;; LR0-automaton * grammar -> (trans-key -> trans-key list)
|
(for/list ([non-term (in-list nullable-non-terms)]
|
||||||
(define (compute-reads a g)
|
#:when (send a run-automaton r non-term))
|
||||||
(let ((nullable-non-terms
|
(make-trans-key r non-term))))
|
||||||
(filter (lambda (nt) (send g nullable-non-term? nt))
|
|
||||||
(send g get-non-terms))))
|
;; compute-read: LR0-automaton * grammar -> (trans-key -> term set)
|
||||||
(lambda (tk)
|
;; output term set is represented in bit-vector form
|
||||||
(let ((r (send a run-automaton (trans-key-st tk) (trans-key-gs tk))))
|
(define (compute-read a g)
|
||||||
(map (lambda (x) (make-trans-key r x))
|
(define dr (compute-DR a g))
|
||||||
(filter (lambda (non-term) (send a run-automaton r non-term))
|
(define reads (compute-reads a g))
|
||||||
nullable-non-terms))))))
|
(digraph-tk->terml (send a get-mapped-non-term-keys)
|
||||||
|
reads
|
||||||
;; compute-read: LR0-automaton * grammar -> (trans-key -> term set)
|
dr
|
||||||
;; output term set is represented in bit-vector form
|
(send a get-num-states)))
|
||||||
(define (compute-read a g)
|
;; returns the list of all k such that state k transitions to state start on the
|
||||||
(let* ((dr (compute-DR a g))
|
;; transitions in rhs (in order)
|
||||||
(reads (compute-reads a g)))
|
(define (run-lr0-backward a rhs dot-pos start num-states)
|
||||||
(digraph-tk->terml (send a get-mapped-non-term-keys)
|
(let loop ([states (list start)]
|
||||||
reads
|
[i (sub1 dot-pos)])
|
||||||
dr
|
(cond
|
||||||
(send a get-num-states))))
|
[(< i 0) states]
|
||||||
;; returns the list of all k such that state k transitions to state start on the
|
[else (loop (send a run-automaton-back states (vector-ref rhs i))
|
||||||
;; transitions in rhs (in order)
|
(sub1 i))])))
|
||||||
(define (run-lr0-backward a rhs dot-pos start num-states)
|
|
||||||
(let loop ((states (list start))
|
;; prod->items-for-include: grammar * prod * non-term -> lr0-item list
|
||||||
(i (sub1 dot-pos)))
|
;; returns the list of all (B -> beta . nt gamma) such that prod = (B -> beta nt gamma)
|
||||||
(cond
|
;; and gamma =>* epsilon
|
||||||
((< i 0) states)
|
(define (prod->items-for-include g prod nt)
|
||||||
(else (loop (send a run-automaton-back states (vector-ref rhs i))
|
(define rhs (prod-rhs prod))
|
||||||
(sub1 i))))))
|
(define rhs-l (vector-length rhs))
|
||||||
|
(append (if (and (> rhs-l 0) (eq? nt (vector-ref rhs (sub1 rhs-l))))
|
||||||
;; prod->items-for-include: grammar * prod * non-term -> lr0-item list
|
(list (make-item prod (sub1 rhs-l)))
|
||||||
;; returns the list of all (B -> beta . nt gamma) such that prod = (B -> beta nt gamma)
|
null)
|
||||||
;; and gamma =>* epsilon
|
(let loop ([i (sub1 rhs-l)])
|
||||||
(define (prod->items-for-include g prod nt)
|
(cond
|
||||||
(let* ((rhs (prod-rhs prod))
|
[(and (> i 0)
|
||||||
(rhs-l (vector-length rhs)))
|
(non-term? (vector-ref rhs i))
|
||||||
(append (if (and (> rhs-l 0) (eq? nt (vector-ref rhs (sub1 rhs-l))))
|
(send g nullable-non-term? (vector-ref rhs i)))
|
||||||
(list (make-item prod (sub1 rhs-l)))
|
(if (eq? nt (vector-ref rhs (sub1 i)))
|
||||||
null)
|
(cons (make-item prod (sub1 i))
|
||||||
(let loop ((i (sub1 rhs-l)))
|
(loop (sub1 i)))
|
||||||
(cond
|
(loop (sub1 i)))]
|
||||||
((and (> i 0)
|
[else null]))))
|
||||||
(non-term? (vector-ref rhs i))
|
|
||||||
(send g nullable-non-term? (vector-ref rhs i)))
|
;; prod-list->items-for-include: grammar * prod list * non-term -> lr0-item list
|
||||||
(if (eq? nt (vector-ref rhs (sub1 i)))
|
;; return the list of all (B -> beta . nt gamma) such that (B -> beta nt gamma) in prod-list
|
||||||
(cons (make-item prod (sub1 i))
|
;; and gamma =>* epsilon
|
||||||
(loop (sub1 i)))
|
(define (prod-list->items-for-include g prod-list nt)
|
||||||
(loop (sub1 i))))
|
(apply append (map (λ (prod) (prod->items-for-include g prod nt)) prod-list)))
|
||||||
(else null))))))
|
|
||||||
|
;; comput-includes: lr0-automaton * grammar -> (trans-key -> trans-key list)
|
||||||
;; prod-list->items-for-include: grammar * prod list * non-term -> lr0-item list
|
(define (compute-includes a g)
|
||||||
;; return the list of all (B -> beta . nt gamma) such that (B -> beta nt gamma) in prod-list
|
(define num-states (send a get-num-states))
|
||||||
;; and gamma =>* epsilon
|
(define items-for-input-nt (make-vector (send g get-num-non-terms) null))
|
||||||
(define (prod-list->items-for-include g prod-list nt)
|
(for ([input-nt (in-list (send g get-non-terms))])
|
||||||
(apply append (map (lambda (prod) (prod->items-for-include g prod nt)) prod-list)))
|
(vector-set! items-for-input-nt (non-term-index input-nt)
|
||||||
|
(prod-list->items-for-include g (send g get-prods) input-nt)))
|
||||||
;; comput-includes: lr0-automaton * grammar -> (trans-key -> trans-key list)
|
(λ (tk)
|
||||||
(define (compute-includes a g)
|
(define goal-state (trans-key-st tk))
|
||||||
(let ((num-states (send a get-num-states))
|
(define non-term (trans-key-gs tk))
|
||||||
(items-for-input-nt (make-vector (send g get-num-non-terms) null)))
|
(define items (vector-ref items-for-input-nt (non-term-index non-term)))
|
||||||
(for-each
|
(trans-key-list-remove-dups
|
||||||
(lambda (input-nt)
|
(apply append
|
||||||
(vector-set! items-for-input-nt (non-term-index input-nt)
|
(for/list ([item (in-list items)])
|
||||||
(prod-list->items-for-include g (send g get-prods) input-nt)))
|
(define prod (item-prod item))
|
||||||
(send g get-non-terms))
|
(define rhs (prod-rhs prod))
|
||||||
(lambda (tk)
|
(define lhs (prod-lhs prod))
|
||||||
(let* ((goal-state (trans-key-st tk))
|
(map (λ (state) (make-trans-key state lhs))
|
||||||
(non-term (trans-key-gs tk))
|
(run-lr0-backward a
|
||||||
(items (vector-ref items-for-input-nt (non-term-index non-term))))
|
rhs
|
||||||
(trans-key-list-remove-dups
|
(item-dot-pos item)
|
||||||
(apply append
|
goal-state
|
||||||
(map (lambda (item)
|
num-states)))))))
|
||||||
(let* ((prod (item-prod item))
|
|
||||||
(rhs (prod-rhs prod))
|
;; compute-lookback: lr0-automaton * grammar -> (kernel * proc -> trans-key list)
|
||||||
(lhs (prod-lhs prod)))
|
(define (compute-lookback a g)
|
||||||
(map (lambda (state)
|
(define num-states (send a get-num-states))
|
||||||
(make-trans-key state lhs))
|
(λ (state prod)
|
||||||
(run-lr0-backward a
|
(map (λ (k) (make-trans-key k (prod-lhs prod)))
|
||||||
rhs
|
(run-lr0-backward a (prod-rhs prod) (vector-length (prod-rhs prod)) state num-states))))
|
||||||
(item-dot-pos item)
|
|
||||||
goal-state
|
;; compute-follow: LR0-automaton * grammar -> (trans-key -> term set)
|
||||||
num-states))))
|
;; output term set is represented in bit-vector form
|
||||||
items)))))))
|
(define (compute-follow a g includes)
|
||||||
|
(define read (compute-read a g))
|
||||||
;; compute-lookback: lr0-automaton * grammar -> (kernel * proc -> trans-key list)
|
(digraph-tk->terml (send a get-mapped-non-term-keys)
|
||||||
(define (compute-lookback a g)
|
includes
|
||||||
(let ((num-states (send a get-num-states)))
|
read
|
||||||
(lambda (state prod)
|
(send a get-num-states)))
|
||||||
(map (lambda (k) (make-trans-key k (prod-lhs prod)))
|
|
||||||
(run-lr0-backward a (prod-rhs prod) (vector-length (prod-rhs prod)) state num-states)))))
|
;; compute-LA: LR0-automaton * grammar -> kernel * prod -> term set
|
||||||
|
;; output term set is represented in bit-vector form
|
||||||
;; compute-follow: LR0-automaton * grammar -> (trans-key -> term set)
|
(define (compute-LA a g)
|
||||||
;; output term set is represented in bit-vector form
|
(define includes (compute-includes a g))
|
||||||
(define (compute-follow a g includes)
|
(define lookback (compute-lookback a g))
|
||||||
(let ((read (compute-read a g)))
|
(define follow (compute-follow a g includes))
|
||||||
(digraph-tk->terml (send a get-mapped-non-term-keys)
|
(λ (k p)
|
||||||
includes
|
(define l (lookback k p))
|
||||||
read
|
(define f (map follow l))
|
||||||
(send a get-num-states))))
|
(apply bitwise-ior (cons 0 f))))
|
||||||
|
|
||||||
;; compute-LA: LR0-automaton * grammar -> kernel * prod -> term set
|
|
||||||
;; output term set is represented in bit-vector form
|
(define (print-DR dr a g)
|
||||||
(define (compute-LA a g)
|
(print-input-st-sym dr "DR" a g print-output-terms))
|
||||||
(let* ((includes (compute-includes a g))
|
(define (print-Read Read a g)
|
||||||
(lookback (compute-lookback a g))
|
(print-input-st-sym Read "Read" a g print-output-terms))
|
||||||
(follow (compute-follow a g includes)))
|
(define (print-includes i a g)
|
||||||
(lambda (k p)
|
(print-input-st-sym i "includes" a g print-output-st-nt))
|
||||||
(let* ((l (lookback k p))
|
(define (print-lookback l a g)
|
||||||
(f (map follow l)))
|
(print-input-st-prod l "lookback" a g print-output-st-nt))
|
||||||
(apply bitwise-ior (cons 0 f))))))
|
(define (print-follow f a g)
|
||||||
|
(print-input-st-sym f "follow" a g print-output-terms))
|
||||||
(define (print-DR dr a g)
|
(define (print-LA l a g)
|
||||||
(print-input-st-sym dr "DR" a g print-output-terms))
|
(print-input-st-prod l "LA" a g print-output-terms))
|
||||||
(define (print-Read Read a g)
|
|
||||||
(print-input-st-sym Read "Read" a g print-output-terms))
|
(define (print-input-st-sym f name a g print-output)
|
||||||
(define (print-includes i a g)
|
(printf "~a:\n" name)
|
||||||
(print-input-st-sym i "includes" a g print-output-st-nt))
|
(send a for-each-state
|
||||||
(define (print-lookback l a g)
|
(λ (state)
|
||||||
(print-input-st-prod l "lookback" a g print-output-st-nt))
|
|
||||||
(define (print-follow f a g)
|
|
||||||
(print-input-st-sym f "follow" a g print-output-terms))
|
|
||||||
(define (print-LA l a g)
|
|
||||||
(print-input-st-prod l "LA" a g print-output-terms))
|
|
||||||
|
|
||||||
(define (print-input-st-sym f name a g print-output)
|
|
||||||
(printf "~a:\n" name)
|
|
||||||
(send a for-each-state
|
|
||||||
(lambda (state)
|
|
||||||
(for-each
|
|
||||||
(lambda (non-term)
|
|
||||||
(let ((res (f (make-trans-key state non-term))))
|
|
||||||
(if (not (null? res))
|
|
||||||
(printf "~a(~a, ~a) = ~a\n"
|
|
||||||
name
|
|
||||||
state
|
|
||||||
(gram-sym-symbol non-term)
|
|
||||||
(print-output res)))))
|
|
||||||
(send g get-non-terms))))
|
|
||||||
(newline))
|
|
||||||
|
|
||||||
(define (print-input-st-prod f name a g print-output)
|
|
||||||
(printf "~a:\n" name)
|
|
||||||
(send a for-each-state
|
|
||||||
(lambda (state)
|
|
||||||
(for-each
|
|
||||||
(lambda (non-term)
|
|
||||||
(for-each
|
(for-each
|
||||||
(lambda (prod)
|
(λ (non-term)
|
||||||
(let ((res (f state prod)))
|
(let ([res (f (make-trans-key state non-term))])
|
||||||
(if (not (null? res))
|
(when (not (null? res))
|
||||||
(printf "~a(~a, ~a) = ~a\n"
|
(printf "~a(~a, ~a) = ~a\n"
|
||||||
name
|
name
|
||||||
(kernel-index state)
|
state
|
||||||
(prod-index prod)
|
(gram-sym-symbol non-term)
|
||||||
(print-output res)))))
|
(print-output res)))))
|
||||||
(send g get-prods-for-non-term non-term)))
|
(send g get-non-terms))))
|
||||||
(send g get-non-terms)))))
|
(newline))
|
||||||
|
|
||||||
(define (print-output-terms r)
|
(define (print-input-st-prod f name a g print-output)
|
||||||
(map
|
(printf "~a:\n" name)
|
||||||
(lambda (p)
|
(send a for-each-state
|
||||||
(gram-sym-symbol p))
|
(λ (state)
|
||||||
r))
|
(for-each
|
||||||
|
(λ (non-term)
|
||||||
(define (print-output-st-nt r)
|
(for-each
|
||||||
(map
|
(λ (prod)
|
||||||
(lambda (p)
|
(let ([res (f state prod)])
|
||||||
(list
|
(when (not (null? res))
|
||||||
(kernel-index (trans-key-st p))
|
(printf "~a(~a, ~a) = ~a\n"
|
||||||
(gram-sym-symbol (trans-key-gs p))))
|
name
|
||||||
r))
|
(kernel-index state)
|
||||||
|
(prod-index prod)
|
||||||
;; init-tk-map : int -> (vectorof hashtable?)
|
(print-output res)))))
|
||||||
(define (init-tk-map n)
|
(send g get-prods-for-non-term non-term)))
|
||||||
(let ((v (make-vector n #f)))
|
(send g get-non-terms)))))
|
||||||
(let loop ((i (sub1 (vector-length v))))
|
|
||||||
(when (>= i 0)
|
(define (print-output-terms r)
|
||||||
(vector-set! v i (make-hash-table))
|
(map gram-sym-symbol r))
|
||||||
(loop (sub1 i))))
|
|
||||||
v))
|
(define (print-output-st-nt r)
|
||||||
|
(map (λ (p) (list (kernel-index (trans-key-st p)) (gram-sym-symbol (trans-key-gs p)))) r))
|
||||||
;; lookup-tk-map : (vectorof (symbol? int hashtable)) -> trans-key? -> int
|
|
||||||
(define (lookup-tk-map map)
|
;; init-tk-map : int -> (vectorof hashtable?)
|
||||||
(lambda (tk)
|
(define (init-tk-map n)
|
||||||
(let ((st (trans-key-st tk))
|
(define v (make-vector n #f))
|
||||||
(gs (trans-key-gs tk)))
|
(let loop ([i (sub1 (vector-length v))])
|
||||||
(hash-table-get (vector-ref map (kernel-index st))
|
(when (>= i 0)
|
||||||
(gram-sym-symbol gs)
|
(vector-set! v i (make-hasheq))
|
||||||
(lambda () 0)))))
|
(loop (sub1 i))))
|
||||||
|
v)
|
||||||
;; add-tk-map : (vectorof (symbol? int hashtable)) -> trans-key int ->
|
|
||||||
(define (add-tk-map map)
|
;; lookup-tk-map : (vectorof (symbol? int hashtable)) -> trans-key? -> int
|
||||||
(lambda (tk v)
|
(define ((lookup-tk-map map) tk)
|
||||||
(let ((st (trans-key-st tk))
|
(define st (trans-key-st tk))
|
||||||
(gs (trans-key-gs tk)))
|
(define gs (trans-key-gs tk))
|
||||||
(hash-table-put! (vector-ref map (kernel-index st))
|
(hash-ref (vector-ref map (kernel-index st))
|
||||||
(gram-sym-symbol gs)
|
(gram-sym-symbol gs)
|
||||||
v))))
|
(λ () 0)))
|
||||||
|
|
||||||
;; digraph-tk->terml:
|
;; add-tk-map : (vectorof (symbol? int hashtable)) -> trans-key int ->
|
||||||
;; (trans-key list) * (trans-key -> trans-key list) * (trans-key -> term list) * int * int * int
|
(define ((add-tk-map map) tk v)
|
||||||
;; -> (trans-key -> term list)
|
(define st (trans-key-st tk))
|
||||||
;; DeRemer and Pennello 1982
|
(define gs (trans-key-gs tk))
|
||||||
;; Computes (f x) = (f- x) union Union{(f y) | y in (edges x)}
|
(hash-set! (vector-ref map (kernel-index st))
|
||||||
;; A specialization of digraph in the file graph.rkt
|
(gram-sym-symbol gs)
|
||||||
(define (digraph-tk->terml nodes edges f- num-states)
|
v))
|
||||||
(letrec [
|
|
||||||
;; Will map elements of trans-key to term sets represented as bit vectors
|
;; digraph-tk->terml:
|
||||||
(results (init-tk-map num-states))
|
;; (trans-key list) * (trans-key -> trans-key list) * (trans-key -> term list) * int * int * int
|
||||||
|
;; -> (trans-key -> term list)
|
||||||
;; Maps elements of trans-keys to integers.
|
;; DeRemer and Pennello 1982
|
||||||
(N (init-tk-map num-states))
|
;; Computes (f x) = (f- x) union Union{(f y) | y in (edges x)}
|
||||||
|
;; A specialization of digraph in the file graph.rkt
|
||||||
(get-N (lookup-tk-map N))
|
(define (digraph-tk->terml nodes edges f- num-states)
|
||||||
(set-N (add-tk-map N))
|
;; Will map elements of trans-key to term sets represented as bit vectors
|
||||||
(get-f (lookup-tk-map results))
|
(define results (init-tk-map num-states))
|
||||||
(set-f (add-tk-map results))
|
|
||||||
|
;; Maps elements of trans-keys to integers.
|
||||||
(stack null)
|
(define N (init-tk-map num-states))
|
||||||
(push (lambda (x)
|
|
||||||
(set! stack (cons x stack))))
|
(define get-N (lookup-tk-map N))
|
||||||
(pop (lambda ()
|
(define set-N (add-tk-map N))
|
||||||
(begin0
|
(define get-f (lookup-tk-map results))
|
||||||
(car stack)
|
(define set-f (add-tk-map results))
|
||||||
(set! stack (cdr stack)))))
|
|
||||||
(depth (lambda () (length stack)))
|
(define stack null)
|
||||||
|
(define (push x) (set! stack (cons x stack)))
|
||||||
;; traverse: 'a ->
|
(define (pop) (begin0
|
||||||
(traverse
|
(car stack)
|
||||||
(lambda (x)
|
(set! stack (cdr stack))))
|
||||||
(push x)
|
(define (depth) (length stack))
|
||||||
(let ((d (depth)))
|
|
||||||
(set-N x d)
|
;; traverse: 'a ->
|
||||||
(set-f x (f- x))
|
(define (traverse x)
|
||||||
(for-each (lambda (y)
|
(push x)
|
||||||
(when (= 0 (get-N y))
|
(let ([d (depth)])
|
||||||
(traverse y))
|
(set-N x d)
|
||||||
(set-f x (bitwise-ior (get-f x) (get-f y)))
|
(set-f x (f- x))
|
||||||
(set-N x (min (get-N x) (get-N y))))
|
(for-each (λ (y)
|
||||||
(edges x))
|
(when (= 0 (get-N y))
|
||||||
(when (= d (get-N x))
|
(traverse y))
|
||||||
(let loop ((p (pop)))
|
(set-f x (bitwise-ior (get-f x) (get-f y)))
|
||||||
(set-N p +inf.0)
|
(set-N x (min (get-N x) (get-N y))))
|
||||||
(set-f p (get-f x))
|
(edges x))
|
||||||
(unless (equal? x p)
|
(when (= d (get-N x))
|
||||||
(loop (pop))))))))]
|
(let loop ([p (pop)])
|
||||||
(for-each (lambda (x)
|
(set-N p +inf.0)
|
||||||
(when (= 0 (get-N x))
|
(set-f p (get-f x))
|
||||||
(traverse x)))
|
(unless (equal? x p)
|
||||||
nodes)
|
(loop (pop)))))))
|
||||||
get-f))
|
|
||||||
)
|
(for ([x (in-list nodes)]
|
||||||
|
#:when (zero? (get-N x)))
|
||||||
|
(traverse x))
|
||||||
|
get-f)
|
||||||
|
@ -1,54 +1,54 @@
|
|||||||
(module parser-actions mzscheme
|
#lang racket/base
|
||||||
(require "grammar.rkt")
|
(require "grammar.rkt")
|
||||||
(provide (all-defined-except make-reduce make-reduce*)
|
(provide (except-out (all-defined-out) make-reduce make-reduce*)
|
||||||
(rename make-reduce* make-reduce))
|
(rename-out [make-reduce* make-reduce]))
|
||||||
|
|
||||||
;; An action is
|
;; An action is
|
||||||
;; - (make-shift int)
|
;; - (make-shift int)
|
||||||
;; - (make-reduce prod runtime-action)
|
;; - (make-reduce prod runtime-action)
|
||||||
;; - (make-accept)
|
;; - (make-accept)
|
||||||
;; - (make-goto int)
|
;; - (make-goto int)
|
||||||
;; - (no-action)
|
;; - (no-action)
|
||||||
;; A reduce contains a runtime-reduce so that sharing of the reduces can
|
;; A reduce contains a runtime-reduce so that sharing of the reduces can
|
||||||
;; be easily transferred to sharing of runtime-reduces.
|
;; be easily transferred to sharing of runtime-reduces.
|
||||||
|
|
||||||
(define-struct action () (make-inspector))
|
(define-struct action () #:inspector (make-inspector))
|
||||||
(define-struct (shift action) (state) (make-inspector))
|
(define-struct (shift action) (state) #:inspector (make-inspector))
|
||||||
(define-struct (reduce action) (prod runtime-reduce) (make-inspector))
|
(define-struct (reduce action) (prod runtime-reduce) #:inspector (make-inspector))
|
||||||
(define-struct (accept action) () (make-inspector))
|
(define-struct (accept action) () #:inspector (make-inspector))
|
||||||
(define-struct (goto action) (state) (make-inspector))
|
(define-struct (goto action) (state) #:inspector (make-inspector))
|
||||||
(define-struct (no-action action) () (make-inspector))
|
(define-struct (no-action action) () #:inspector (make-inspector))
|
||||||
|
|
||||||
(define (make-reduce* p)
|
(define (make-reduce* p)
|
||||||
(make-reduce p
|
(make-reduce p
|
||||||
(vector (prod-index p)
|
(vector (prod-index p)
|
||||||
(gram-sym-symbol (prod-lhs p))
|
(gram-sym-symbol (prod-lhs p))
|
||||||
(vector-length (prod-rhs p)))))
|
(vector-length (prod-rhs p)))))
|
||||||
|
|
||||||
;; A runtime-action is
|
;; A runtime-action is
|
||||||
;; non-negative-int (shift)
|
;; non-negative-int (shift)
|
||||||
;; (vector int symbol int) (reduce)
|
;; (vector int symbol int) (reduce)
|
||||||
;; 'accept (accept)
|
;; 'accept (accept)
|
||||||
;; negative-int (goto)
|
;; negative-int (goto)
|
||||||
;; #f (no-action)
|
;; #f (no-action)
|
||||||
|
|
||||||
(define (action->runtime-action a)
|
(define (action->runtime-action a)
|
||||||
(cond
|
(cond
|
||||||
((shift? a) (shift-state a))
|
[(shift? a) (shift-state a)]
|
||||||
((reduce? a) (reduce-runtime-reduce a))
|
[(reduce? a) (reduce-runtime-reduce a)]
|
||||||
((accept? a) 'accept)
|
[(accept? a) 'accept]
|
||||||
((goto? a) (- (+ (goto-state a) 1)))
|
[(goto? a) (- (+ (goto-state a) 1))]
|
||||||
((no-action? a) #f)))
|
[(no-action? a) #f]))
|
||||||
|
|
||||||
(define (runtime-shift? x) (and (integer? x) (>= x 0)))
|
(define (runtime-shift? x) (and (integer? x) (>= x 0)))
|
||||||
(define runtime-reduce? vector?)
|
(define runtime-reduce? vector?)
|
||||||
(define (runtime-accept? x) (eq? x 'accept))
|
(define (runtime-accept? x) (eq? x 'accept))
|
||||||
(define (runtime-goto? x) (and (integer? x) (< x 0)))
|
(define (runtime-goto? x) (and (integer? x) (< x 0)))
|
||||||
|
|
||||||
(define runtime-shift-state values)
|
(define runtime-shift-state values)
|
||||||
(define (runtime-reduce-prod-num x) (vector-ref x 0))
|
(define (runtime-reduce-prod-num x) (vector-ref x 0))
|
||||||
(define (runtime-reduce-lhs x) (vector-ref x 1))
|
(define (runtime-reduce-lhs x) (vector-ref x 1))
|
||||||
(define (runtime-reduce-rhs-length x) (vector-ref x 2))
|
(define (runtime-reduce-rhs-length x) (vector-ref x 2))
|
||||||
(define (runtime-goto-state x) (- (+ x 1)))
|
(define (runtime-goto-state x) (- (+ x 1)))
|
||||||
|
|
||||||
)
|
|
||||||
|
@ -1,290 +1,264 @@
|
|||||||
#lang scheme/base
|
#lang racket/base
|
||||||
|
(require "grammar.rkt"
|
||||||
|
"lr0.rkt"
|
||||||
|
"lalr.rkt"
|
||||||
|
"parser-actions.rkt"
|
||||||
|
racket/contract
|
||||||
|
racket/list
|
||||||
|
racket/class)
|
||||||
|
|
||||||
;; Routine to build the LALR table
|
;; Routine to build the LALR table
|
||||||
|
|
||||||
(require "grammar.rkt"
|
|
||||||
"lr0.rkt"
|
|
||||||
"lalr.rkt"
|
|
||||||
"parser-actions.rkt"
|
|
||||||
racket/contract
|
|
||||||
mzlib/list
|
|
||||||
mzlib/class)
|
|
||||||
|
|
||||||
(define (is-a-grammar%? x) (is-a? x grammar%))
|
(define (is-a-grammar%? x) (is-a? x grammar%))
|
||||||
(provide/contract
|
(provide/contract
|
||||||
(build-table (-> is-a-grammar%? string? any/c
|
(build-table (-> is-a-grammar%? string? any/c
|
||||||
(vectorof (listof (cons/c (or/c term? non-term?) action?))))))
|
(vectorof (listof (cons/c (or/c term? non-term?) action?))))))
|
||||||
|
|
||||||
;; A parse-table is (vectorof (listof (cons/c gram-sym? action)))
|
;; A parse-table is (vectorof (listof (cons/c gram-sym? action)))
|
||||||
;; A grouped-parse-table is (vectorof (listof (cons/c gram-sym? (listof action))))
|
;; A grouped-parse-table is (vectorof (listof (cons/c gram-sym? (listof action))))
|
||||||
|
|
||||||
;; make-parse-table : int -> parse-table
|
;; make-parse-table : int -> parse-table
|
||||||
(define (make-parse-table num-states)
|
(define (make-parse-table num-states)
|
||||||
(make-vector num-states null))
|
(make-vector num-states null))
|
||||||
|
|
||||||
;; table-add!: parse-table nat symbol action ->
|
;; table-add!: parse-table nat symbol action ->
|
||||||
(define (table-add! table state-index symbol val)
|
(define (table-add! table state-index symbol val)
|
||||||
(vector-set! table state-index (cons (cons symbol val)
|
(vector-set! table state-index (cons (cons symbol val)
|
||||||
(vector-ref table state-index))))
|
(vector-ref table state-index))))
|
||||||
|
|
||||||
;; group-table : parse-table -> grouped-parse-table
|
;; group-table : parse-table -> grouped-parse-table
|
||||||
(define (group-table table)
|
(define (group-table table)
|
||||||
(list->vector
|
(list->vector
|
||||||
(map
|
(for/list ([state-entry (in-list (vector->list table))])
|
||||||
(lambda (state-entry)
|
(define ht (make-hasheq))
|
||||||
(let ((ht (make-hash)))
|
(for* ([gs/actions (in-list state-entry)]
|
||||||
(for-each
|
[group (in-value (hash-ref ht (car gs/actions) (λ () null)))]
|
||||||
(lambda (gs/actions)
|
#:unless (member (cdr gs/actions) group))
|
||||||
(let ((group (hash-ref ht (car gs/actions) (lambda () null))))
|
(hash-set! ht (car gs/actions) (cons (cdr gs/actions) group)))
|
||||||
(unless (member (cdr gs/actions) group)
|
(hash-map ht cons))))
|
||||||
(hash-set! ht (car gs/actions) (cons (cdr gs/actions) group)))))
|
|
||||||
state-entry)
|
|
||||||
(hash-map ht cons)))
|
|
||||||
(vector->list table))))
|
|
||||||
|
|
||||||
;; table-map : (vectorof (listof (cons/c gram-sym? X))) (gram-sym? X -> Y) ->
|
;; table-map : (vectorof (listof (cons/c gram-sym? X))) (gram-sym? X -> Y) ->
|
||||||
;; (vectorof (listof (cons/c gram-sym? Y)))
|
;; (vectorof (listof (cons/c gram-sym? Y)))
|
||||||
(define (table-map f table)
|
(define (table-map f table)
|
||||||
(list->vector
|
(list->vector
|
||||||
(map
|
(for/list ([state-entry (in-list (vector->list table))])
|
||||||
(lambda (state-entry)
|
(for/list ([gs/X (in-list state-entry)])
|
||||||
(map
|
(cons (car gs/X) (f (car gs/X) (cdr gs/X)))))))
|
||||||
(lambda (gs/X)
|
|
||||||
(cons (car gs/X) (f (car gs/X) (cdr gs/X))))
|
|
||||||
state-entry))
|
|
||||||
(vector->list table))))
|
|
||||||
|
|
||||||
|
(define (bit-vector-for-each f bv)
|
||||||
|
(let loop ([bv bv] [number 0])
|
||||||
|
(cond
|
||||||
|
[(zero? bv) (void)]
|
||||||
|
[(= 1 (bitwise-and 1 bv))
|
||||||
|
(f number)
|
||||||
|
(loop (arithmetic-shift bv -1) (add1 number))]
|
||||||
|
[else (loop (arithmetic-shift bv -1) (add1 number))])))
|
||||||
|
|
||||||
(define (bit-vector-for-each f bv)
|
|
||||||
(letrec ((for-each
|
|
||||||
(lambda (bv number)
|
|
||||||
(cond
|
|
||||||
((= 0 bv) (void))
|
|
||||||
((= 1 (bitwise-and 1 bv))
|
|
||||||
(f number)
|
|
||||||
(for-each (arithmetic-shift bv -1) (add1 number)))
|
|
||||||
(else (for-each (arithmetic-shift bv -1) (add1 number)))))))
|
|
||||||
(for-each bv 0)))
|
|
||||||
|
|
||||||
|
;; print-entry: symbol action output-port ->
|
||||||
|
;; prints the action a for lookahead sym to the given port
|
||||||
|
(define (print-entry sym a port)
|
||||||
|
(define s "\t~a\t\t\t\t\t~a\t~a\n")
|
||||||
|
(cond
|
||||||
|
[(shift? a) (fprintf port s sym "shift" (shift-state a))]
|
||||||
|
[(reduce? a) (fprintf port s sym "reduce" (prod-index (reduce-prod a)))]
|
||||||
|
[(accept? a) (fprintf port s sym "accept" "")]
|
||||||
|
[(goto? a) (fprintf port s sym "goto" (goto-state a))]))
|
||||||
|
|
||||||
;; print-entry: symbol action output-port ->
|
|
||||||
;; prints the action a for lookahead sym to the given port
|
|
||||||
(define (print-entry sym a port)
|
|
||||||
(let ((s "\t~a\t\t\t\t\t~a\t~a\n"))
|
|
||||||
(cond
|
|
||||||
((shift? a)
|
|
||||||
(fprintf port s sym "shift" (shift-state a)))
|
|
||||||
((reduce? a)
|
|
||||||
(fprintf port s sym "reduce" (prod-index (reduce-prod a))))
|
|
||||||
((accept? a)
|
|
||||||
(fprintf port s sym "accept" ""))
|
|
||||||
((goto? a)
|
|
||||||
(fprintf port s sym "goto" (goto-state a))))))
|
|
||||||
|
|
||||||
|
;; count: ('a -> bool) * 'a list -> num
|
||||||
|
;; counts the number of elements in list that satisfy pred
|
||||||
|
(define (count pred list)
|
||||||
|
(cond
|
||||||
|
[(null? list) 0]
|
||||||
|
[(pred (car list)) (+ 1 (count pred (cdr list)))]
|
||||||
|
[else (count pred (cdr list))]))
|
||||||
|
|
||||||
;; count: ('a -> bool) * 'a list -> num
|
;; display-parser: LR0-automaton grouped-parse-table (listof prod?) output-port ->
|
||||||
;; counts the number of elements in list that satisfy pred
|
;; Prints out the parser given by table.
|
||||||
(define (count pred list)
|
(define (display-parser a grouped-table prods port)
|
||||||
(cond
|
(define SR-conflicts 0)
|
||||||
((null? list) 0)
|
(define RR-conflicts 0)
|
||||||
((pred (car list)) (+ 1 (count pred (cdr list))))
|
(for ([prod (in-list prods)])
|
||||||
(else (count pred (cdr list)))))
|
(fprintf port
|
||||||
|
"~a\t~a\t=\t~a\n"
|
||||||
|
(prod-index prod)
|
||||||
|
(gram-sym-symbol (prod-lhs prod))
|
||||||
|
(map gram-sym-symbol (vector->list (prod-rhs prod)))))
|
||||||
|
|
||||||
;; display-parser: LR0-automaton grouped-parse-table (listof prod?) output-port ->
|
(send a for-each-state
|
||||||
;; Prints out the parser given by table.
|
(λ (state)
|
||||||
(define (display-parser a grouped-table prods port)
|
|
||||||
(let* ((SR-conflicts 0)
|
|
||||||
(RR-conflicts 0))
|
|
||||||
(for-each
|
|
||||||
(lambda (prod)
|
|
||||||
(fprintf port
|
|
||||||
"~a\t~a\t=\t~a\n"
|
|
||||||
(prod-index prod)
|
|
||||||
(gram-sym-symbol (prod-lhs prod))
|
|
||||||
(map gram-sym-symbol (vector->list (prod-rhs prod)))))
|
|
||||||
prods)
|
|
||||||
(send a for-each-state
|
|
||||||
(lambda (state)
|
|
||||||
(fprintf port "State ~a\n" (kernel-index state))
|
(fprintf port "State ~a\n" (kernel-index state))
|
||||||
(for-each (lambda (item)
|
(for ([item (in-list (kernel-items state))])
|
||||||
(fprintf port "\t~a\n" (item->string item)))
|
(fprintf port "\t~a\n" (item->string item)))
|
||||||
(kernel-items state))
|
|
||||||
(newline port)
|
(newline port)
|
||||||
(for-each
|
(for ([gs/action (in-list (vector-ref grouped-table (kernel-index state)))])
|
||||||
(lambda (gs/action)
|
(define sym (gram-sym-symbol (car gs/action)))
|
||||||
(let ((sym (gram-sym-symbol (car gs/action)))
|
(define act (cdr gs/action))
|
||||||
(act (cdr gs/action)))
|
(cond
|
||||||
(cond
|
[(null? act) (void)]
|
||||||
((null? act) (void))
|
[(null? (cdr act))
|
||||||
((null? (cdr act))
|
(print-entry sym (car act) port)]
|
||||||
(print-entry sym (car act) port))
|
[else
|
||||||
(else
|
(fprintf port "begin conflict:\n")
|
||||||
(fprintf port "begin conflict:\n")
|
(when (> (count reduce? act) 1)
|
||||||
(when (> (count reduce? act) 1)
|
(set! RR-conflicts (add1 RR-conflicts)))
|
||||||
(set! RR-conflicts (add1 RR-conflicts)))
|
(when (> (count shift? act) 0)
|
||||||
(when (> (count shift? act) 0)
|
(set! SR-conflicts (add1 SR-conflicts)))
|
||||||
(set! SR-conflicts (add1 SR-conflicts)))
|
(map (λ (x) (print-entry sym x port)) act)
|
||||||
(map (lambda (x) (print-entry sym x port)) act)
|
(fprintf port "end conflict\n")]))
|
||||||
(fprintf port "end conflict\n")))))
|
|
||||||
(vector-ref grouped-table (kernel-index state)))
|
|
||||||
(newline port)))
|
(newline port)))
|
||||||
|
|
||||||
(when (> SR-conflicts 0)
|
(when (> SR-conflicts 0)
|
||||||
(fprintf port "~a shift/reduce conflict~a\n"
|
(fprintf port "~a shift/reduce conflict~a\n"
|
||||||
SR-conflicts
|
SR-conflicts
|
||||||
(if (= SR-conflicts 1) "" "s")))
|
(if (= SR-conflicts 1) "" "s")))
|
||||||
(when (> RR-conflicts 0)
|
(when (> RR-conflicts 0)
|
||||||
(fprintf port "~a reduce/reduce conflict~a\n"
|
(fprintf port "~a reduce/reduce conflict~a\n"
|
||||||
RR-conflicts
|
RR-conflicts
|
||||||
(if (= RR-conflicts 1) "" "s")))))
|
(if (= RR-conflicts 1) "" "s"))))
|
||||||
|
|
||||||
;; resolve-conflict : (listof action?) -> action? bool bool
|
|
||||||
(define (resolve-conflict actions)
|
|
||||||
(cond
|
|
||||||
((null? actions) (values (make-no-action) #f #f))
|
|
||||||
((null? (cdr actions))
|
|
||||||
(values (car actions) #f #f))
|
|
||||||
(else
|
|
||||||
(let ((SR-conflict? (> (count shift? actions) 0))
|
|
||||||
(RR-conflict? (> (count reduce? actions) 1)))
|
|
||||||
(let loop ((current-guess #f)
|
|
||||||
(rest actions))
|
|
||||||
(cond
|
|
||||||
((null? rest) (values current-guess SR-conflict? RR-conflict?))
|
|
||||||
((shift? (car rest)) (values (car rest) SR-conflict? RR-conflict?))
|
|
||||||
((not current-guess)
|
|
||||||
(loop (car rest) (cdr rest)))
|
|
||||||
((and (reduce? (car rest))
|
|
||||||
(< (prod-index (reduce-prod (car rest)))
|
|
||||||
(prod-index (reduce-prod current-guess))))
|
|
||||||
(loop (car rest) (cdr rest)))
|
|
||||||
((accept? (car rest))
|
|
||||||
(eprintf "accept/reduce or accept/shift conflicts. Check the grammar for useless cycles of productions\n")
|
|
||||||
(loop current-guess (cdr rest)))
|
|
||||||
(else (loop current-guess (cdr rest)))))))))
|
|
||||||
|
|
||||||
;; resolve-conflicts : grouped-parse-table bool -> parse-table
|
;; resolve-conflict : (listof action?) -> action? bool bool
|
||||||
(define (resolve-conflicts grouped-table suppress)
|
(define (resolve-conflict actions)
|
||||||
(let* ((SR-conflicts 0)
|
(cond
|
||||||
(RR-conflicts 0)
|
[(null? actions) (values (make-no-action) #f #f)]
|
||||||
(table (table-map
|
[(null? (cdr actions)) (values (car actions) #f #f)]
|
||||||
(lambda (gs actions)
|
[else
|
||||||
(let-values (((action SR? RR?)
|
(define SR-conflict? (> (count shift? actions) 0))
|
||||||
(resolve-conflict actions)))
|
(define RR-conflict? (> (count reduce? actions) 1))
|
||||||
(when SR?
|
(let loop ((current-guess #f)
|
||||||
(set! SR-conflicts (add1 SR-conflicts)))
|
(rest actions))
|
||||||
(when RR?
|
(cond
|
||||||
(set! RR-conflicts (add1 RR-conflicts)))
|
[(null? rest) (values current-guess SR-conflict? RR-conflict?)]
|
||||||
action))
|
[(shift? (car rest)) (values (car rest) SR-conflict? RR-conflict?)]
|
||||||
grouped-table)))
|
[(not current-guess) (loop (car rest) (cdr rest))]
|
||||||
(unless suppress
|
[(and (reduce? (car rest))
|
||||||
(when (> SR-conflicts 0)
|
(< (prod-index (reduce-prod (car rest)))
|
||||||
(eprintf "~a shift/reduce conflict~a\n"
|
(prod-index (reduce-prod current-guess))))
|
||||||
SR-conflicts
|
(loop (car rest) (cdr rest))]
|
||||||
(if (= SR-conflicts 1) "" "s")))
|
[(accept? (car rest))
|
||||||
(when (> RR-conflicts 0)
|
(eprintf "accept/reduce or accept/shift conflicts. Check the grammar for useless cycles of productions\n")
|
||||||
(eprintf "~a reduce/reduce conflict~a\n"
|
(loop current-guess (cdr rest))]
|
||||||
RR-conflicts
|
[else (loop current-guess (cdr rest))]))]))
|
||||||
(if (= RR-conflicts 1) "" "s"))))
|
|
||||||
table))
|
|
||||||
|
|
||||||
|
;; resolve-conflicts : grouped-parse-table bool -> parse-table
|
||||||
|
(define (resolve-conflicts grouped-table suppress)
|
||||||
|
(define SR-conflicts 0)
|
||||||
|
(define RR-conflicts 0)
|
||||||
|
(define table (table-map
|
||||||
|
(λ (gs actions)
|
||||||
|
(let-values ([(action SR? RR?)
|
||||||
|
(resolve-conflict actions)])
|
||||||
|
(when SR?
|
||||||
|
(set! SR-conflicts (add1 SR-conflicts)))
|
||||||
|
(when RR?
|
||||||
|
(set! RR-conflicts (add1 RR-conflicts)))
|
||||||
|
action))
|
||||||
|
grouped-table))
|
||||||
|
(unless suppress
|
||||||
|
(when (> SR-conflicts 0)
|
||||||
|
(eprintf "~a shift/reduce conflict~a\n"
|
||||||
|
SR-conflicts
|
||||||
|
(if (= SR-conflicts 1) "" "s")))
|
||||||
|
(when (> RR-conflicts 0)
|
||||||
|
(eprintf "~a reduce/reduce conflict~a\n"
|
||||||
|
RR-conflicts
|
||||||
|
(if (= RR-conflicts 1) "" "s"))))
|
||||||
|
table)
|
||||||
|
|
||||||
;; resolve-sr-conflict : (listof action) (union int #f) -> (listof action)
|
|
||||||
;; Resolves a single shift-reduce conflict, if precedences are in place.
|
|
||||||
(define (resolve-sr-conflict/prec actions shift-prec)
|
|
||||||
(let* ((shift (if (shift? (car actions))
|
|
||||||
(car actions)
|
|
||||||
(cadr actions)))
|
|
||||||
(reduce (if (shift? (car actions))
|
|
||||||
(cadr actions)
|
|
||||||
(car actions)))
|
|
||||||
(reduce-prec (prod-prec (reduce-prod reduce))))
|
|
||||||
(cond
|
|
||||||
((and shift-prec reduce-prec)
|
|
||||||
(cond
|
|
||||||
((< (prec-num shift-prec) (prec-num reduce-prec))
|
|
||||||
(list reduce))
|
|
||||||
((> (prec-num shift-prec) (prec-num reduce-prec))
|
|
||||||
(list shift))
|
|
||||||
((eq? 'left (prec-assoc shift-prec))
|
|
||||||
(list reduce))
|
|
||||||
((eq? 'right (prec-assoc shift-prec))
|
|
||||||
(list shift))
|
|
||||||
(else null)))
|
|
||||||
(else actions))))
|
|
||||||
|
|
||||||
|
;; resolve-sr-conflict : (listof action) (union int #f) -> (listof action)
|
||||||
|
;; Resolves a single shift-reduce conflict, if precedences are in place.
|
||||||
|
(define (resolve-sr-conflict/prec actions shift-prec)
|
||||||
|
(define shift (if (shift? (car actions))
|
||||||
|
(car actions)
|
||||||
|
(cadr actions)))
|
||||||
|
(define reduce (if (shift? (car actions))
|
||||||
|
(cadr actions)
|
||||||
|
(car actions)))
|
||||||
|
(define reduce-prec (prod-prec (reduce-prod reduce)))
|
||||||
|
(cond
|
||||||
|
[(and shift-prec reduce-prec)
|
||||||
|
(cond
|
||||||
|
[(< (prec-num shift-prec) (prec-num reduce-prec))
|
||||||
|
(list reduce)]
|
||||||
|
[(> (prec-num shift-prec) (prec-num reduce-prec))
|
||||||
|
(list shift)]
|
||||||
|
[(eq? 'left (prec-assoc shift-prec))
|
||||||
|
(list reduce)]
|
||||||
|
[(eq? 'right (prec-assoc shift-prec))
|
||||||
|
(list shift)]
|
||||||
|
[else null])]
|
||||||
|
[else actions]))
|
||||||
|
|
||||||
;; resolve-prec-conflicts : parse-table -> grouped-parse-table
|
|
||||||
(define (resolve-prec-conflicts table)
|
|
||||||
(table-map
|
|
||||||
(lambda (gs actions)
|
|
||||||
(cond
|
|
||||||
((and (term? gs)
|
|
||||||
(= 2 (length actions))
|
|
||||||
(or (shift? (car actions))
|
|
||||||
(shift? (cadr actions))))
|
|
||||||
(resolve-sr-conflict/prec actions (term-prec gs)))
|
|
||||||
(else actions)))
|
|
||||||
(group-table table)))
|
|
||||||
|
|
||||||
;; build-table: grammar string bool -> parse-table
|
;; resolve-prec-conflicts : parse-table -> grouped-parse-table
|
||||||
(define (build-table g file suppress)
|
(define (resolve-prec-conflicts table)
|
||||||
(let* ((a (build-lr0-automaton g))
|
(table-map
|
||||||
(term-vector (list->vector (send g get-terms)))
|
(λ (gs actions)
|
||||||
(end-terms (send g get-end-terms))
|
(cond
|
||||||
(table (make-parse-table (send a get-num-states)))
|
[(and (term? gs)
|
||||||
(get-lookahead (compute-LA a g))
|
(= 2 (length actions))
|
||||||
(reduce-cache (make-hash)))
|
(or (shift? (car actions))
|
||||||
|
(shift? (cadr actions))))
|
||||||
|
(resolve-sr-conflict/prec actions (term-prec gs))]
|
||||||
|
[else actions]))
|
||||||
|
(group-table table)))
|
||||||
|
|
||||||
(for-each
|
;; build-table: grammar string bool -> parse-table
|
||||||
(lambda (trans-key/state)
|
(define (build-table g file suppress)
|
||||||
(let ((from-state-index (kernel-index (trans-key-st (car trans-key/state))))
|
(define a (build-lr0-automaton g))
|
||||||
(gs (trans-key-gs (car trans-key/state)))
|
(define term-vector (list->vector (send g get-terms)))
|
||||||
(to-state (cdr trans-key/state)))
|
(define end-terms (send g get-end-terms))
|
||||||
(table-add! table from-state-index gs
|
(define table (make-parse-table (send a get-num-states)))
|
||||||
(cond
|
(define get-lookahead (compute-LA a g))
|
||||||
((non-term? gs)
|
(define reduce-cache (make-hash))
|
||||||
(make-goto (kernel-index to-state)))
|
(for ([trans-key/state (in-list (send a get-transitions))])
|
||||||
((member gs end-terms)
|
(define from-state-index (kernel-index (trans-key-st (car trans-key/state))))
|
||||||
(make-accept))
|
(define gs (trans-key-gs (car trans-key/state)))
|
||||||
(else
|
(define to-state (cdr trans-key/state))
|
||||||
(make-shift
|
|
||||||
(kernel-index to-state)))))))
|
|
||||||
(send a get-transitions))
|
|
||||||
|
|
||||||
(send a for-each-state
|
(table-add! table from-state-index gs
|
||||||
(lambda (state)
|
(cond
|
||||||
(for-each
|
((non-term? gs)
|
||||||
(lambda (item)
|
(make-goto (kernel-index to-state)))
|
||||||
(let ((item-prod (item-prod item)))
|
((member gs end-terms)
|
||||||
(bit-vector-for-each
|
(make-accept))
|
||||||
(lambda (term-index)
|
(else
|
||||||
(unless (start-item? item)
|
(make-shift
|
||||||
(let ((r (hash-ref reduce-cache item-prod
|
(kernel-index to-state))))))
|
||||||
(lambda ()
|
(send a for-each-state
|
||||||
(let ((r (make-reduce item-prod)))
|
(λ (state)
|
||||||
(hash-set! reduce-cache item-prod r)
|
(for ([item (in-list (append (hash-ref (send a get-epsilon-trans) state (λ () null))
|
||||||
r)))))
|
(filter (λ (item)
|
||||||
(table-add! table
|
(not (move-dot-right item)))
|
||||||
(kernel-index state)
|
(kernel-items state))))])
|
||||||
(vector-ref term-vector term-index)
|
(let ([item-prod (item-prod item)])
|
||||||
r))))
|
(bit-vector-for-each
|
||||||
(get-lookahead state item-prod))))
|
(λ (term-index)
|
||||||
(append (hash-ref (send a get-epsilon-trans) state (lambda () null))
|
(unless (start-item? item)
|
||||||
(filter (lambda (item)
|
(let ((r (hash-ref reduce-cache item-prod
|
||||||
(not (move-dot-right item)))
|
(λ ()
|
||||||
(kernel-items state))))))
|
(let ((r (make-reduce item-prod)))
|
||||||
|
(hash-set! reduce-cache item-prod r)
|
||||||
|
r)))))
|
||||||
|
(table-add! table
|
||||||
|
(kernel-index state)
|
||||||
|
(vector-ref term-vector term-index)
|
||||||
|
r))))
|
||||||
|
(get-lookahead state item-prod))))))
|
||||||
|
|
||||||
(let ((grouped-table (resolve-prec-conflicts table)))
|
(define grouped-table (resolve-prec-conflicts table))
|
||||||
(unless (string=? file "")
|
(unless (string=? file "")
|
||||||
(with-handlers [(exn:fail:filesystem?
|
(with-handlers [(exn:fail:filesystem?
|
||||||
(lambda (e)
|
(λ (e)
|
||||||
(eprintf
|
(eprintf
|
||||||
"Cannot write debug output to file \"~a\": ~a\n"
|
"Cannot write debug output to file \"~a\": ~a\n"
|
||||||
file
|
file
|
||||||
(exn-message e))))]
|
(exn-message e))))]
|
||||||
(call-with-output-file file
|
(call-with-output-file file
|
||||||
(lambda (port)
|
(λ (port)
|
||||||
(display-parser a grouped-table (send g get-prods) port))
|
(display-parser a grouped-table (send g get-prods) port))
|
||||||
#:exists 'truncate)))
|
#:exists 'truncate)))
|
||||||
(resolve-conflicts grouped-table suppress))))
|
(resolve-conflicts grouped-table suppress))
|
||||||
|
@ -1,118 +1,71 @@
|
|||||||
(module yacc-helper mzscheme
|
#lang racket/base
|
||||||
|
(require (prefix-in rl: racket/list)
|
||||||
|
"../private-lex/token-syntax.rkt")
|
||||||
|
|
||||||
(require mzlib/list
|
;; General helper routines
|
||||||
"../private-lex/token-syntax.rkt")
|
(provide duplicate-list? remove-duplicates overlap? vector-andmap display-yacc)
|
||||||
|
|
||||||
;; General helper routines
|
(define (vector-andmap pred vec)
|
||||||
|
(for/and ([item (in-vector vec)])
|
||||||
|
(pred vec)))
|
||||||
|
|
||||||
(provide duplicate-list? remove-duplicates overlap? vector-andmap display-yacc)
|
;; duplicate-list?: symbol list -> #f | symbol
|
||||||
|
;; returns a symbol that exists twice in l, or false if no such symbol
|
||||||
|
;; exists
|
||||||
|
(define (duplicate-list? syms)
|
||||||
|
(rl:check-duplicates syms eq?))
|
||||||
|
|
||||||
(define (vector-andmap f v)
|
;; remove-duplicates: syntax-object list -> syntax-object list
|
||||||
(let loop ((i 0))
|
;; removes the duplicates from the lists
|
||||||
(cond
|
(define (remove-duplicates syms)
|
||||||
((= i (vector-length v)) #t)
|
(rl:remove-duplicates syms equal? #:key syntax->datum))
|
||||||
(else (if (f (vector-ref v i))
|
|
||||||
(loop (add1 i))
|
|
||||||
#f)))))
|
|
||||||
|
|
||||||
;; duplicate-list?: symbol list -> #f | symbol
|
;; overlap?: symbol list * symbol list -> #f | symbol
|
||||||
;; returns a symbol that exists twice in l, or false if no such symbol
|
;; Returns an symbol in l1 intersect l2, or #f is no such symbol exists
|
||||||
;; exists
|
(define (overlap? syms1 syms2)
|
||||||
(define (duplicate-list? l)
|
(for/first ([sym1 (in-list syms1)]
|
||||||
(letrec ((t (make-hash-table))
|
#:when (memq sym1 syms2))
|
||||||
(dl? (lambda (l)
|
sym1))
|
||||||
(cond
|
|
||||||
((null? l) #f)
|
|
||||||
((hash-table-get t (car l) (lambda () #f)) =>
|
|
||||||
(lambda (x) x))
|
|
||||||
(else
|
|
||||||
(hash-table-put! t (car l) (car l))
|
|
||||||
(dl? (cdr l)))))))
|
|
||||||
(dl? l)))
|
|
||||||
|
|
||||||
;; remove-duplicates: syntax-object list -> syntax-object list
|
|
||||||
;; removes the duplicates from the lists
|
|
||||||
(define (remove-duplicates sl)
|
|
||||||
(let ((t (make-hash-table)))
|
|
||||||
(letrec ((x
|
|
||||||
(lambda (sl)
|
|
||||||
(cond
|
|
||||||
((null? sl) sl)
|
|
||||||
((hash-table-get t (syntax-object->datum (car sl)) (lambda () #f))
|
|
||||||
(x (cdr sl)))
|
|
||||||
(else
|
|
||||||
(hash-table-put! t (syntax-object->datum (car sl)) #t)
|
|
||||||
(cons (car sl) (x (cdr sl))))))))
|
|
||||||
(x sl))))
|
|
||||||
|
|
||||||
;; overlap?: symbol list * symbol list -> #f | symbol
|
(define (display-yacc grammar tokens start precs port)
|
||||||
;; Returns an symbol in l1 intersect l2, or #f is no such symbol exists
|
(let-syntax ([p (syntax-rules ()
|
||||||
(define (overlap? l1 l2)
|
((_ args ...) (fprintf port args ...)))])
|
||||||
(let/ec ret
|
(let* ([tokens (map syntax-local-value tokens)]
|
||||||
(let ((t (make-hash-table)))
|
[eterms (filter e-terminals-def? tokens)]
|
||||||
(for-each (lambda (s1)
|
[terms (filter terminals-def? tokens)]
|
||||||
(hash-table-put! t s1 s1))
|
[term-table (make-hasheq)]
|
||||||
l1)
|
[display-rhs
|
||||||
(for-each (lambda (s2)
|
(λ (rhs)
|
||||||
(cond
|
(for ([sym (in-list (car rhs))])
|
||||||
((hash-table-get t s2 (lambda () #f)) =>
|
(p "~a " (hash-ref term-table sym (λ () sym))))
|
||||||
(lambda (o) (ret o)))))
|
(when (= 3 (length rhs))
|
||||||
l2)
|
(p "%prec ~a" (cadadr rhs)))
|
||||||
#f)))
|
(p "\n"))])
|
||||||
|
(for* ([t (in-list eterms)]
|
||||||
|
[t (in-list (syntax->datum (e-terminals-def-t t)))])
|
||||||
|
(hash-set! term-table t (format "'~a'" t)))
|
||||||
|
(for* ([t (in-list terms)]
|
||||||
|
[t (in-list (syntax->datum (terminals-def-t t)))])
|
||||||
|
(p "%token ~a\n" t)
|
||||||
|
(hash-set! term-table t (format "~a" t)))
|
||||||
|
(when precs
|
||||||
|
(for ([prec (in-list precs)])
|
||||||
|
(p "%~a " (car prec))
|
||||||
|
(for ([tok (in-list (cdr prec))])
|
||||||
|
(p " ~a" (hash-ref term-table tok)))
|
||||||
|
(p "\n")))
|
||||||
|
(p "%start ~a\n" start)
|
||||||
|
(p "%%\n")
|
||||||
|
(for ([prod (in-list grammar)])
|
||||||
|
(define nt (car prod))
|
||||||
|
(p "~a: " nt)
|
||||||
|
(display-rhs (cadr prod))
|
||||||
|
(for ([rhs (in-list (cddr prod))])
|
||||||
|
(p "| ")
|
||||||
|
(display-rhs rhs))
|
||||||
|
(p ";\n"))
|
||||||
|
(p "%%\n"))))
|
||||||
|
|
||||||
|
|
||||||
(define (display-yacc grammar tokens start precs port)
|
|
||||||
(let-syntax ((p (syntax-rules ()
|
|
||||||
((_ args ...) (fprintf port args ...)))))
|
|
||||||
(let* ((tokens (map syntax-local-value tokens))
|
|
||||||
(eterms (filter e-terminals-def? tokens))
|
|
||||||
(terms (filter terminals-def? tokens))
|
|
||||||
(term-table (make-hash-table))
|
|
||||||
(display-rhs
|
|
||||||
(lambda (rhs)
|
|
||||||
(for-each (lambda (sym) (p "~a " (hash-table-get term-table sym (lambda () sym))))
|
|
||||||
(car rhs))
|
|
||||||
(if (= 3 (length rhs))
|
|
||||||
(p "%prec ~a" (cadadr rhs)))
|
|
||||||
(p "\n"))))
|
|
||||||
(for-each
|
|
||||||
(lambda (t)
|
|
||||||
(for-each
|
|
||||||
(lambda (t)
|
|
||||||
(hash-table-put! term-table t (format "'~a'" t)))
|
|
||||||
(syntax-object->datum (e-terminals-def-t t))))
|
|
||||||
eterms)
|
|
||||||
(for-each
|
|
||||||
(lambda (t)
|
|
||||||
(for-each
|
|
||||||
(lambda (t)
|
|
||||||
(p "%token ~a\n" t)
|
|
||||||
(hash-table-put! term-table t (format "~a" t)))
|
|
||||||
(syntax-object->datum (terminals-def-t t))))
|
|
||||||
terms)
|
|
||||||
(if precs
|
|
||||||
(for-each (lambda (prec)
|
|
||||||
(p "%~a " (car prec))
|
|
||||||
(for-each (lambda (tok)
|
|
||||||
(p " ~a" (hash-table-get term-table tok)))
|
|
||||||
(cdr prec))
|
|
||||||
(p "\n"))
|
|
||||||
precs))
|
|
||||||
(p "%start ~a\n" start)
|
|
||||||
(p "%%\n")
|
|
||||||
|
|
||||||
(for-each (lambda (prod)
|
|
||||||
(let ((nt (car prod)))
|
|
||||||
(p "~a: " nt)
|
|
||||||
(display-rhs (cadr prod))
|
|
||||||
(for-each (lambda (rhs)
|
|
||||||
(p "| ")
|
|
||||||
(display-rhs rhs))
|
|
||||||
(cddr prod))
|
|
||||||
(p ";\n")))
|
|
||||||
grammar)
|
|
||||||
(p "%%\n"))))
|
|
||||||
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
|
@ -1,135 +1,130 @@
|
|||||||
(module yacc-to-scheme mzscheme
|
#lang racket/base
|
||||||
(require br-parser-tools/lex
|
(require br-parser-tools/lex
|
||||||
(prefix : br-parser-tools/lex-sre)
|
(prefix-in : br-parser-tools/lex-sre)
|
||||||
br-parser-tools/yacc
|
br-parser-tools/yacc
|
||||||
syntax/readerr
|
syntax/readerr
|
||||||
mzlib/list)
|
racket/list)
|
||||||
(provide trans)
|
(provide trans)
|
||||||
|
|
||||||
(define match-double-string
|
(define match-double-string
|
||||||
(lexer
|
(lexer
|
||||||
((:+ (:~ #\" #\\)) (append (string->list lexeme)
|
[(:+ (:~ #\" #\\)) (append (string->list lexeme)
|
||||||
(match-double-string input-port)))
|
(match-double-string input-port))]
|
||||||
((:: #\\ any-char) (cons (string-ref lexeme 1) (match-double-string input-port)))
|
[(:: #\\ any-char) (cons (string-ref lexeme 1) (match-double-string input-port))]
|
||||||
(#\" null)))
|
[#\" null]))
|
||||||
|
|
||||||
(define match-single-string
|
(define match-single-string
|
||||||
(lexer
|
(lexer
|
||||||
((:+ (:~ #\' #\\)) (append (string->list lexeme)
|
[(:+ (:~ #\' #\\)) (append (string->list lexeme)
|
||||||
(match-single-string input-port)))
|
(match-single-string input-port))]
|
||||||
((:: #\\ any-char) (cons (string-ref lexeme 1) (match-single-string input-port)))
|
[(:: #\\ any-char) (cons (string-ref lexeme 1) (match-single-string input-port))]
|
||||||
(#\' null)))
|
[#\' null]))
|
||||||
|
|
||||||
(define-lex-abbrevs
|
(define-lex-abbrevs
|
||||||
(letter (:or (:/ "a" "z") (:/ "A" "Z")))
|
[letter (:or (:/ "a" "z") (:/ "A" "Z"))]
|
||||||
(digit (:/ "0" "9"))
|
[digit (:/ "0" "9")]
|
||||||
(initial (:or letter (char-set "!$%&*/<=>?^_~@")))
|
[initial (:or letter (char-set "!$%&*/<=>?^_~@"))]
|
||||||
(subsequent (:or initial digit (char-set "+-.@")))
|
[subsequent (:or initial digit (char-set "+-.@"))]
|
||||||
(comment (:: "/*" (complement (:: any-string "*/" any-string)) "*/")))
|
[comment (:: "/*" (complement (:: any-string "*/" any-string)) "*/")])
|
||||||
|
|
||||||
(define-empty-tokens x
|
(define-empty-tokens x (EOF PIPE |:| SEMI |%%| %prec))
|
||||||
(EOF PIPE |:| SEMI |%%| %prec))
|
(define-tokens y (SYM STRING))
|
||||||
(define-tokens y
|
|
||||||
(SYM STRING))
|
|
||||||
|
|
||||||
(define get-token-grammar
|
(define get-token-grammar
|
||||||
(lexer-src-pos
|
(lexer-src-pos
|
||||||
("%%" '|%%|)
|
["%%" '|%%|]
|
||||||
(":" (string->symbol lexeme))
|
[":" (string->symbol lexeme)]
|
||||||
("%prec" (string->symbol lexeme))
|
["%prec" (string->symbol lexeme)]
|
||||||
(#\| 'PIPE)
|
[#\| 'PIPE]
|
||||||
((:+ (:or #\newline #\tab " " comment (:: "{" (:* (:~ "}")) "}")))
|
[(:+ (:or #\newline #\tab " " comment (:: "{" (:* (:~ "}")) "}")))
|
||||||
(return-without-pos (get-token-grammar input-port)))
|
(return-without-pos (get-token-grammar input-port))]
|
||||||
(#\; 'SEMI)
|
[#\; 'SEMI]
|
||||||
(#\' (token-STRING (string->symbol (list->string (match-single-string input-port)))))
|
[#\' (token-STRING (string->symbol (list->string (match-single-string input-port))))]
|
||||||
(#\" (token-STRING (string->symbol (list->string (match-double-string input-port)))))
|
[#\" (token-STRING (string->symbol (list->string (match-double-string input-port))))]
|
||||||
((:: initial (:* subsequent)) (token-SYM (string->symbol lexeme)))))
|
[(:: initial (:* subsequent)) (token-SYM (string->symbol lexeme))]))
|
||||||
|
|
||||||
(define (parse-grammar enter-term enter-empty-term enter-non-term)
|
(define (parse-grammar enter-term enter-empty-term enter-non-term)
|
||||||
(parser
|
(parser
|
||||||
(tokens x y)
|
(tokens x y)
|
||||||
(src-pos)
|
(src-pos)
|
||||||
(error (lambda (tok-ok tok-name tok-value start-pos end-pos)
|
(error (λ (tok-ok tok-name tok-value start-pos end-pos)
|
||||||
(raise-read-error
|
(raise-read-error
|
||||||
(format "Error Parsing YACC grammar at token: ~a with value: ~a" tok-name tok-value)
|
(format "Error Parsing YACC grammar at token: ~a with value: ~a" tok-name tok-value)
|
||||||
(file-path)
|
(file-path)
|
||||||
(position-line start-pos)
|
(position-line start-pos)
|
||||||
(position-col start-pos)
|
(position-col start-pos)
|
||||||
(position-offset start-pos)
|
(position-offset start-pos)
|
||||||
(- (position-offset end-pos) (position-offset start-pos)))))
|
(- (position-offset end-pos) (position-offset start-pos)))))
|
||||||
|
|
||||||
(end |%%|)
|
(end |%%|)
|
||||||
(start gram)
|
(start gram)
|
||||||
(grammar
|
(grammar
|
||||||
(gram
|
(gram
|
||||||
((production) (list $1))
|
((production) (list $1))
|
||||||
((production gram) (cons $1 $2)))
|
((production gram) (cons $1 $2)))
|
||||||
(production
|
(production
|
||||||
((SYM |:| prods SEMI)
|
((SYM |:| prods SEMI)
|
||||||
(begin
|
(begin
|
||||||
(enter-non-term $1)
|
(enter-non-term $1)
|
||||||
(cons $1 $3))))
|
(cons $1 $3))))
|
||||||
(prods
|
(prods
|
||||||
((rhs) (list `(,$1 #f)))
|
((rhs) (list `(,$1 #f)))
|
||||||
((rhs prec) (list `(,$1 ,$2 #f)))
|
((rhs prec) (list `(,$1 ,$2 #f)))
|
||||||
((rhs PIPE prods) (cons `(,$1 #f) $3))
|
((rhs PIPE prods) (cons `(,$1 #f) $3))
|
||||||
((rhs prec PIPE prods) (cons `(,$1 ,$2 #f) $4)))
|
((rhs prec PIPE prods) (cons `(,$1 ,$2 #f) $4)))
|
||||||
(prec
|
(prec
|
||||||
((%prec SYM)
|
((%prec SYM)
|
||||||
(begin
|
(begin
|
||||||
(enter-term $2)
|
(enter-term $2)
|
||||||
(list 'prec $2)))
|
(list 'prec $2)))
|
||||||
((%prec STRING)
|
((%prec STRING)
|
||||||
(begin
|
(begin
|
||||||
(enter-empty-term $2)
|
(enter-empty-term $2)
|
||||||
(list 'prec $2))))
|
(list 'prec $2))))
|
||||||
(rhs
|
(rhs
|
||||||
(() null)
|
(() null)
|
||||||
((SYM rhs)
|
((SYM rhs)
|
||||||
(begin
|
(begin
|
||||||
(enter-term $1)
|
(enter-term $1)
|
||||||
(cons $1 $2)))
|
(cons $1 $2)))
|
||||||
((STRING rhs)
|
((STRING rhs)
|
||||||
(begin
|
(begin
|
||||||
(enter-empty-term $1)
|
(enter-empty-term $1)
|
||||||
(cons $1 $2)))))))
|
(cons $1 $2)))))))
|
||||||
|
|
||||||
(define (symbol<? a b)
|
(define (symbol<? a b)
|
||||||
(string<? (symbol->string a) (symbol->string b)))
|
(string<? (symbol->string a) (symbol->string b)))
|
||||||
|
|
||||||
(define (trans filename)
|
(define (trans filename)
|
||||||
(let* ((i (open-input-file filename))
|
(define i (open-input-file filename))
|
||||||
(terms (make-hash-table))
|
(define terms (make-hasheq))
|
||||||
(eterms (make-hash-table))
|
(define eterms (make-hasheq))
|
||||||
(nterms (make-hash-table))
|
(define nterms (make-hasheq))
|
||||||
(enter-term
|
(define (enter-term s)
|
||||||
(lambda (s)
|
(when (not (hash-ref nterms s (λ () #f)))
|
||||||
(if (not (hash-table-get nterms s (lambda () #f)))
|
(hash-set! terms s #t)))
|
||||||
(hash-table-put! terms s #t))))
|
(define (enter-empty-term s)
|
||||||
(enter-empty-term
|
(when (not (hash-ref nterms s (λ () #f)))
|
||||||
(lambda (s)
|
(hash-set! eterms s #t)))
|
||||||
(if (not (hash-table-get nterms s (lambda () #f)))
|
(define (enter-non-term s)
|
||||||
(hash-table-put! eterms s #t))))
|
(hash-remove! terms s)
|
||||||
(enter-non-term
|
(hash-remove! eterms s)
|
||||||
(lambda (s)
|
(hash-set! nterms s #t))
|
||||||
(hash-table-remove! terms s)
|
(port-count-lines! i)
|
||||||
(hash-table-remove! eterms s)
|
(file-path filename)
|
||||||
(hash-table-put! nterms s #t))))
|
(regexp-match "%%" i)
|
||||||
(port-count-lines! i)
|
(begin0
|
||||||
(file-path filename)
|
(let ([gram ((parse-grammar enter-term enter-empty-term enter-non-term)
|
||||||
(regexp-match "%%" i)
|
(λ ()
|
||||||
(begin0
|
(let ((t (get-token-grammar i)))
|
||||||
(let ((gram ((parse-grammar enter-term enter-empty-term enter-non-term)
|
t)))])
|
||||||
(lambda ()
|
`(begin
|
||||||
(let ((t (get-token-grammar i)))
|
(define-tokens t ,(sort (hash-map terms (λ (k v) k)) symbol<?))
|
||||||
t)))))
|
(define-empty-tokens et ,(sort (hash-map eterms (λ (k v) k)) symbol<?))
|
||||||
`(begin
|
(parser
|
||||||
(define-tokens t ,(sort (hash-table-map terms (lambda (k v) k)) symbol<?))
|
(start ___)
|
||||||
(define-empty-tokens et ,(sort (hash-table-map eterms (lambda (k v) k)) symbol<?))
|
(end ___)
|
||||||
(parser
|
(error ___)
|
||||||
(start ___)
|
(tokens t et)
|
||||||
(end ___)
|
(grammar ,@gram))))
|
||||||
(error ___)
|
(close-input-port i)))
|
||||||
(tokens t et)
|
|
||||||
(grammar ,@gram))))
|
|
||||||
(close-input-port i)))))
|
|
||||||
|
Loading…
Reference in New Issue