This file is indexed.

/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
}")