home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / windows / winlisp.zip / OOPL.LZH / GRAMMAR.WL < prev    next >
Text File  |  1989-08-29  |  15KB  |  310 lines

  1. (dmd desetq (l1 l2) `(deset ',l1 ,l2))
  2.     
  3. ;===============================================================================
  4. ;
  5. ;                      G R A M M A R    O B J E C T S
  6. ;
  7. ; This example is given to demonstrate some object modeling techniques using
  8. ; metaclasses. The problem chosen for this purpose is to have an object 
  9. ; representation of a grammar with its tokens, non-terminals, ... and then
  10. ; to use all these objects in order to build a parser.
  11. ;
  12. ; See also parser.wl for parser creation and sample.grm for having an 
  13. ; executable example.
  14. ;===============================================================================
  15.  
  16. ; -----------------------------------------------------------------------------
  17. ; The problem can be stated as:
  18. ;     a grammar element is an object that shares the grammar object G
  19. ;     with all the other grammar elements referenced within the same 
  20. ;    grammar G.
  21. ;
  22. ; A simple solution for implementing this is to have an instance variable 
  23. ; that contains G in all kinds of grammar element:
  24. ;
  25. ;    [{AbstractClass} new 'name 'GrammarElement
  26. ;        'superClass        {Object}
  27. ;            'instanceVariables    '(grammar)]
  28. ;    [{Class} new 'name 'NonTerminal
  29. ;        'superClass        {GrammarElement}
  30. ;            'instanceVariables    '(name productions)]
  31. ;
  32. ;    [{Class} new 'name 'Production
  33. ;                . . .
  34. ;
  35. ; But that means duplicating the information G and not really sharing it.     
  36. ;
  37. ; To avoid this drawback, all the elements of the same grammar G will
  38. ; be created as instances of some classes inside which G will be wired.
  39. ; Let's call these classes the grammar element classes PRIVATE TO G:
  40. ;             How this could be done ?
  41. ; For these private classes considered as some objects, G will be stored 
  42. ; in their instance variable called <grammar>. 
  43. ; Thus for the instances of these private classes, G is available through 
  44. ; the CLASS VARIABLE called <grammar>.
  45. ; -----------------------------------------------------------------------------
  46.  
  47. [{Class} new 'name 'MetaGrammarElement
  48.     'superClass        {Class}
  49.         'instanceVariables    '(grammar)]
  50.         
  51. ; -----------------------------------------------------------------------------
  52. ; The following classes define the structure end behavior of all kinds of
  53. ; grammar elements but can't be used directly to create grammar elements
  54. ; since they don't hold any grammar object that can be shared by their
  55. ; instances.
  56. ;
  57. ; Notice here that we would like to let <MetaAbstractGrammarElement> inherits
  58. ; from <MetaGrammarElement> to get the instance variable <grammar> AND from
  59. ; <AbstractClass> to have the method for <new> redefined as an error.
  60. ; -----------------------------------------------------------------------------
  61.  
  62. [{Class} new 'name 'MetaAbstractGrammarElement
  63.     'superClass        {MetaGrammarElement}
  64.         'methods        '(
  65. new ( inits
  66.       (error "{MetaAbstractGrammarElement}:new" 
  67.              "abstract grammar element classes cannot be instantiated" self))
  68. )]
  69.  
  70. [{MetaAbstractGrammarElement} new 'name 'AbstractGrammarElement
  71.     'superClass        {Object}
  72.         'grammar        ()
  73.         'methods        '(
  74. grammar (()        #Cgrammar)
  75. )]                                   
  76.  
  77. [{MetaAbstractGrammarElement} new 'name 'AbstractNonTerminal
  78.     'superClass        {AbstractGrammarElement}
  79.         'instanceVariables    '(name productions)
  80.         'grammar        ()]
  81.  
  82. [{MetaAbstractGrammarElement} new 'name 'AbstractProduction
  83.     'superClass        {AbstractGrammarElement}
  84.         'instanceVariables    '(body action)
  85.         'grammar        ()]
  86.  
  87. [{MetaAbstractGrammarElement} new 'name 'AbstractToken
  88.     'superClass        {AbstractGrammarElement}
  89.         'instanceVariables    '(name value)
  90.         'grammar        ()]
  91.  
  92. [{MetaAbstractGrammarElement} new 'name 'AbstractErrorToken
  93.     'superClass        {AbstractGrammarElement}
  94.         'grammar        ()]
  95.  
  96. ; -----------------------------------------------------------------------------
  97. ; Notice here the 'private to <newGrammar>' grammar element classes creation 
  98. ; with:
  99. ;
  100. ;    [{MetaGrammarElement} new 
  101. ;              'name       (concat 'NonTerminal newSymbol)
  102. ;           'superClass {AbstractNonTerminal}
  103. ;               'grammar    newGrammar]
  104. ;
  105. ; and their storage in the nonTerminalClass, productionClass, ... instance
  106. ; variables of <newGrammar>, the newly created instance of Grammar.
  107. ; -----------------------------------------------------------------------------
  108.  
  109. [{Class} new 'name 'MetaGrammar
  110.     'superClass        {Class}
  111.         'methods        '(
  112. new ((grammarFileName)    [[super new] initialize grammarFileName])
  113. )]
  114.  
  115. [{MetaGrammar} new 'name 'Grammar
  116.     'superClass        {Object}
  117.         'instanceVariables    '(nonTerminalClass productionClass tokenClass
  118.                                   errorTokenClass dictionary)
  119.         'methods        '(
  120. initialize ((grammarFileName)                                   
  121.         (let ( (newSymbol  [{symbol} new]) )
  122.              (setf #InonTerminalClass
  123.                        [{MetaGrammarElement} new 
  124.                     'name       (concat 'NonTerminal newSymbol)
  125.                                 'superClass {AbstractNonTerminal}
  126.                                 'grammar    self]
  127.                        #IproductionClass
  128.                        [{MetaGrammarElement} new 
  129.                     'name       (concat 'Production newSymbol)
  130.                                 'superClass {AbstractProduction}
  131.                                 'grammar    self]
  132.                        #ItokenClass
  133.                        [{MetaGrammarElement} new 
  134.                     'name       (concat 'Token newSymbol)
  135.                                 'superClass {AbstractToken}
  136.                                 'grammar    self]
  137.                        #IerrorTokenClass
  138.                        [{MetaGrammarElement} new 
  139.                     'name       (concat 'ErrorToken newSymbol)
  140.                                 'superClass {AbstractErrorToken}
  141.                                 'grammar    self]
  142.                        #Idictionary    [{Dictionary} new])
  143.                  [self buildDictionary grammarFileName]
  144.                  self))
  145.  
  146. buildDictionary ((grammarFileName)
  147.                  ;; ------------------------------------------------------------
  148.                  ;; In order to build the grammar elements dictionary, a grammar
  149.                  ;; file is parsed (with a hand coded recursive descent parser)
  150.                  ;; the format of a grammar file is:
  151.                  ;;
  152.                  ;; grammarFile -> [lispCode] '%%' 
  153.                  ;;                {grammarRule}+          ;1 or more rules...
  154.                  ;;                ['%%' lispCode]
  155.                  ;;
  156.                  ;; grammarRule -> nonTerminalSymbol ':' productions ';'
  157.                  ;;
  158.                  ;; productions -> production '|' productions
  159.                  ;;             -> production
  160.                  ;;
  161.                  ;; production -> body [action]
  162.                  ;;
  163.                  ;; body -> {grammarSymbol}*              ;0 or more symbols...
  164.                  ;;
  165.                  ;; grammarSymbol -> nonTerminalSymbol 
  166.                  ;;               -> '%'tokenSymbol
  167.                  ;;               -> '%error'
  168.                  ;;
  169.                  ;; action -> '(' lambdaFunctionOrLispFunctionName ')'
  170.                  ;; ------------------------------------------------------------
  171.                   (unless (probefile grammarFileName)
  172.                                 (error "{Grammar}:buildDictionary" 
  173.                                        "unknown file" grammarFileName))
  174.                         (with ( (inchan (openi grammarFileName)) )
  175.                               (untilexit eof 
  176.                                          (let ( (x (read)) )
  177.                                               (if (eq x '%%) 
  178.                                                   (untilexit grammarRules
  179.                                                           [self addNonTerminal])
  180.                                                   ;;ELSE
  181.                                                   (eval x)))))
  182.                         [self checkDictionary]
  183.                         self)
  184.  
  185. addNonTerminal (()
  186.                (let ( ((type1 . name)   [self scan])
  187.                        ((type2 . sep)    [self scan]) 
  188.                        (productions) )
  189.                      (unless (and (eq type1 'symbol) 
  190.                                   (eq type2 'first-body-sep))
  191.                              (error "{Grammar}:addNonTerminal"
  192.                                     "expected <non-terminal name> ':', got"
  193.                                     (cons name sep)))
  194.                      ;; grammarRule AND NO OTHER TAG MUST BE EXITED FROM HERE...
  195.                      (newl productions 
  196.                            (lock '(lambda (tag lastProduction)
  197.                                           (if (eq tag 'grammarRule)
  198.                                               lastProduction
  199.                                               ;;ELSE
  200.                                               (error "{Grammar}:addNonTerminal"
  201.                                                      "unexpected end of rule"
  202.                                                      ())))
  203.                                  (while t    
  204.                              (newl productions 
  205.                                    [self addProduction]))))
  206.                      [#Idictionary at name 
  207.                                        [#InonTerminalClass new
  208.                                        'name        name 
  209.                                         'productions (nreverse productions)]]))
  210.                      
  211. addProduction (()
  212.                (let ( (dictionary      #Idictionary)
  213.                        (tokenClass      #ItokenClass)
  214.                        (errorTokenClass #IerrorTokenClass)
  215.                        (type) (val) (body) (action) (production) ) 
  216.                      (untilexit body
  217.                                 (desetq (type . val) [self scan])
  218.                                 (cond ( (eq type 'symbol)
  219.                                         (newl body val)
  220.                                         (unless [dictionary at val]
  221.                                                 [dictionary at val ()]) )
  222.                                       ( (eq type 'token)
  223.                                         (newl body val)
  224.                                         (unless [dictionary at val]
  225.                                                 [dictionary at val
  226.                                                                [tokenClass new 
  227.                                                                 'name   val
  228.                                                                  'value  ()]]) )
  229.                                       ( (eq type 'error)
  230.                                         (newl body val)
  231.                                         (unless [dictionary at val]
  232.                                                 [dictionary at val
  233.                                                        [errorTokenClass new]]) )
  234.                                       ( t    (exit body t) )))
  235.                      (when (eq type 'cons)
  236.                            (setq   action       (car val))
  237.                            (desetq (type . val) [self scan]))
  238.                      (setq production [#IproductionClass new 
  239.                                        'body (nreverse body) 
  240.                                                 'action action])
  241.                      (cond ( (eq type 'body-sep)    production )
  242.                            ( (eq type 'rule-sep)    (exit grammarRule 
  243.                                                               production) )
  244.                            ( t
  245.                              (error "{Grammar}:addProduction"
  246.                                     "expected '|' or ';', got"
  247.                                     val) ))))
  248.                   
  249. scan (()
  250.        (let ( (c (peekcn)) )
  251.             (selectq c
  252.                      ( #/:
  253.                        (cons 'first-body-sep (readcn)) )
  254.                      ( #/|
  255.                        (cons 'body-sep (readcn)) )
  256.                      ( #/;
  257.                        (cons 'rule-sep (readcn)) )
  258.                      ( #/%
  259.                        (readcn)
  260.                        (when (eq (peekcn) #/%)
  261.                              (exit grammarRules (readcn) t))
  262.                        (let ( (x (read)) )
  263.                             (unless (variablep x)
  264.                                     (error "{Grammar}:scan"
  265.                                            "expected '%'<token name>, got '%'"
  266.                                            x))
  267.                             (if (eq x 'error) 
  268.                                 '(error . error) 
  269.                                 ;;ELSE
  270.                                 (cons 'token x))) )
  271.                      ( t
  272.                        (cond ( (member (typecn c) '(csep cecom))
  273.                                (readcn)
  274.                                [self scan] )
  275.                              ( t
  276.                                (let ( (x (read)) ) (cons (type-of x) x)) )) ))))
  277.                   
  278. checkDictionary (()
  279.             (let ( (dictionary #Idictionary)
  280.                                (missingElements) )
  281.                              (when [dictionary isEmpty]
  282.                                    (error "{Grammar}:checkDictionary" 
  283.                                           "grammar elements not found" ()))
  284.                              [dictionary do '(lambda (name element)
  285.                                                 (unless element
  286.                                                         (newl missingElements 
  287.                                                               name)))]
  288.                              (when missingElements
  289.                                    (error "{Grammar}:checkDictionary"
  290.                                           "undefined non terminals" 
  291.                                           missingElements))
  292.                              self))
  293.  
  294. element ((name)        [#Idictionary at name])
  295.  
  296. prin (()
  297.       ;; -------------------------------------------------------------------
  298.       ;; circular structures ...
  299.       ;; Without this method, the standard lisp printer will loop while
  300.       ;; trying to print a Grammar Object (because its private classes
  301.       ;; contains some references to itself).
  302.       ;; -------------------------------------------------------------------
  303.     (prin "aGrammar"))
  304. )]
  305.  
  306.  
  307.  
  308.  
  309.