Emacs/cc-ide: More flexible ccide-all-includes implementation
[emacsstuff.git] / cc-ide / recdesc.el
diff --git a/cc-ide/recdesc.el b/cc-ide/recdesc.el
new file mode 100644 (file)
index 0000000..90b4c04
--- /dev/null
@@ -0,0 +1,271 @@
+;;; recdesc.el --- Generator for recursive-descent parsers
+;;
+;; Copyright (C) 2000,2007 Stefan Bund
+
+;; recdesc.el is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; recdesc.el is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;;; Commentary:
+
+;; Der Syntax einer term deklaration ist:
+
+;; <term-declaration> := (term <symbol> <arglist> <command>...)
+;;
+;; <command> := <directive>
+;;            | (collect <directive-or-form>)
+;;            | (return <form>)
+;; 
+;; <directive-or-form> := <directive> | <form>
+;; 
+;; <diretive> :=  (match <term> [<form>...])
+;;             |  (or <command>...)
+;;             |  (and <command>...)
+;;             |  (maybe <command>...)
+;;             |  (repeat <command>...)
+;;             |  (commit)
+;;             |  (fail)
+;;             |  (progn <lisp-code>...)
+;;
+;; <term> := <symbol> | <form>
+
+;; 
+;;
+
+;;; Change-Log:
+
+;; $Log: recdesc.el,v $
+;; Revision 1.3  2000/02/13 21:19:56  bund
+;; Erste vollständige version von SqIV2
+;;
+;; Revision 1.2  2000/02/03 10:15:19  bund
+;; *** empty log message ***
+;;
+;; Revision 1.1  2000/02/01 13:26:03  bund
+;; *** empty log message ***
+;;
+;;
+
+;;; Variables:
+
+;;; Code:
+
+(require 'cl)
+
+(declaim (special position))
+(declaim (special string))
+(declaim (special commit-flag))
+(declaim (special saved-position))
+(declaim (special saved-elements))
+(declaim (special elements))
+(declaim (special return-form))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Zunächst der Parser/Scanner zur deklaration von Termen
+
+(defmacro recdesc-deferror (name message &rest classes)
+  `(progn
+     (put ',name 'error-conditions '(error sqi-error ,@classes ,name))
+     (put ',name 'error-message ,message)))
+
+(defmacro recdesc-declare (&rest forms)
+  (cons 'progn
+        (loop for form in forms
+              collect (if (and (consp form)
+                               (eq (car form) 'term)
+                               (consp (cdr form))
+                               (symbolp (cadr form))
+                               (consp (cddr form))
+                               (listp (caddr form)))
+                          (recdesc-declare-term (cadr form)
+                                                    (caddr form)
+                                                    (cdddr form))
+                        (signal 'recdesc-invalid-decl-component
+                                (list form))))))
+
+(recdesc-deferror recdesc-invalid-decl-component
+  "Invalid component in recdesc-declare" recdesc-error)
+
+(defun recdesc-declare-term (name arglist body)
+  (let (return-form)
+    `(defun ,(intern (concat "recdesc@@" (symbol-name name))) ,arglist
+       (let (elements)
+         (or (and ,(recdesc-parse-directive/and body)
+                 ,(if return-form
+                      return-form
+                    '(or elements t))))))))
+
+(defun recdesc-parse-command (command)
+  (if (not (consp command))
+      (signal 'recdesc-invalid-command
+              (list command)))
+  (cond ((eq (car command) 'return)
+         (if (not (consp (cdr command)))
+             (signal 'recdesc-invalid-command
+                     (list command)))
+         (setq return-form (cadr command))
+         t)
+        ((eq (car command) 'collect)
+         (if (not (consp (cdr command)))
+             (signal 'recdesc-invalid-command (list command)))
+         `(recdesc-collect ,(recdesc-parse-directive-or-form (cadr command))))
+        (t (recdesc-parse-directive command))))
+
+(recdesc-deferror recdesc-invalid-command
+  "Invalid scanner command" recdesc-error)
+
+(defun recdesc-parse-directive-or-form (directive-or-form)
+  (or (recdesc-parse-directive directive-or-form t)
+      directive-or-form))
+
+(defun recdesc-parse-directive (directive &optional nosignal)
+  (if (not (consp directive))
+      (if (not nosignal)
+          (signal 'recdesc-invalid-directive
+                  (list directive)))
+    (cond ((eq (car directive) 'match)   (recdesc-parse-directive/match   (cdr directive)))
+          ((eq (car directive) 'or)      (recdesc-parse-directive/or      (cdr directive)))
+          ((eq (car directive) 'and)     (recdesc-parse-directive/and     (cdr directive)))
+          ((eq (car directive) 'maybe)   (recdesc-parse-directive/maybe   (cdr directive)))
+          ((eq (car directive) 'repeat)  (recdesc-parse-directive/repeat  (cdr directive)))
+          ((eq (car directive) 'commit)  (recdesc-parse-directive/commit  (cdr directive)))
+          ((eq (car directive) 'fail)    (recdesc-parse-directive/fail    (cdr directive)))
+          ((eq (car directive) 'progn)   (recdesc-parse-directive/progn   (cdr directive)))
+          (t (if (not nosignal)
+                 (signal 'recdesc-invalid-directive
+                         (list directive)))))))
+
+(recdesc-deferror recdesc-invalid-directive
+  "Invalid scanner directive" recdesc-error)
+
+(defun recdesc-parse-directive/match (args)
+  (if (not (consp args))
+      (signal 'recdesc-invalid-match-arguments
+              (list args)))
+  (if (symbolp (car args))
+      (cons (intern (concat "recdesc@@" (symbol-name (car args))))
+            (cdr args))
+    (if (not (null (cdr args)))
+        (signal 'recdesc-invalid-match-arguments
+                (list args)))
+    (list 'recdesc-match-regexp (car args))))
+
+(recdesc-deferror recdesc-invalid-match-arguments
+  "Invalid arguments to match directive" recdesc-error)
+
+(defun recdesc-parse-directive/or (args)
+  (if (not (consp args))
+      (signal 'recdesc-invalid-or-arguments
+              (list args)))
+  (cons 'or
+        (loop for command in args
+              collect (recdesc-parse-directive/and (list command)))))
+
+(recdesc-deferror recdesc-invalid-or-arguments
+  "Invalid arguments to or directive" recdesc-error)
+
+(defun recdesc-parse-directive/and (args)
+  (if (not (consp args))
+      (signal 'recdesc-invalid-and-arguments
+              (list args)))
+  `(let ((saved-position position)
+         (saved-elements elements)
+         commit-flag)
+     (or (and ,@(loop for command in args
+                      collect (recdesc-parse-command command)))
+         (recdesc-backtrack))))
+
+(recdesc-deferror recdesc-invalid-and-arguments
+  "Invalid arguments to and directive" recdesc-error)
+
+(defun recdesc-parse-directive/maybe (args)
+  (if (not (consp args))
+      (signal 'recdesc-invalid-maybe-arguments
+              (list args)))
+  `(or ,(recdesc-parse-directive/and args) t))
+
+(defun recdesc-parse-directive/repeat (args)
+  `(loop for repeat-item = ,(recdesc-parse-directive/and args)
+         while repeat-item
+         collect repeat-item))
+
+(defun recdesc-parse-directive/commit (args)
+  (if args
+      (signal 'recdesc-invalid-commit-arguments
+              (list args)))
+  `(setq commit-flag t))
+
+(recdesc-deferror recdesc-invalid-commit-arguments
+  "Invalid arguments to commit directive" recdesc-error)
+
+(defun recdesc-parse-directive/fail (args)
+  (if args
+      (signal 'recdesc-invalid-fail-arguments
+              (list args)))
+  '(throw 'recdesc-failed nil))
+
+(recdesc-deferror recdesc-invalid-fail-arguments
+  "Invalid arguments to fail directive" recdesc-error)
+
+(defun recdesc-parse-directive/progn (args)
+  `(progn ,@args))
+
+(put 'term 'lisp-indent-function 'defun)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Die folgenden Funktionen werden von den durch recdesc-declare
+;; erzeugten termen benötigt
+
+(defun recdesc-backtrack ()
+  (progn
+    (if commit-flag
+       (throw 'recdesc-failed nil))
+    (setq position saved-position
+         elements saved-elements)
+    nil))
+
+(defun recdesc-collect (value)
+  (if value
+      (progn
+       (setq elements (nconc elements 
+                             (list value)))
+       value)))
+
+(defun recdesc-match-regexp (regexp)
+  (if (string-match (concat "^" regexp) (substring string position))
+      (let ((start position))
+       (setq position (+ position (match-end 0)))
+       (substring string start position))))
+
+(defun recdesc-match (term &rest args)
+  (apply (intern (concat "recdesc@@" (symbol-name term))) args))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; 
+;; Toplevel calls to generated scanners
+
+(defun recdesc-scan-string (term string &rest args)
+  (let ((scanner (intern (concat "recdesc@@"
+                                (symbol-name term))))
+       (position 0)
+       rv)
+    (setq rv (catch 'recdesc-failed
+              (apply scanner args)))
+    (if (not (string-match "^[ \t\n\r]*$" (substring string position)))
+       nil
+      rv)))
+
+(provide 'recdesc)
+
+\f
+;;; Local Variables:
+;;; elisp-project-autoload-file-name: "sqi-autoload.el"
+;;; End: