123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- #-esrap (ql:quickload :esrap)
- (require :esrap)
- (defpackage #:test-parser
- (:use :esrap
- :cl)
- (:export :display-parse-tree))
- (in-package :test-parser)
- (defvar *routines* (make-hash-table))
- (defvar *variables* (make-hash-table))
- (defvar *arrays* (make-hash-table))
- (defun not-doublequote (char)
- (not (eql #\" char)))
- (defun not-integer (string)
- (when (find-if-not #'digit-char-p string)
- t))
- (defrule name
- (+ (alphanumericp character))
- (:text t))
- (defrule space
- (+ (or #\Space #\Tab #\Newline))
- (:constant nil))
- (defrule variable
- (and "*v:" name)
- (:destructure (vv name)
- (declare (ignore vv))
- (list :variable name)))
- (defrule string-char
- (or (not-doublequote character)
- (and #\\ #\")))
- (defrule string
- (and #\" (* string-char) #\")
- (:destructure (q1 string q2)
- (declare (ignore q1 q2))
- (list :string (text string))))
- (defrule number
- (+ (or "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"))
- (:lambda (list)
- (list :number (parse-integer (text list)))))
- (defrule call-routine
- (and "*r:" name "(" (? val-list) ")")
- (:destructure (call-syntax name lpar vals rpar)
- (declare (ignore call-syntax lpar rpar))
- (list 'handle-call-routine name vals)))
- (defrule val-list
- (+ (or possible-value ", "))
- (:destructure (&rest vals)
- (let ((list '(:val-list)))
- (dolist (value vals)
- (if (not (stringp value))
- (push value list)))
- (reverse list))))
- (defrule possible-value
- (or string variable number call-routine builtins array array-in))
- (defrule assignment
- (and (or variable array)
- (? space)
- #\=
- (? space)
- possible-value)
- (:destructure (var s1 eqlsgn s2 value)
- (declare (ignore s1 eqlsgn s2))
- (list 'handle-assignment var value)))
- (defrule builtins
- (and (or "out" "in" "system" "open" "close" "return" "argument" "random") "(" val-list ")")
- (:destructure (name start vals end)
- (declare (ignore start end))
- (list
- (cond
- ((string= name "out")
- 'do-out)
- ((string= name "in")
- 'do-in)
- ((string= name "system")
- 'do-system)
- ((string= name "open")
- 'do-open)
- ((string= name "close")
- 'do-close)
- ((string= name "return")
- 'do-return)
- ((string= name "argument")
- 'do-argument)
- ((string= name "random")
- 'do-random))
- vals)))
- (defrule arith-ops
- (or "+" "-" "*" "/" "%" "^")
- (:lambda (operator)
- (cond
- ((string= operator "+") :PLUS)
- ((string= operator "-") :SUBT)
- ((string= operator "*") :MULT)
- ((string= operator "/") :DIVD)
- ((string= operator "%") :MODU)
- ((string= operator "^") :EXPT))))
- (defrule arithmetic
- (or (and (? "(") (? space) arithmetic (? space) arith-ops (? space) arithmetic (? space) (? ")"))
- (or variable number))
- (:destructure (first second &optional aritha mspace op mmspace arithb mmmspace rpar)
- (if (symbolp first)
- (list (list first second))
- (list :ARITH
- op
- aritha
- arithb))))
- (defrule index
- (and ":" possible-value ":")
- (:destructure (s val e)
- (declare (ignore s e))
- val))
- (defrule array
- (and "*a:" name (? index))
- (:destructure (va name index)
- (declare (ignore va))
- (list :ARRAY name index)))
- (defrule array-in
- (and "<" val-list ">")
- (:destructure (s vals e)
- (declare (ignore s e))
- (list :aval vals)))
- ;; rest goes here
- (defrule boolean
- (and variable (? space) (or "==" "!=" ">" "<" ">=" "<=") (? space) possible-value)
- (:destructure (variable s1 type s2 value)
- (declare (ignore s1 s2))
- (list :boolean variable type value)))
- (defrule bool-name
- (or "AND" "NOT" "OR" "NOR")
- (:lambda (name)
- (cond
- ((string= name "AND")
- :AND)
- ((string= name "NOT")
- :NOT)
- ((string= name "OR")
- :OR)
- ((string= name "NOR")
- :NOR))))
- (defrule statement
- (and (? space)
- (or assignment call-routine builtins)
- (? space) #\; (? space))
- (:destructure (space1 statement space2 semicolon space3)
- (declare (ignore semicolon space1 space2 space3))
- statement))
- (defrule block
- (* statement)
- (:destructure (&rest statements)
- (list :block statements)))
- (defrule else
- (and "ELSE:" space block)
- (:destructure (name space block)
- (declare (ignore name space))
- (list :ELSE block)))
- (defrule else-if
- (and "ELSE-IF" space boolean #\: block)
- (:destructure (start space bool colon block)
- (declare (ignore start space colon))
- (list :ELSEIF bool block)))
- (defrule if
- (and "IF" space boolean #\: space
- block
- (* (or else else-if))
- "ENDIF")
- (:destructure (start space bool colon morespace block else-else-ifs end)
- (declare (ignore start space colon morespace end))
- (list :IF bool block else-else-ifs)))
- (defrule routine
- (and "ROUTINE" (? space) name #\:
- block
- "END-ROUTINE")
- (:destructure (rtn spc1 name colon block end-rtn)
- (declare (ignore rtn spc1 colon end-rtn))
- (list :routine name block)))
- (defrule program
- (* (or statement if routine)))
- (defun run-string (string)
- (run-program (parse 'program string)))
- (defun run-program (program-list)
- (dolist (chunk program-list)
- (let ((type (car chunk)))
- (cond
- ((eq type :call-routine)
- (handle-call-routine chunk))
- ((eq type :assignment)
- (handle-assignment chunk))
- ((eq type :builtins)
- (handle-builtins chunk))
- ((eq type :block)
- (run-program (cdr chunk)))
- ((eq type :routine)
- (handle-routine chunk))
- ((eq type :if)
- (handle-if chunk))))))
- (defun handle-call-routine (list))
- (defun handle-assignment (list))
- (defun handle-builtins (list))
- (defun handle-routine (list)
- (let ((routine-name (cadr list))
- (routine (caddr list)))
- (setf (gethash (intern routine-name) *routines*) routine)))
- (defun handle-if (list))
- (defun set-variable (name value))
- (defun set-whole-array (name vil value))
- (defun set-array-indexed (name index values))
- (defun display-parse-tree (string)
- (parse 'program string))
|