;;; python.lisp --- sample grammar definition for the Python language
;;; Copyright (C) 2003 by Walter C. Pelissero
;;; Author: Walter C. Pelissero <walter@pelissero.de>
;;; 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