/usr/share/common-lisp/source/esrap/example-symbol-table.lisp is in cl-esrap 20151218-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | ;;;; Esrap example: a simple grammar with scopes and symbol tables.
(require :esrap)
(defpackage :symbol-table
(:use :cl :esrap))
(in-package :symbol-table)
;;; Use the :AROUND construction to maintain a stack of symbol tables
;;; during parsing.
;;;
;;; It is important to note that the bodies of :AROUND options are
;;; executed during result construction, not parsing. Therefore,
;;; :AROUND cannot be used to introduce context sensitivity into
;;; parsing. However, this can be done when using functions as
;;; terminals, see example-function-terminals.lisp.
(declaim (special *symbol-table*))
(defvar *symbol-table* nil)
(defstruct (symbol-table
(:constructor make-symbol-table (&optional %parent)))
(%table (make-hash-table :test #'equal))
%parent)
(defun lookup/direct (name &optional (table *symbol-table*))
(values (gethash name (symbol-table-%table table))))
(defun lookup (name &optional (table *symbol-table*))
(or (lookup/direct name table)
(alexandria:when-let ((parent (symbol-table-%parent table)))
(lookup name parent))))
(defun (setf lookup) (new-value name &optional (table *symbol-table*))
(when (lookup/direct name table)
(error "~@<Duplicate name: ~S.~@:>"
name))
(setf (gethash name (symbol-table-%table table)) new-value))
(defrule whitespace
(+ (or #\Space #\Tab #\Newline))
(:constant nil))
(defrule name
(+ (alphanumericp character))
(:text t))
(defrule type
(+ (alphanumericp character))
(:text t))
(defrule declaration
(and name #\: type)
(:destructure (name colon type)
(declare (ignore colon))
(setf (lookup name) (list name :type type))
(values)))
(defrule use
name
(:lambda (name)
(list :use (or (lookup name)
(error "~@<Undeclared variable: ~S.~@:>"
name)))))
(defrule statement
(+ (or scope declaration use))
(:lambda (items)
(remove nil items)))
(defrule statement/ws
(and statement (? whitespace))
(:function first))
(defrule scope
(and (and #\{ (? whitespace))
(* statement/ws)
(and #\} (? whitespace)))
(:function second)
(:around ()
(let ((*symbol-table* (make-symbol-table *symbol-table*)))
(list* :scope (apply #'append (call-transform))))))
(parse 'scope "{
a:int
a
{
a
b:double
a
b
{
a:string
a
b
}
a
b
}
a
}")
|