Parsers, BRAG, and ragg
I poked around and found two alternative parser generators:
ragg and
brag
Brag seems to be more modern and up to date so I went with that one.
I worked through the examples to get a VERY BASIC ast generated from the LISP lexer I made a few weeks ago.
I attached a zip with all the files below as well as output.
Here is the code.
The lexer/parser
#lang racket
#| toy_lisp_lex.rkt
Description:
A simple LISP/Rack Tokenizer/parser.
To use:
$ racket toy_lisp_lex.rkt <lisp file to parse>
Racket 6.3 | 9/23/16 | License MIT
|#
(require parser-tools/lex)
(require parser-tools/lex-sre)
(require brag/support)
(require "lisp_ast.rkt")
(define token-stream '())
(define-lex-abbrev comment? (or (: #\; (* (char-complement #\newline)))
(: "#|" (complement (: any-string "|#" any-string)) "|#")))
(define-lex-abbrev meta-word? (: #\# (* alphabetic) #\space))
(define-lex-abbrev literal?
(or (+ (char-range #\0 #\9))
(: (* (char-range #\0 #\9)) "." (or (* (char-range #\0 #\9)) (* (char-range #\a #\z))))
(: #\" (* any-char) #\")
(: #\' any-char #\')
(or "#f" "#t")))
(define-lex-abbrev identifier? (: (+ alphabetic)
(* (or alphabetic
#\- #\> #\< #\_ #\+ #\. #\/ #\= #\! #\?
#\: #\$ #\% #\& #\~ #\^))))
(define-lex-abbrev lparen? (or #\( #\[ #\{))
(define-lex-abbrev rparen? (or #\) #\] #\}))
(define-lex-abbrev symbol? (: #\' (: (+ alphabetic)
(* (or alphabetic
#\- #\> #\< #\_ #\+ #\. #\/ #\= #\! #\?
#\: #\$ #\% #\& #\~ #\^)))))
(define-lex-abbrev keyword? (or "=>" "do" "or"
"and" "else" "quasiquote"
"begin" "if" "quote"
"case" "lambda" "set!"
"cond" "let" "unquote"
"define" "let*" "unquote-splicing"
"delay" "letrec" "+"
"-" "*" "/"
"mod" "not" "equal?"
">" "<" ">="
">=" "="))
; A lexer to tokenize LISP files
(define tokenize
(lambda (file-port)
(port-count-lines! file-port)
(define lisp-lexer
(lexer
[comment? (token 'COMMENT lexeme #:skip? #t)]
[meta-word? (token 'META-WORD lexeme)]
[lparen? (token 'LPAREN lexeme)]
[rparen? (token 'RPAREN lexeme)]
[symbol? (token 'SYM lexeme)]
[#\' (token 'QUOTE "'")] ;; Quote for next s-exp
[literal? (token 'LIT lexeme)]
[keyword? (token 'KEYWORD lexeme)]
[identifier? (token 'ID lexeme)]
[(or #\newline #\space "") (token 'WHITESPACE lexeme #:skip? #t)] ;; Ignore
[(eof) (void)]))
(define (next-token) (lisp-lexer file-port))
next-token))
(define test '())
; Run over a file specified at the command line call
(with-handlers ([exn:fail?
(lambda (exn)
(printf "Please provide a file name to lex...\n"))])
(set! test (open-input-file
(vector-ref (current-command-line-arguments) 0)))
(set! token-stream (tokenize test))
(define ast (parse token-stream))
(syntax->datum ast))
The parser grammar
#lang brag
program: lang-name s-exp*
s-exp: LPAREN (KEYWORD | ID | s-exp| QUOTE s-exp | LIT | SYM | COMMENT)* RPAREN
lang-name: META-WORD ID
The test file
#lang racket
#|
primefinder.rkt
----------------------------------------------------------
Description:
A simple prime finder to solver problem
7 - "10001st prime": https://projecteuler.net/problem=7
Use:
import or run a promt with these definitions and call
(main).
----------------------------------------------------------
References:
https://docs.racket-lang.org/
https://learnxinyminutes.com/docs/racket/
----------------------------------------------------------
Contact: ldavis@marlboro.edu
https://github.com/SafeCamp
https://safecamp.github.io/
Logan Davis | 1/23/16 | DrRacket:6.2/Lang:racket
|#
(define prime?
#|
A simple, but reasonably fast prime test that returns
true if the test was positive and false otherwise.
Arguments = 2:
- num: the number to test.
- lst-of-tests: prime numbers used to test num_to_test.
|#
(lambda (num lst-of-primes)
(cond [(null? lst-of-primes) #t]
[(< (+ (sqrt num) 1) (first lst-of-primes)) #t]
[(= (remainder num (first lst-of-primes)) 0) #f]
[else (prime? num (rest lst-of-primes))])))
(define finder
#|
Finds what prime number corresponders to
a given index. This function is 0 indexing,
E.G. passing '0' to the index arg will result
in '2' being returned.
Arguments = 3:
current-num: The number to be tested.
index: The desired index of prime to be found.
lst-of-primes: prime numbers found.
|#
(lambda (current-num index lst-of-primes)
(cond [(= index 0) (last lst-of-primes)]
[(prime? current-num lst-of-primes)
(finder (+ current-num 2)
(- index 1)
(append lst-of-primes
(list current-num)))]
[else (finder (+ current-num 2) index lst-of-primes)])))
(define main
#|
Prompts the user to enter a the index of the prime
they wish to know and then calulates it using (finder).
|#
(lambda ()
(print "Please enter the desired index of the number you wish to find:")
(define target (read-line))
(define answer (finder 3 (- (string->number target) 1) '(2)))
answer))