class MacroParser(Parser): rnormalize = { re.compile(r'\s+'): '' } def __init__(self, nonTerminalParser, terminalParser, sListMacroParser, nListMacroParser, tListMacroParser, mListMacroParser, optionalMacroParser, expand=True): self.__dict__.update(locals()) self.logger = LoggerFactory().getClassLogger(__name__, self.__class__.__name__) def parse(self, string): self.logger.debug('Parsing macro %s' % (string)) if string[:5].lower() == 'tlist': macro = self.tListMacroParser.parse(string, self.expand) elif string[:5].lower() == 'mlist': macro = self.mListMacroParser.parse(string, self.expand) elif string[:8].lower() == 'optional': macro = self.optionalMacroParser.parse(string, self.expand) elif string[:4].lower() == 'list': (nonterminal, separator, minimum) = pad(3, string[5:-1].split(',')) if separator: macro = self.sListMacroParser.parse(string, self.expand) else: macro = self.nListMacroParser.parse(string, self.expand) self.logger.debug('Parsed macro: %s' % (macro)) return macro
class Rule: def __init__(self, nonterminal, production, id=None, root=None, ast=None): self.__dict__.update(locals()) self.logger = LoggerFactory().getClassLogger(__name__, self.__class__.__name__) def __copy__(self): return Rule(self.nonterminal, Production(copy(self.production.morphemes)), self.id, self.root, self.ast) def isTokenAlias(self): if len(self.production.morphemes) == 1 and isinstance( self.production.morphemes[0], Terminal): return self.production.morphemes[0] return False def isAliasFor(self, terminal_str): # terminal alias rule is a rule in the form nt := 'terminal' return len(self.production.morphemes) == 1 and isinstance( self.production.morphemes[0], Terminal) and self.production.morphemes[0].string == terminal_str def expand(self): morphemes = [] rules = [] for m in self.production.morphemes: if isinstance(m, LL1ListMacro): rules.extend(m.rules) morphemes.append(m.start_nt) else: morphemes.append(m) rules.append( Rule(self.nonterminal, Production(morphemes), self.id, self.root, self.ast)) self.logger.debug('[rule expansion] %s becomes %s' % (self, ', '.join([str(x) for x in rules]))) return rules def str(self, theme=None): return self.__str__(theme) def __str__(self, theme=None): astString = '' if self.ast and not (isinstance(self.ast, AstTranslation) and self.ast.idx == 0): astString = ' -> %s' % (self.ast.str(theme) if theme else self.ast) nonterminal = self.nonterminal.str(theme) if theme else str( self.nonterminal) production = self.production.str(theme) if theme else str( self.production) rule = "%s := %s%s" % (nonterminal, production, astString) return theme.rule(rule) if theme else rule def getProduction(self): return self.production def getNonTerminal(self): return self.nonterminal
class Rule: def __init__( self, nonterminal, production, id=None, root=None, ast=None): self.__dict__.update(locals()) self.logger = LoggerFactory().getClassLogger(__name__, self.__class__.__name__) def __copy__( self ): return Rule(self.nonterminal, Production(copy(self.production.morphemes)), self.id, self.root, self.ast) def isTokenAlias(self): if len(self.production.morphemes) == 1 and isinstance(self.production.morphemes[0], Terminal): return self.production.morphemes[0] return False def isAliasFor(self, terminal_str): # terminal alias rule is a rule in the form nt := 'terminal' return len(self.production.morphemes) == 1 and isinstance(self.production.morphemes[0], Terminal) and self.production.morphemes[0].string == terminal_str def expand( self ): morphemes = [] rules = [] for m in self.production.morphemes: if isinstance(m, LL1ListMacro): rules.extend(m.rules) morphemes.append(m.start_nt) else: morphemes.append(m) rules.append(Rule(self.nonterminal, Production(morphemes), self.id, self.root, self.ast)) self.logger.debug('[rule expansion] %s becomes %s' % (self, ', '.join([str(x) for x in rules]))) return rules def str( self, theme = None ): return self.__str__( theme ) def __str__( self, theme = None ): astString = '' if self.ast and not (isinstance(self.ast, AstTranslation) and self.ast.idx == 0): astString = ' -> %s' % (self.ast.str(theme) if theme else self.ast) nonterminal = self.nonterminal.str(theme) if theme else str(self.nonterminal) production = self.production.str(theme) if theme else str(self.production) rule = "%s := %s%s" % ( nonterminal, production, astString) return theme.rule(rule) if theme else rule def getProduction(self): return self.production def getNonTerminal(self): return self.nonterminal
def __init__( self, nonterminal, production, id=None, root=None, ast=None): self.__dict__.update(locals()) self.logger = LoggerFactory().getClassLogger(__name__, self.__class__.__name__)
def __init__(self, nonTerminalParser, terminalParser, sListMacroParser, nListMacroParser, tListMacroParser, mListMacroParser, optionalMacroParser, expand=True): self.__dict__.update(locals()) self.logger = LoggerFactory().getClassLogger(__name__, self.__class__.__name__)
def __init__(self, nonterminal, production, id=None, root=None, ast=None): self.__dict__.update(locals()) self.logger = LoggerFactory().getClassLogger(__name__, self.__class__.__name__)
def Cli(): ver = sys.version_info # Version 3.2 required for argparse if ver.major < 3 or (ver.major == 3 and ver.minor < 2): print("Python 3.2+ required. %d.%d.%d installed" %(ver.major, ver.minor, ver.micro)) sys.exit(-1) parser = argparse.ArgumentParser( description = 'Hermes Parser Generator', epilog = '(c) 2011-2012 Scott Frazer') parser.add_argument('action', choices = ['analyze', 'generate'], help = 'Parser Generator Actions') parser.add_argument('grammar', metavar = 'GRAMMAR', nargs = '+', help = 'Grammar file') parser.add_argument('--version', action='version', version=str(pkg_resources.get_distribution('hermes-parser'))) parser.add_argument('-D', '--debug', required = False, action='store_true', help = 'Open the floodgates') parser.add_argument('-d', '--directory', required=False, default='.', help='Directory to write generated code to') parser.add_argument('-l', '--language', required = False, default='python', choices=['c', 'java', 'python'], help = 'Language for generated parser') parser.add_argument('--java-package', required = False, help = 'If generating Java code, this is the package.') parser.add_argument('-c', '--color', required = False, action = 'store_true', help = 'Prints things in color! For the colorblind, this is a no-op.') parser.add_argument('-m', '--add-main', required = False, action = 'store_true', help = 'If this is specified, a main() function will be generated in the source code.') cli = parser.parse_args() logger = LoggerFactory().initialize(cli.debug) logger.debug('CLI Parameters: %s' % (cli)) factory = HermesParserFactory() fp = GrammarFileParser(factory.create()) grammars = [] for grammar in cli.grammar: if not os.path.isfile( grammar ): sys.stderr.write("Error: Grammar file doesn't exist\n") sys.exit(-1) name = os.path.basename(grammar) if not name.endswith('.zgr'): sys.stderr.write("Error: Grammar file must have .zgr extension\n") sys.exit(-1) name = name[:-4] grammars.append( fp.parse(name, open(grammar)) ) if cli.action == 'analyze': if cli.color: theme = TerminalColorTheme() else: theme = TerminalDefaultTheme() for grammar in grammars: analyzer = GrammarAnalyzer(grammar) analyzer.analyze( theme=theme ) if cli.action == 'generate': cli.directory = os.path.abspath(os.path.expanduser(cli.directory)) if not os.path.isdir( cli.directory ): sys.stderr.write("Error: Directory doesn't exist\n") sys.exit(-1) elif not os.access(cli.directory, os.W_OK): sys.stderr.write("Error: Directory not writable\n") sys.exit(-1) templateFactory = TemplateFactoryFactory().create(outputLanguage=cli.language.lower()) templateWriter = TemplateWriter(templateFactory) templateWriter.write(grammars, cli.directory, addMain=cli.add_main, javaPackage=cli.java_package)
def Cli(): ver = sys.version_info # Version 3.2 required for argparse if ver.major < 3 or (ver.major == 3 and ver.minor < 2): print("Python 3.2+ required. %d.%d.%d installed" % (ver.major, ver.minor, ver.micro)) sys.exit(-1) parser = argparse.ArgumentParser(description='Hermes Parser Generator', epilog='(c) 2011-2012 Scott Frazer') parser.add_argument('action', choices=['analyze', 'generate'], help='Parser Generator Actions') parser.add_argument('grammar', metavar='GRAMMAR', nargs='+', help='Grammar file') parser.add_argument('--version', action='version', version=str( pkg_resources.get_distribution('hermes-parser'))) parser.add_argument('-D', '--debug', required=False, action='store_true', help='Open the floodgates') parser.add_argument('-d', '--directory', required=False, default='.', help='Directory to write generated code to') parser.add_argument('-l', '--language', required=False, default='python', choices=['c', 'java', 'python'], help='Language for generated parser') parser.add_argument('--java-package', required=False, help='If generating Java code, this is the package.') parser.add_argument( '-c', '--color', required=False, action='store_true', help='Prints things in color! For the colorblind, this is a no-op.') parser.add_argument( '-m', '--add-main', required=False, action='store_true', help= 'If this is specified, a main() function will be generated in the source code.' ) cli = parser.parse_args() logger = LoggerFactory().initialize(cli.debug) logger.debug('CLI Parameters: %s' % (cli)) factory = HermesParserFactory() fp = GrammarFileParser(factory.create()) grammars = [] for grammar in cli.grammar: if not os.path.isfile(grammar): sys.stderr.write("Error: Grammar file doesn't exist\n") sys.exit(-1) name = os.path.basename(grammar) if not name.endswith('.zgr'): sys.stderr.write("Error: Grammar file must have .zgr extension\n") sys.exit(-1) name = name[:-4] grammars.append(fp.parse(name, open(grammar))) if cli.action == 'analyze': if cli.color: theme = TerminalColorTheme() else: theme = TerminalDefaultTheme() for grammar in grammars: analyzer = GrammarAnalyzer(grammar) analyzer.analyze(theme=theme) if cli.action == 'generate': cli.directory = os.path.abspath(os.path.expanduser(cli.directory)) if not os.path.isdir(cli.directory): sys.stderr.write("Error: Directory doesn't exist\n") sys.exit(-1) elif not os.access(cli.directory, os.W_OK): sys.stderr.write("Error: Directory not writable\n") sys.exit(-1) templateFactory = TemplateFactoryFactory().create( outputLanguage=cli.language.lower()) templateWriter = TemplateWriter(templateFactory) templateWriter.write(grammars, cli.directory, addMain=cli.add_main, javaPackage=cli.java_package)