|
@@ -0,0 +1,245 @@
|
|
|
+#-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))
|