;;; python.lisp --- sample grammar definition for the Python language ;;; Copyright (C) 2003 by Walter C. Pelissero ;;; Author: Walter C. Pelissero ;;; Project: NPG a Naive Parser Generator ;;; $Id: F-C1A8CD5961889C584B22F05E8B956006.lisp,v 1.3 2004/03/09 10:33:06 wcp Exp $ ;;; This library is free software; you can redistribute it and/or ;;; modify it under the terms of the GNU Lesser General Public License ;;; as published by the Free Software Foundation; either version 2.1 ;;; of the License, or (at your option) any later version. ;;; This library 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 ;;; Lesser General Public License for more details. ;;; You should have received a copy of the GNU Lesser General Public ;;; License along with this library; if not, write to the Free ;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ;;; 02111-1307 USA ;;; Commentary: ;;; ;;; This is far from being a complete Python grammar. Actually I ;;; haven't even read a Python book before starting to write this ;;; stuff, so the code below comes mostly from wild guessing while ;;; reading a Python source file. ;;; ;;; It's a design decision to avoid writing any transformation in this ;;; module; only tagging is done at this level. This improves the ;;; separation between parsing and transformation, making the grammar ;;; reusable for other purposes. #+cmu (ext:file-comment "$Id: F-C1A8CD5961889C584B22F05E8B956006.lisp,v 1.3 2004/03/09 10:33:06 wcp Exp $") (in-package :grammar) (deflazy define-grammar (let ((*package* #.*package*) (*compile-print* (and parser::*debug* t))) (reset-grammar) (format t "~&creating Python grammar...~%") (populate-grammar) (let ((grammar (parser:generate-grammar))) (reset-grammar) (parser:print-grammar-figures grammar) grammar))) (defun populate-grammar () (defrule program := comment-string? statement+) (defrule comment-string := string eol :reduce string) ;;; BOB = Beginning Of Block, EOB = End Of Block. It's lexical ;;; analyzer's task to find out where a statement or block starts/ends. (defrule suite := statement-list eol :reduce statement-list := statement-block) (defrule commentable-suite := statement-list eol :reduce statement-list := commented-statement-block) (defrule statement-block := bob statement+ eob :reduce $2) (defrule commented-statement-block := bob comment-string? statement* eob :reduce (cons comment-string statement)) (defrule statement-list := (+ simple-statement ";") :reduce (if (cdr $1) (cons :statement-list $1) (car $1))) (defrule statement := statement-list eol :reduce statement-list := compound-statement) (defrule simple-statement := import-statement := raise-statement := assignment := function-call := return-statement := assert-statement := pass-statement := break-statement := continue-statement) (defrule compound-statement := class-definition := method-definition := try-statement := if-statement := while-statement := for-statement) (defrule import-statement := "import" (+ package-name ",") :tag :import := "from" package-name "import" (+ symbol-name ",") :tag :import-from) (defrule package-name := identifier) (defrule symbol-name := identifier := "*") (defrule try-statement := "try" ":" suite try-except-part* try-finally-part? :tag :try) (defrule try-except-part := "except" exception-subject? ":" suite) (defrule try-finally-part := "finally" ":" suite) (defrule exception-subject := exception-name exception-variable?) (defrule exception-variable := "," identifier) (defrule exception-name := class-name) (defrule class-name := identifier) (defrule raise-statement := "raise" :tag :raise-same := "raise" exception-name :tag :raise := "raise" exception-name "," expression :tag :raise := "raise" exception-name "(" expression ")" :tag :raise) (defrule assignment := (+ variable-with-optional-subscript ",") "=" more-assignment :tag :set) (defrule more-assignment := expression := assignment) (defrule variable-with-optional-subscript := variable-name subscript :tag :subscript := variable-name) (defrule variable-name := (+ identifier ".") :tag :varef) (defrule expression := expression "or" expression1 :tag :or := expression1) (defrule expression1 := expression1 "and" expression2 :tag :and := expression2) (defrule expression2 := expression2 "==" expression3 :tag :equal := expression2 ">=" expression3 :tag :more-equal := expression2 "<=" expression3 :tag :less-equal := expression2 "!=" expression3 :tag :not-equal := expression2 ">" expression3 :tag :more := expression2 "<" expression3 :tag :less := expression2 "is" expression3 :tag :equal := expression2 "is" "not" expression3 :tag :not-equal := expression3) (defrule expression3 := expression3 "+" expression4 :tag :plus := expression3 "-" expression4 :tag :minus := expression3 "|" expression4 :tag :bit-or := expression4) ;; high priority expression (defrule expression4 := expression4 "*" expression5 :tag :mult := expression4 "/" expression5 :tag :div := expression4 "%" expression5 :tag :modulo := expression4 "&" expression5 :tag :bit-and := expression4 "in" expression5 :tag :in := expression5) (defrule expression5 := "~" expression5 :tag :bit-not := "not" expression5 :tag :not := "(" expression ")" := expression6) (defrule expression6 := simple-expression subscript :tag :subscript := simple-expression) (defrule simple-expression := function-call := variable-name := constant := string-conversion := list-constructor) (defrule subscript := "[" expression "]" := "[" expression ":" expression "]" := "[" expression ":" "]" :reduce (list expression nil) := "[" ":" expression "]" :reduce (list nil expression)) (defrule string-conversion := "`" expression "`" :tag :to-string) (defrule constant := number := string := lambda-expression) (defrule number := float := integer) (defrule list-constructor := "[" (* expression ",") "]" :tag :make-list) (defrule class-definition := "class" class-name superclasses? ":" commentable-suite :tag :defclass) (defrule superclasses := "(" class-name+ ")") (defrule method-definition := "def" method-name "(" method-arguments ")" ":" commentable-suite :tag :defmethod) (defrule method-arguments := (* method-argument ",")) (defrule method-argument := identifier argument-default?) (defrule argument-default := "=" expression) (defrule method-name := identifier) (defrule if-statement := "if" expression ":" suite elif-part* else-part? :tag :if) (defrule else-part := "else" ":" suite) (defrule elif-part := "elif" expression ":" suite) (defrule lambda-expression := "lambda" method-arguments ":" expression :tag :lambda) (defrule function-call := (+ identifier ".") "(" (* expression ",") ")" :tag :funcall) (defrule for-statement := "for" identifier "in" expression ":" suite :tag :do-list := "for" identifier "in" "range" "(" expression "," expression ")" ":" suite :tag :do-range) (defrule while-statement := "while" expression ":" suite :tag :while) (defrule return-statement := "return" expression? :tag :return) (defrule assert-statement := "assert" expression "," string :tag :assert) (defrule pass-statement := "pass" :tag :pass) (defrule break-statement := "break" :tag :break) (defrule continue-statement := "continue" :tag :continue) ) ; end of POPULATE-GRAMMAR