I’ve been trying to learn how to use the PLT Scheme parser-tools collection. As a learning exercise I’ve written a small parser and lexer.
The parser will read in a file with the format of the named.conf configuration files used by the Unix DNS daemon Bind. They look (in part) like this:
zone "web-wide.net" IN {
type master;
file "zone/web-wide.net";
allow-update {
127.0.0.1;
};
};
And it will output it as an s-expression that looks like this:
((zone |"web-wide.net"| |IN| ((type master) (file |"zone/web-wide.net"|) (allow-update ((127.0.0.1))))))
Here is the code for the parser and lexer:
(require (lib "yacc.ss" "parser-tools")
(lib "lex.ss" "parser-tools")
(lib "readerr.ss" "syntax"))
(define-tokens value-tokens (STRING))
(define-empty-tokens stanza-tokens (OB CB SEMI EOF))
(define-lex-abbrevs
(lower-letter (- "a" "z"))
(upper-letter (- #A #Z))
(digit (- "0" "9"))
(string (+ (: lower-letter upper-letter digit "." "-" "_" )))
(qstring (@ #\" (+ (^ #\")) #\"))
)
(define confl
(lexer
((eof) 'EOF)
((: #tab #space #newline) (confl input-port))
("{" 'OB)
("}" 'CB)
(";" 'SEMI)
(qstring (token-STRING (string->symbol lexeme)))
(string (token-STRING (string->symbol lexeme)))))
(define confp
(parser
(start start)
(end EOF)
(tokens value-tokens stanza-tokens)
(error (lambda (a b c) (void)))
(grammar
(start ((statement_list) $1))
(block
((OB statement_list CB) (list $2)))
(element
((string) (list $1) )
((block) $1))
(element_list
((element) $1)
((element_list element) (append $1 $2)))
(statement
((element_list SEMI) (list $1)))
(statement_list
((statement) $1)
((statement_list statement) (append $1 $2))))))
(define runp
(lambda () (confp (lambda () (confl (current-input-port))))))
