com.ph.pr.parser
Class ASTBuilder

java.lang.Object
  extended by com.ph.pr.parser.ASTBuilder
All Implemented Interfaces:
goldengine.java.GPMessageConstants

public class ASTBuilder
extends java.lang.Object
implements goldengine.java.GPMessageConstants

A singleton class providing capabilities for creating a class hierarchy for an AST for a supplied grammar, and creating the tree of AST objects, each one corresponding to a non-terminal, upon parsing. This is based on GOLD Parsing System and its Java engine .

Author:
" Greg Golberg "
See Also:
parse(ClassLoader, String, String), generateClasses(String, String, String, String)

Field Summary
static java.lang.String AST_SUFFIX
           
private  java.util.Map ast2Comments
           
private  boolean caseInsensitive
           
private  java.util.Map childMap
           
private  ASTNode curAst
          Current AST node (eventually this is returned by parse(ClassLoader, String, String)).
private  java.lang.String curComment
           
static java.lang.String GOLD_NON_TERMINAL_END
           
static java.lang.String GOLD_NON_TERMINAL_START
           
static java.lang.String GOLD_PROD_SYMB
           
private  java.lang.String grammar
           
private  boolean grammarLoaded
           
private  java.lang.String input
           
private static ASTBuilder instance
          The singleton instance
private  java.io.PrintWriter out
           
private  goldengine.java.GOLDParser parser
           
private  java.util.Map prodMap
          Map of namesof rule non-terminalsto an ArrayList of productions, as Strings.
private  java.util.Map red2Ast
          Map of Reductionto corresponding ASTNode.
private  java.util.Map terminalMap
           
 
Fields inherited from interface goldengine.java.GPMessageConstants
gpMsgAccept, gpMsgCommentError, gpMsgCommentLineRead, gpMsgInternalError, gpMsgLexicalError, gpMsgNotLoadedError, gpMsgReduction, gpMsgSyntaxError, gpMsgTokenRead
 
Constructor Summary
private ASTBuilder()
           
 
Method Summary
 void generateClasses(java.lang.String root, java.lang.String pkg, java.lang.String visitorPkg, java.lang.String visitorName)
          Generate the classes implementing ASTNodefor each non-terminal.
 java.util.Collection getAllAsts()
           
 java.util.Map getAst2Comments()
           
 ASTNode getStart()
           
 java.util.Map getTerminalMap()
           
private  boolean isNonTerminal(java.lang.String s)
           
static void main(java.lang.String[] argv)
           
private  java.lang.String nonTerminalName(java.lang.String s)
           
 ASTNode parse(java.lang.ClassLoader loader, java.lang.String pkg, java.lang.String input)
          Parse the input.
static java.lang.String pkg2Dir(java.lang.String pkg)
           
private  void processReduction(java.lang.ClassLoader myLoader, java.lang.String pkg, goldengine.java.Reduction reduction)
           
private  void readRules()
          Read the GOLD's .cgt file (provided in #setGrammar(String)) and initialize childMapand prodMap.
 void setGrammar(java.lang.String g, boolean force)
          Loads the grammar.
static ASTBuilder singleton()
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

AST_SUFFIX

public static final java.lang.String AST_SUFFIX
See Also:
Constant Field Values

instance

private static ASTBuilder instance
The singleton instance


GOLD_NON_TERMINAL_START

public static final java.lang.String GOLD_NON_TERMINAL_START
See Also:
Constant Field Values

GOLD_NON_TERMINAL_END

public static final java.lang.String GOLD_NON_TERMINAL_END
See Also:
Constant Field Values

GOLD_PROD_SYMB

public static final java.lang.String GOLD_PROD_SYMB
See Also:
Constant Field Values

curComment

private java.lang.String curComment

childMap

private final java.util.Map childMap

prodMap

private final java.util.Map prodMap
Map of namesof rule non-terminalsto an ArrayList of productions, as Strings.


out

private java.io.PrintWriter out

grammar

private java.lang.String grammar

input

private java.lang.String input

parser

private final goldengine.java.GOLDParser parser

grammarLoaded

private boolean grammarLoaded

red2Ast

private java.util.Map red2Ast
Map of Reductionto corresponding ASTNode.


ast2Comments

private java.util.Map ast2Comments

curAst

private ASTNode curAst
Current AST node (eventually this is returned by parse(ClassLoader, String, String)).


terminalMap

private java.util.Map terminalMap

caseInsensitive

private boolean caseInsensitive
Constructor Detail

ASTBuilder

private ASTBuilder()
Method Detail

singleton

public static ASTBuilder singleton()
Returns:
the singleton ASTBuilder.

nonTerminalName

private java.lang.String nonTerminalName(java.lang.String s)

isNonTerminal

private boolean isNonTerminal(java.lang.String s)

readRules

private void readRules()
Read the GOLD's .cgt file (provided in #setGrammar(String)) and initialize childMapand prodMap.


setGrammar

public void setGrammar(java.lang.String g,
                       boolean force)
                throws goldengine.java.ParserException
Loads the grammar.

Parameters:
g - path to GOLD compiled grammar (.cgt file).
force - if true, the grammar is reloaded, otherwise, if the grammar points to the same one loaded previously, it is ignored.
Throws:
goldengine.java.ParserException - whenever {GOLDParser#loadCompiledGrammar} does.
See Also:
GOLDParser.loadCompiledGrammar(String)

generateClasses

public void generateClasses(java.lang.String root,
                            java.lang.String pkg,
                            java.lang.String visitorPkg,
                            java.lang.String visitorName)
                     throws goldengine.java.ParserException,
                            java.io.IOException
Generate the classes implementing ASTNodefor each non-terminal. They will be named by the name of the non-terminal with a suffix AST_SUFFIXand structure as explained below. The parse(ClassLoader, String, String)method will instantiate and populate appropriate objects from this hierarchy during parsing, using setters as described here.

Thus, for the following production

 
  
   
    
     
      
       
        
         
          
           
            
             
              <ext_statement> ::= 
                        SUB tkName <formal_list_opt> tkEol <statement_list> END SUB tkEol
                |       DECLARE FUNCTION tkName LIB tkString <formal_list_opt> <as_opt> tkEol
                |
              
             
            
           
          
         
        
       
      
     
    
   
  
 

a ext_statement_AST class will be generated, containing the following:

In addition to the ASTNode hierarchy, a skeleton for a class extending ReflectiveVisitorwill be generated. It will provide a visit method for every ASTNode subclass that was generated. Using our example above, one such method will be:

 public void visit(ext_statement_AST node) {
     // ext_statement ::= SUB tkName <formal_list_opt> tkEol
     // <statement_list> END SUB tkEol
     if (node.getProduction().equals(ext_statement_AST.PROD_1)) {
         String curStr = "";
 
         // TERMINAL: [SUB]
         curStr += (String) node.getTerminals().get(0);
         // TERMINAL: [tkName]
         curStr += (String) node.getTerminals().get(1);
         node.get_formal_list_opt_AST().accept(this);
 
         // TODO
         curStr = this.code;
         this.code = "";
 
         // TERMINAL: [tkEol]
         curStr += (String) node.getTerminals().get(2);
         node.get_statement_list_AST().accept(this);
 
         // TODO
         curStr = this.code;
         this.code = "";
 
         // TERMINAL: [END]
         curStr += (String) node.getTerminals().get(3);
 
         // TERMINAL: [SUB]
         curStr += (String) node.getTerminals().get(4);
 
         // TERMINAL: [tkEol]
         curStr += (String) node.getTerminals().get(5);
         return;
     }
 
     // ext_statement ::= DECLARE FUNCTION tkName LIB tkString
     // <formal_list_opt> <as_opt> tkEol
     if (node.getProduction().equals(ext_statement_AST.PROD_2)) {
         String curStr = "";
 
         // TERMINAL: [DECLARE]
         curStr += (String) node.getTerminals().get(0);
 
         // TERMINAL: [FUNCTION]
         curStr += (String) node.getTerminals().get(1);
 
         // TERMINAL: [tkName]
         curStr += (String) node.getTerminals().get(2);
 
         // TERMINAL: [LIB]
         curStr += (String) node.getTerminals().get(3);
 
         // TERMINAL: [tkString]
         curStr += (String) node.getTerminals().get(4);
 
         node.get_formal_list_opt_AST().accept(this);
 
         // TODO
         curStr = this.code;
         this.code = "";
         node.get_as_opt_AST().accept(this);
 
         // TODO
         curStr = this.code;
         this.code = "";
         // TERMINAL: [tkEol]
         curStr += (String) node.getTerminals().get(5);
         return;
     }
 
     // ext_statement ::=
     if (node.getProduction().equals(ext_statement_AST.PROD_3)) {
         String curStr = "";
         return;
     }
 }
 

This visitor can then be modified.

TODO

  1. If rhs is a single non-terminal, just visit that one, without touching this.code
  2. If the production is empty, do nothing
  3. BUG: how to handle same names in a rhs? E.g.: ::= FOR TO ? For now, introduce Nodes list.
  4. Generate rudimentary Javadoc with the code.

Parameters:
root - path where the pkg containing generated classes is to be created
pkg - package into which to place generated classes; if it exists, its contents will be deleted prior to the generation.
visitorPkg - package into which a subclass of ReflectiveVisitoris generated -- different from pkg in that it's something to be modified/customized by a developer, rather than to be used as generated.
visitorName - a name of the subclass of ReflectiveVisitorto be generated.
Throws:
goldengine.java.ParserException - if an error occurs
java.io.IOException

pkg2Dir

public static final java.lang.String pkg2Dir(java.lang.String pkg)

getAllAsts

public java.util.Collection getAllAsts()

parse

public ASTNode parse(java.lang.ClassLoader loader,
                     java.lang.String pkg,
                     java.lang.String input)
              throws goldengine.java.ParserException
Parse the input.

Parameters:
loader - ClassLoader to use to load classes implementing ASTNode that were generated by #generateClasses(String, String)(useful if not running in an IDE, etc.); if null, then Thread.getContextClassLoader()of the Thread.currentThread()is used.
pkg - package where the classes implementing ASTNode that were generated by #generateClasses(String, String) reside.
input - input to parse.
Returns:
the ASTNode corresponding to the last ( <start> production).
Throws:
goldengine.java.ParserException - if there were any errors in parsing

getAst2Comments

public java.util.Map getAst2Comments()

main

public static void main(java.lang.String[] argv)
Parameters:
argv - In the following order:
  1. E.g.,

getTerminalMap

public java.util.Map getTerminalMap()

processReduction

private void processReduction(java.lang.ClassLoader myLoader,
                              java.lang.String pkg,
                              goldengine.java.Reduction reduction)
                       throws goldengine.java.ParserException
Throws:
goldengine.java.ParserException

getStart

public ASTNode getStart()