#lang scheme/base ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; PARSEQ.PLT ;; A Parser Combinator library. ;; ;; Bonzai Lab, LLC. All rights reserved. ;; ;; Licensed under LGPL. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; basic.ss - a set of basic parsers ;; yc 12/31/2009 - first version ;; yc 7/7/2010 - updating real-number to also handle exponents. (require "depend.ss" "primitive.ss" "combinator.ss" "input.ss" ) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; char parsers. ;; digit (define digit (char-between #\0 #\9)) ;; not-digit (define not-digit (char-not-between #\0 #\9)) ;; lower-case (define lower-case (char-between #\a #\z)) ;; upper-case (define upper-case (char-between #\A #\Z)) ;; alpha (define alpha (choice lower-case upper-case)) ;; alphanumeric (define alphanumeric (choice alpha digit)) ;; hexdecimal parser (define hexdecimal (char-in '(#\a #\b #\c #\d #\e #\f #\A #\B #\C #\D #\E #\F #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))) ;; whitespace (define whitespace (char-in '(#\space #\return #\newline #\tab #\vtab))) (define not-whitespace (char-not-in '(#\space #\return #\newline #\tab #\vtab))) ;; ascii (define ascii (char-between (integer->char 0) (integer->char 127))) ;; word = a-zA-Z0-9_ (define word (choice alphanumeric (char= #\_))) ;; not-word (define not-word (char-when (lambda (c) (not (or (char<=? #\a c #\z) (char<=? #\A c #\Z) (char<=? #\0 c #\9) (char=? c #\_)))))) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; number parsers. ;; signed (define sign (zero-one (char= #\-) #\+)) ;; natural (define natural (one-many digit)) ;; decimal ;; there is a bug - anything fails in seq should automatically fail the whole thing... (define decimal (seq number <- (zero-many digit) point <- (char= #\.) decimals <- natural (return (append number (cons point decimals))))) (define (hexdecimals->number hexes) (define (hex->num hex) (- (char->integer hex) (char->integer (case hex ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) #\0) ((#\a #\b #\c #\d #\e #\f) #\a) ((#\A #\B #\C #\D #\E #\F) #\A))) (- (case hex ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) 0) ((#\a #\b #\c #\d #\e #\f) 10) ((#\A #\B #\C #\D #\E #\F) 10))))) (define (helper rest total) (if (null? rest) total (helper (cdr rest) (+ (hex->num (car rest)) (* total 16))))) ;;(trace helper) ;;(trace hex->num) (helper hexes 0)) (define hexdecimals (seq num <- (zero-many hexdecimal) (return (hexdecimals->number num)))) ;; positive (define positive (choice decimal natural)) ;; signed (number) (define (make-signed parser) (seq +/- <- sign number <- parser (return (cons +/- number)))) ;; make-number (define (make-number parser) (seq n <- parser (return (string->number (list->string n))))) ;; natural-number (define natural-number (make-number natural)) ;; integer (define integer (make-number (make-signed natural))) ;; positive-integer (define positive-number (make-number positive)) ;; real-number (now handling exponents) (define real-number (make-number (choice (seq exp <- (make-signed positive) e <- (choice #\E #\e) magenta <- (make-signed natural) (return (append exp (list e) magenta))) (make-signed positive) ))) (define hexdecimal-number (make-number hexdecimals)) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; string parsers. ;; escaped-char ;; allows for an escaping sequence for a particular character... (define (escaped-char escape char (as #f)) (seq (char= escape) c <- (if (char? char) (char= char) char) (return (if as as c)))) ;; e-newline (define e-newline (escaped-char #\\ #\n #\newline)) ;; e-return (define e-return (escaped-char #\\ #\r #\return)) ;; e-tab (define e-tab (escaped-char #\\ #\t #\tab)) ;; e-backslash (define e-backslash (escaped-char #\\ #\\)) ;; quoted ;; a specific string-based bracket parser (define (quoted open close escape) (seq (char= open) atoms <- (zero-many (choice e-newline e-return e-tab e-backslash (escaped-char escape close) (char-not-in (list close #\\)))) (char= close) (return atoms))) ;; make-quoted-string ;; a simplification for creating a string parser (define (make-quoted-string open (close #f) (escape #\\)) (seq v <- (quoted open (if close close open) escape) (return (list->string v)))) ;; single-quoted-string ;; parse a string with single quotes (define single-quoted-string (make-quoted-string #\')) ;; double-quoted-string ;; parse a string with double quotes (define double-quoted-string (make-quoted-string #\")) ;; quoted-string ;; choosing between single and double quotes (define quoted-string (choice single-quoted-string double-quoted-string)) ;; whitespaces ;; parsing out all whitespaces together... (define whitespaces (zero-many whitespace)) ;; newline (define newline (choice (seq r <- (char= #\return) n <- (char= #\newline) (return (list r n))) (char= #\return) (char= #\newline))) (provide (all-defined-out))