diff --git a/plugins/explain.py b/plugins/explain.py new file mode 100755 index 0000000..44fba6b --- /dev/null +++ b/plugins/explain.py @@ -0,0 +1,14 @@ +from pycparser.cdecl import explain_c_declaration + +@hook.command('explain') +def explain(inp): + '''.explain char *(*(**foo[][8])())[]; -- returns : +foo is a array of array[8] of pointer to pointer to function() returning pointer + to array of pointer to char +''' + if not inp: + return None + + result = explain_c_declaration(inp) + if result: return result + else: return None \ No newline at end of file diff --git a/plugins/pycparser/cdecl.py b/plugins/pycparser/cdecl.py new file mode 100644 index 0000000..8816cfa --- /dev/null +++ b/plugins/pycparser/cdecl.py @@ -0,0 +1,106 @@ +#----------------------------------------------------------------- +# pycparser: cdecl.py +# +# Example of the CDECL tool using pycparser. CDECL "explains" +# C type declarations in plain English. +# +# The AST generated by pycparser from the given declaration is +# traversed recursively to build the explanation. +# Note that the declaration must be a valid external declaration +# in C. All the types used in it must be defined with typedef, +# or parsing will fail. The definition can be arbitrary, it isn't +# really used - by pycparser must know which tokens are types. +# +# For example: +# +# 'typedef int Node; const Node* (*ar)[10];' +# => +# ar is a pointer to array[10] of pointer to const Node +# +# Copyright (C) 2008, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- +import sys + +# This is not required if you've installed pycparser into +# your site-packages/ with setup.py +# +sys.path.insert(0, '..') + +from pycparser import c_parser, c_ast + + +def explain_c_declaration(c_decl): + """ Parses the declaration in c_decl and returns a text + explanation as a string. + + The last external node of the string is used, to allow + earlier typedefs for used types. + """ + parser = c_parser.CParser() + + try: + node = parser.parse(c_decl, filename='') + except c_parser.ParseError, e: + return None + + if ( not isinstance(node, c_ast.FileAST) or + not isinstance(node.ext[-1], c_ast.Decl)): + return None + + return _explain_decl_node(node.ext[-1]) + + +def _explain_decl_node(decl_node): + """ Receives a c_ast.Decl note and returns its explanation in + English. + """ + #~ print decl_node.show() + storage = ' '.join(decl_node.storage) + ' ' if decl_node.storage else '' + + return (decl_node.name + + " is a " + + storage + + _explain_type(decl_node.type)) + + +def _explain_type(decl): + """ Recursively explains a type decl node + """ + typ = type(decl) + + if typ == c_ast.TypeDecl: + quals = ' '.join(decl.quals) + ' ' if decl.quals else '' + return quals + _explain_type(decl.type) + elif typ == c_ast.Typename or typ == c_ast.Decl: + return _explain_type(decl.type) + elif typ == c_ast.IdentifierType: + return ' '.join(decl.names) + elif typ == c_ast.PtrDecl: + quals = ' '.join(decl.quals) + ' ' if decl.quals else '' + return quals + 'pointer to ' + _explain_type(decl.type) + elif typ == c_ast.ArrayDecl: + arr = 'array' + if decl.dim: arr += '[%s]' % decl.dim.value + + return arr + " of " + _explain_type(decl.type) + + elif typ == c_ast.FuncDecl: + if decl.args: + params = [_explain_type(param) for param in decl.args.params] + args = ', '.join(params) + else: + args = '' + + return ('function(%s) returning ' % (args) + + _explain_type(decl.type)) + + +if __name__ == "__main__": + if len(sys.argv) > 1: + c_decl = sys.argv[1] + else: + c_decl = "char *(*(**foo[][8])())[];" + + print "Explaining the declaration:", c_decl + print "\n", explain_c_declaration(c_decl) diff --git a/plugins/pycparser/lextab.py b/plugins/pycparser/lextab.py new file mode 100644 index 0000000..f33ce0c --- /dev/null +++ b/plugins/pycparser/lextab.py @@ -0,0 +1,9 @@ +# pycparser.lextab.py. This file automatically created by PLY (version 3.3). Don't edit! +_tabversion = '3.3' +_lextokens = {'VOID': 1, 'LBRACKET': 1, 'WCHAR_CONST': 1, 'FLOAT_CONST': 1, 'MINUS': 1, 'RPAREN': 1, 'LONG': 1, 'PLUS': 1, 'ELLIPSIS': 1, 'GT': 1, 'GOTO': 1, 'ENUM': 1, 'PERIOD': 1, 'GE': 1, 'INT_CONST_DEC': 1, 'ARROW': 1, 'DOUBLE': 1, 'MINUSEQUAL': 1, 'INT_CONST_OCT': 1, 'TIMESEQUAL': 1, 'OR': 1, 'SHORT': 1, 'RETURN': 1, 'RSHIFTEQUAL': 1, 'STATIC': 1, 'SIZEOF': 1, 'UNSIGNED': 1, 'UNION': 1, 'COLON': 1, 'WSTRING_LITERAL': 1, 'DIVIDE': 1, 'FOR': 1, 'PLUSPLUS': 1, 'EQUALS': 1, 'ELSE': 1, 'EQ': 1, 'AND': 1, 'TYPEID': 1, 'LBRACE': 1, 'PPHASH': 1, 'INT': 1, 'SIGNED': 1, 'CONTINUE': 1, 'NOT': 1, 'OREQUAL': 1, 'MOD': 1, 'RSHIFT': 1, 'DEFAULT': 1, 'CHAR': 1, 'WHILE': 1, 'DIVEQUAL': 1, 'EXTERN': 1, 'CASE': 1, 'LAND': 1, 'REGISTER': 1, 'MODEQUAL': 1, 'NE': 1, 'SWITCH': 1, 'INT_CONST_HEX': 1, 'PLUSEQUAL': 1, 'STRUCT': 1, 'CONDOP': 1, 'BREAK': 1, 'VOLATILE': 1, 'ANDEQUAL': 1, 'DO': 1, 'LNOT': 1, 'CONST': 1, 'LOR': 1, 'CHAR_CONST': 1, 'LSHIFT': 1, 'RBRACE': 1, 'LE': 1, 'SEMI': 1, 'LT': 1, 'COMMA': 1, 'TYPEDEF': 1, 'XOR': 1, 'AUTO': 1, 'TIMES': 1, 'LPAREN': 1, 'MINUSMINUS': 1, 'ID': 1, 'IF': 1, 'STRING_LITERAL': 1, 'FLOAT': 1, 'XOREQUAL': 1, 'LSHIFTEQUAL': 1, 'RBRACKET': 1} +_lexreflags = 0 +_lexliterals = '' +_lexstateinfo = {'ppline': 'exclusive', 'INITIAL': 'inclusive'} +_lexstatere = {'ppline': [('(?P"([^"\\\\\\n]|(\\\\(([a-zA-Z\\\\?\'"])|([0-7]{1,3})|(x[0-9a-fA-F]+))))*")|(?P(0(([uU][lL])|([lL][uU])|[uU]|[lL])?)|([1-9][0-9]*(([uU][lL])|([lL][uU])|[uU]|[lL])?))|(?P\\n)|(?Pline)', [None, ('t_ppline_FILENAME', 'FILENAME'), None, None, None, None, None, None, ('t_ppline_LINE_NUMBER', 'LINE_NUMBER'), None, None, None, None, None, None, None, None, ('t_ppline_NEWLINE', 'NEWLINE'), ('t_ppline_PPLINE', 'PPLINE')])], 'INITIAL': [('(?P[ \\t]*\\#)|(?P\\n+)|(?P((((([0-9]*\\.[0-9]+)|([0-9]+\\.))([eE][-+]?[0-9]+)?)|([0-9]+([eE][-+]?[0-9]+)))[FfLl]?))|(?P0[xX][0-9a-fA-F]+(([uU][lL])|([lL][uU])|[uU]|[lL])?)|(?P0[0-7]*[89])|(?P0[0-7]*(([uU][lL])|([lL][uU])|[uU]|[lL])?)|(?P(0(([uU][lL])|([lL][uU])|[uU]|[lL])?)|([1-9][0-9]*(([uU][lL])|([lL][uU])|[uU]|[lL])?))|(?P\'([^\'\\\\\\n]|(\\\\(([a-zA-Z\\\\?\'"])|([0-7]{1,3})|(x[0-9a-fA-F]+))))\')|(?PL\'([^\'\\\\\\n]|(\\\\(([a-zA-Z\\\\?\'"])|([0-7]{1,3})|(x[0-9a-fA-F]+))))\')|(?P(\'([^\'\\\\\\n]|(\\\\(([a-zA-Z\\\\?\'"])|([0-7]{1,3})|(x[0-9a-fA-F]+))))*\\n)|(\'([^\'\\\\\\n]|(\\\\(([a-zA-Z\\\\?\'"])|([0-7]{1,3})|(x[0-9a-fA-F]+))))*$))|(?P(\'([^\'\\\\\\n]|(\\\\(([a-zA-Z\\\\?\'"])|([0-7]{1,3})|(x[0-9a-fA-F]+))))[^\'\n]+\')|(\'\')|(\'([\\\\][^a-zA-Z\\\\?\'"x0-7])[^\'\\n]*\'))|(?PL"([^"\\\\\\n]|(\\\\(([a-zA-Z\\\\?\'"])|([0-7]{1,3})|(x[0-9a-fA-F]+))))*")|(?P"([^"\\\\\\n]|(\\\\(([a-zA-Z\\\\?\'"])|([0-7]{1,3})|(x[0-9a-fA-F]+))))*([\\\\][^a-zA-Z\\\\?\'"x0-7])([^"\\\\\\n]|(\\\\(([a-zA-Z\\\\?\'"])|([0-7]{1,3})|(x[0-9a-fA-F]+))))*")|(?P[a-zA-Z_][0-9a-zA-Z_]*)|(?P"([^"\\\\\\n]|(\\\\(([a-zA-Z\\\\?\'"])|([0-7]{1,3})|(x[0-9a-fA-F]+))))*")', [None, ('t_PPHASH', 'PPHASH'), ('t_NEWLINE', 'NEWLINE'), ('t_FLOAT_CONST', 'FLOAT_CONST'), None, None, None, None, None, None, None, None, None, ('t_INT_CONST_HEX', 'INT_CONST_HEX'), None, None, None, ('t_BAD_CONST_OCT', 'BAD_CONST_OCT'), ('t_INT_CONST_OCT', 'INT_CONST_OCT'), None, None, None, ('t_INT_CONST_DEC', 'INT_CONST_DEC'), None, None, None, None, None, None, None, None, ('t_CHAR_CONST', 'CHAR_CONST'), None, None, None, None, None, None, ('t_WCHAR_CONST', 'WCHAR_CONST'), None, None, None, None, None, None, ('t_UNMATCHED_QUOTE', 'UNMATCHED_QUOTE'), None, None, None, None, None, None, None, None, None, None, None, None, None, None, ('t_BAD_CHAR_CONST', 'BAD_CHAR_CONST'), None, None, None, None, None, None, None, None, None, None, ('t_WSTRING_LITERAL', 'WSTRING_LITERAL'), None, None, None, None, None, None, ('t_BAD_STRING_LITERAL', 'BAD_STRING_LITERAL'), None, None, None, None, None, None, None, None, None, None, None, None, None, ('t_ID', 'ID'), (None, 'STRING_LITERAL')]), ('(?P\\.\\.\\.)|(?P\\+\\+)|(?P\\|\\|)|(?P\\|=)|(?P<<=)|(?P>>=)|(?P\\*=)|(?P\\+=)|(?P^=)|(?P\\+)|(?P%=)|(?P\\{)|(?P/=)|(?P\\])|(?P\\?)', [None, (None, 'ELLIPSIS'), (None, 'PLUSPLUS'), (None, 'LOR'), (None, 'OREQUAL'), (None, 'LSHIFTEQUAL'), (None, 'RSHIFTEQUAL'), (None, 'TIMESEQUAL'), (None, 'PLUSEQUAL'), (None, 'XOREQUAL'), (None, 'PLUS'), (None, 'MODEQUAL'), (None, 'LBRACE'), (None, 'DIVEQUAL'), (None, 'RBRACKET'), (None, 'CONDOP')]), ('(?P\\^)|(?P<<)|(?P<=)|(?P\\()|(?P->)|(?P==)|(?P\\})|(?P!=)|(?P--)|(?P\\|)|(?P\\*)|(?P\\[)|(?P>=)|(?P\\))|(?P&&)|(?P>>)|(?P&=)|(?P-=)|(?P\\.)|(?P=)|(?P<)|(?P,)|(?P/)|(?P&)|(?P%)|(?P;)|(?P-)|(?P>)|(?P:)|(?P~)|(?P!)', [None, (None, 'XOR'), (None, 'LSHIFT'), (None, 'LE'), (None, 'LPAREN'), (None, 'ARROW'), (None, 'EQ'), (None, 'RBRACE'), (None, 'NE'), (None, 'MINUSMINUS'), (None, 'OR'), (None, 'TIMES'), (None, 'LBRACKET'), (None, 'GE'), (None, 'RPAREN'), (None, 'LAND'), (None, 'RSHIFT'), (None, 'ANDEQUAL'), (None, 'MINUSEQUAL'), (None, 'PERIOD'), (None, 'EQUALS'), (None, 'LT'), (None, 'COMMA'), (None, 'DIVIDE'), (None, 'AND'), (None, 'MOD'), (None, 'SEMI'), (None, 'MINUS'), (None, 'GT'), (None, 'COLON'), (None, 'NOT'), (None, 'LNOT')])]} +_lexstateignore = {'ppline': ' \t', 'INITIAL': ' \t'} +_lexstateerrorf = {'ppline': 't_ppline_error', 'INITIAL': 't_error'} diff --git a/plugins/pycparser/ply/__init__.py b/plugins/pycparser/ply/__init__.py new file mode 100644 index 0000000..853a985 --- /dev/null +++ b/plugins/pycparser/ply/__init__.py @@ -0,0 +1,4 @@ +# PLY package +# Author: David Beazley (dave@dabeaz.com) + +__all__ = ['lex','yacc'] diff --git a/plugins/pycparser/ply/cpp.py b/plugins/pycparser/ply/cpp.py new file mode 100644 index 0000000..39f9d47 --- /dev/null +++ b/plugins/pycparser/ply/cpp.py @@ -0,0 +1,898 @@ +# ----------------------------------------------------------------------------- +# cpp.py +# +# Author: David Beazley (http://www.dabeaz.com) +# Copyright (C) 2007 +# All rights reserved +# +# This module implements an ANSI-C style lexical preprocessor for PLY. +# ----------------------------------------------------------------------------- +from __future__ import generators + +# ----------------------------------------------------------------------------- +# Default preprocessor lexer definitions. These tokens are enough to get +# a basic preprocessor working. Other modules may import these if they want +# ----------------------------------------------------------------------------- + +tokens = ( + 'CPP_ID','CPP_INTEGER', 'CPP_FLOAT', 'CPP_STRING', 'CPP_CHAR', 'CPP_WS', 'CPP_COMMENT', 'CPP_POUND','CPP_DPOUND' +) + +literals = "+-*/%|&~^<>=!?()[]{}.,;:\\\'\"" + +# Whitespace +def t_CPP_WS(t): + r'\s+' + t.lexer.lineno += t.value.count("\n") + return t + +t_CPP_POUND = r'\#' +t_CPP_DPOUND = r'\#\#' + +# Identifier +t_CPP_ID = r'[A-Za-z_][\w_]*' + +# Integer literal +def CPP_INTEGER(t): + r'(((((0x)|(0X))[0-9a-fA-F]+)|(\d+))([uU]|[lL]|[uU][lL]|[lL][uU])?)' + return t + +t_CPP_INTEGER = CPP_INTEGER + +# Floating literal +t_CPP_FLOAT = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?' + +# String literal +def t_CPP_STRING(t): + r'\"([^\\\n]|(\\(.|\n)))*?\"' + t.lexer.lineno += t.value.count("\n") + return t + +# Character constant 'c' or L'c' +def t_CPP_CHAR(t): + r'(L)?\'([^\\\n]|(\\(.|\n)))*?\'' + t.lexer.lineno += t.value.count("\n") + return t + +# Comment +def t_CPP_COMMENT(t): + r'(/\*(.|\n)*?\*/)|(//.*?\n)' + t.lexer.lineno += t.value.count("\n") + return t + +def t_error(t): + t.type = t.value[0] + t.value = t.value[0] + t.lexer.skip(1) + return t + +import re +import copy +import time +import os.path + +# ----------------------------------------------------------------------------- +# trigraph() +# +# Given an input string, this function replaces all trigraph sequences. +# The following mapping is used: +# +# ??= # +# ??/ \ +# ??' ^ +# ??( [ +# ??) ] +# ??! | +# ??< { +# ??> } +# ??- ~ +# ----------------------------------------------------------------------------- + +_trigraph_pat = re.compile(r'''\?\?[=/\'\(\)\!<>\-]''') +_trigraph_rep = { + '=':'#', + '/':'\\', + "'":'^', + '(':'[', + ')':']', + '!':'|', + '<':'{', + '>':'}', + '-':'~' +} + +def trigraph(input): + return _trigraph_pat.sub(lambda g: _trigraph_rep[g.group()[-1]],input) + +# ------------------------------------------------------------------ +# Macro object +# +# This object holds information about preprocessor macros +# +# .name - Macro name (string) +# .value - Macro value (a list of tokens) +# .arglist - List of argument names +# .variadic - Boolean indicating whether or not variadic macro +# .vararg - Name of the variadic parameter +# +# When a macro is created, the macro replacement token sequence is +# pre-scanned and used to create patch lists that are later used +# during macro expansion +# ------------------------------------------------------------------ + +class Macro(object): + def __init__(self,name,value,arglist=None,variadic=False): + self.name = name + self.value = value + self.arglist = arglist + self.variadic = variadic + if variadic: + self.vararg = arglist[-1] + self.source = None + +# ------------------------------------------------------------------ +# Preprocessor object +# +# Object representing a preprocessor. Contains macro definitions, +# include directories, and other information +# ------------------------------------------------------------------ + +class Preprocessor(object): + def __init__(self,lexer=None): + if lexer is None: + lexer = lex.lexer + self.lexer = lexer + self.macros = { } + self.path = [] + self.temp_path = [] + + # Probe the lexer for selected tokens + self.lexprobe() + + tm = time.localtime() + self.define("__DATE__ \"%s\"" % time.strftime("%b %d %Y",tm)) + self.define("__TIME__ \"%s\"" % time.strftime("%H:%M:%S",tm)) + self.parser = None + + # ----------------------------------------------------------------------------- + # tokenize() + # + # Utility function. Given a string of text, tokenize into a list of tokens + # ----------------------------------------------------------------------------- + + def tokenize(self,text): + tokens = [] + self.lexer.input(text) + while True: + tok = self.lexer.token() + if not tok: break + tokens.append(tok) + return tokens + + # --------------------------------------------------------------------- + # error() + # + # Report a preprocessor error/warning of some kind + # ---------------------------------------------------------------------- + + def error(self,file,line,msg): + print >>sys.stderr,"%s:%d %s" % (file,line,msg) + + # ---------------------------------------------------------------------- + # lexprobe() + # + # This method probes the preprocessor lexer object to discover + # the token types of symbols that are important to the preprocessor. + # If this works right, the preprocessor will simply "work" + # with any suitable lexer regardless of how tokens have been named. + # ---------------------------------------------------------------------- + + def lexprobe(self): + + # Determine the token type for identifiers + self.lexer.input("identifier") + tok = self.lexer.token() + if not tok or tok.value != "identifier": + print "Couldn't determine identifier type" + else: + self.t_ID = tok.type + + # Determine the token type for integers + self.lexer.input("12345") + tok = self.lexer.token() + if not tok or int(tok.value) != 12345: + print "Couldn't determine integer type" + else: + self.t_INTEGER = tok.type + self.t_INTEGER_TYPE = type(tok.value) + + # Determine the token type for strings enclosed in double quotes + self.lexer.input("\"filename\"") + tok = self.lexer.token() + if not tok or tok.value != "\"filename\"": + print "Couldn't determine string type" + else: + self.t_STRING = tok.type + + # Determine the token type for whitespace--if any + self.lexer.input(" ") + tok = self.lexer.token() + if not tok or tok.value != " ": + self.t_SPACE = None + else: + self.t_SPACE = tok.type + + # Determine the token type for newlines + self.lexer.input("\n") + tok = self.lexer.token() + if not tok or tok.value != "\n": + self.t_NEWLINE = None + print "Couldn't determine token for newlines" + else: + self.t_NEWLINE = tok.type + + self.t_WS = (self.t_SPACE, self.t_NEWLINE) + + # Check for other characters used by the preprocessor + chars = [ '<','>','#','##','\\','(',')',',','.'] + for c in chars: + self.lexer.input(c) + tok = self.lexer.token() + if not tok or tok.value != c: + print "Unable to lex '%s' required for preprocessor" % c + + # ---------------------------------------------------------------------- + # add_path() + # + # Adds a search path to the preprocessor. + # ---------------------------------------------------------------------- + + def add_path(self,path): + self.path.append(path) + + # ---------------------------------------------------------------------- + # group_lines() + # + # Given an input string, this function splits it into lines. Trailing whitespace + # is removed. Any line ending with \ is grouped with the next line. This + # function forms the lowest level of the preprocessor---grouping into text into + # a line-by-line format. + # ---------------------------------------------------------------------- + + def group_lines(self,input): + lex = self.lexer.clone() + lines = [x.rstrip() for x in input.splitlines()] + for i in xrange(len(lines)): + j = i+1 + while lines[i].endswith('\\') and (j < len(lines)): + lines[i] = lines[i][:-1]+lines[j] + lines[j] = "" + j += 1 + + input = "\n".join(lines) + lex.input(input) + lex.lineno = 1 + + current_line = [] + while True: + tok = lex.token() + if not tok: + break + current_line.append(tok) + if tok.type in self.t_WS and '\n' in tok.value: + yield current_line + current_line = [] + + if current_line: + yield current_line + + # ---------------------------------------------------------------------- + # tokenstrip() + # + # Remove leading/trailing whitespace tokens from a token list + # ---------------------------------------------------------------------- + + def tokenstrip(self,tokens): + i = 0 + while i < len(tokens) and tokens[i].type in self.t_WS: + i += 1 + del tokens[:i] + i = len(tokens)-1 + while i >= 0 and tokens[i].type in self.t_WS: + i -= 1 + del tokens[i+1:] + return tokens + + + # ---------------------------------------------------------------------- + # collect_args() + # + # Collects comma separated arguments from a list of tokens. The arguments + # must be enclosed in parenthesis. Returns a tuple (tokencount,args,positions) + # where tokencount is the number of tokens consumed, args is a list of arguments, + # and positions is a list of integers containing the starting index of each + # argument. Each argument is represented by a list of tokens. + # + # When collecting arguments, leading and trailing whitespace is removed + # from each argument. + # + # This function properly handles nested parenthesis and commas---these do not + # define new arguments. + # ---------------------------------------------------------------------- + + def collect_args(self,tokenlist): + args = [] + positions = [] + current_arg = [] + nesting = 1 + tokenlen = len(tokenlist) + + # Search for the opening '('. + i = 0 + while (i < tokenlen) and (tokenlist[i].type in self.t_WS): + i += 1 + + if (i < tokenlen) and (tokenlist[i].value == '('): + positions.append(i+1) + else: + self.error(self.source,tokenlist[0].lineno,"Missing '(' in macro arguments") + return 0, [], [] + + i += 1 + + while i < tokenlen: + t = tokenlist[i] + if t.value == '(': + current_arg.append(t) + nesting += 1 + elif t.value == ')': + nesting -= 1 + if nesting == 0: + if current_arg: + args.append(self.tokenstrip(current_arg)) + positions.append(i) + return i+1,args,positions + current_arg.append(t) + elif t.value == ',' and nesting == 1: + args.append(self.tokenstrip(current_arg)) + positions.append(i+1) + current_arg = [] + else: + current_arg.append(t) + i += 1 + + # Missing end argument + self.error(self.source,tokenlist[-1].lineno,"Missing ')' in macro arguments") + return 0, [],[] + + # ---------------------------------------------------------------------- + # macro_prescan() + # + # Examine the macro value (token sequence) and identify patch points + # This is used to speed up macro expansion later on---we'll know + # right away where to apply patches to the value to form the expansion + # ---------------------------------------------------------------------- + + def macro_prescan(self,macro): + macro.patch = [] # Standard macro arguments + macro.str_patch = [] # String conversion expansion + macro.var_comma_patch = [] # Variadic macro comma patch + i = 0 + while i < len(macro.value): + if macro.value[i].type == self.t_ID and macro.value[i].value in macro.arglist: + argnum = macro.arglist.index(macro.value[i].value) + # Conversion of argument to a string + if i > 0 and macro.value[i-1].value == '#': + macro.value[i] = copy.copy(macro.value[i]) + macro.value[i].type = self.t_STRING + del macro.value[i-1] + macro.str_patch.append((argnum,i-1)) + continue + # Concatenation + elif (i > 0 and macro.value[i-1].value == '##'): + macro.patch.append(('c',argnum,i-1)) + del macro.value[i-1] + continue + elif ((i+1) < len(macro.value) and macro.value[i+1].value == '##'): + macro.patch.append(('c',argnum,i)) + i += 1 + continue + # Standard expansion + else: + macro.patch.append(('e',argnum,i)) + elif macro.value[i].value == '##': + if macro.variadic and (i > 0) and (macro.value[i-1].value == ',') and \ + ((i+1) < len(macro.value)) and (macro.value[i+1].type == self.t_ID) and \ + (macro.value[i+1].value == macro.vararg): + macro.var_comma_patch.append(i-1) + i += 1 + macro.patch.sort(key=lambda x: x[2],reverse=True) + + # ---------------------------------------------------------------------- + # macro_expand_args() + # + # Given a Macro and list of arguments (each a token list), this method + # returns an expanded version of a macro. The return value is a token sequence + # representing the replacement macro tokens + # ---------------------------------------------------------------------- + + def macro_expand_args(self,macro,args): + # Make a copy of the macro token sequence + rep = [copy.copy(_x) for _x in macro.value] + + # Make string expansion patches. These do not alter the length of the replacement sequence + + str_expansion = {} + for argnum, i in macro.str_patch: + if argnum not in str_expansion: + str_expansion[argnum] = ('"%s"' % "".join([x.value for x in args[argnum]])).replace("\\","\\\\") + rep[i] = copy.copy(rep[i]) + rep[i].value = str_expansion[argnum] + + # Make the variadic macro comma patch. If the variadic macro argument is empty, we get rid + comma_patch = False + if macro.variadic and not args[-1]: + for i in macro.var_comma_patch: + rep[i] = None + comma_patch = True + + # Make all other patches. The order of these matters. It is assumed that the patch list + # has been sorted in reverse order of patch location since replacements will cause the + # size of the replacement sequence to expand from the patch point. + + expanded = { } + for ptype, argnum, i in macro.patch: + # Concatenation. Argument is left unexpanded + if ptype == 'c': + rep[i:i+1] = args[argnum] + # Normal expansion. Argument is macro expanded first + elif ptype == 'e': + if argnum not in expanded: + expanded[argnum] = self.expand_macros(args[argnum]) + rep[i:i+1] = expanded[argnum] + + # Get rid of removed comma if necessary + if comma_patch: + rep = [_i for _i in rep if _i] + + return rep + + + # ---------------------------------------------------------------------- + # expand_macros() + # + # Given a list of tokens, this function performs macro expansion. + # The expanded argument is a dictionary that contains macros already + # expanded. This is used to prevent infinite recursion. + # ---------------------------------------------------------------------- + + def expand_macros(self,tokens,expanded=None): + if expanded is None: + expanded = {} + i = 0 + while i < len(tokens): + t = tokens[i] + if t.type == self.t_ID: + if t.value in self.macros and t.value not in expanded: + # Yes, we found a macro match + expanded[t.value] = True + + m = self.macros[t.value] + if not m.arglist: + # A simple macro + ex = self.expand_macros([copy.copy(_x) for _x in m.value],expanded) + for e in ex: + e.lineno = t.lineno + tokens[i:i+1] = ex + i += len(ex) + else: + # A macro with arguments + j = i + 1 + while j < len(tokens) and tokens[j].type in self.t_WS: + j += 1 + if tokens[j].value == '(': + tokcount,args,positions = self.collect_args(tokens[j:]) + if not m.variadic and len(args) != len(m.arglist): + self.error(self.source,t.lineno,"Macro %s requires %d arguments" % (t.value,len(m.arglist))) + i = j + tokcount + elif m.variadic and len(args) < len(m.arglist)-1: + if len(m.arglist) > 2: + self.error(self.source,t.lineno,"Macro %s must have at least %d arguments" % (t.value, len(m.arglist)-1)) + else: + self.error(self.source,t.lineno,"Macro %s must have at least %d argument" % (t.value, len(m.arglist)-1)) + i = j + tokcount + else: + if m.variadic: + if len(args) == len(m.arglist)-1: + args.append([]) + else: + args[len(m.arglist)-1] = tokens[j+positions[len(m.arglist)-1]:j+tokcount-1] + del args[len(m.arglist):] + + # Get macro replacement text + rep = self.macro_expand_args(m,args) + rep = self.expand_macros(rep,expanded) + for r in rep: + r.lineno = t.lineno + tokens[i:j+tokcount] = rep + i += len(rep) + del expanded[t.value] + continue + elif t.value == '__LINE__': + t.type = self.t_INTEGER + t.value = self.t_INTEGER_TYPE(t.lineno) + + i += 1 + return tokens + + # ---------------------------------------------------------------------- + # evalexpr() + # + # Evaluate an expression token sequence for the purposes of evaluating + # integral expressions. + # ---------------------------------------------------------------------- + + def evalexpr(self,tokens): + # tokens = tokenize(line) + # Search for defined macros + i = 0 + while i < len(tokens): + if tokens[i].type == self.t_ID and tokens[i].value == 'defined': + j = i + 1 + needparen = False + result = "0L" + while j < len(tokens): + if tokens[j].type in self.t_WS: + j += 1 + continue + elif tokens[j].type == self.t_ID: + if tokens[j].value in self.macros: + result = "1L" + else: + result = "0L" + if not needparen: break + elif tokens[j].value == '(': + needparen = True + elif tokens[j].value == ')': + break + else: + self.error(self.source,tokens[i].lineno,"Malformed defined()") + j += 1 + tokens[i].type = self.t_INTEGER + tokens[i].value = self.t_INTEGER_TYPE(result) + del tokens[i+1:j+1] + i += 1 + tokens = self.expand_macros(tokens) + for i,t in enumerate(tokens): + if t.type == self.t_ID: + tokens[i] = copy.copy(t) + tokens[i].type = self.t_INTEGER + tokens[i].value = self.t_INTEGER_TYPE("0L") + elif t.type == self.t_INTEGER: + tokens[i] = copy.copy(t) + # Strip off any trailing suffixes + tokens[i].value = str(tokens[i].value) + while tokens[i].value[-1] not in "0123456789abcdefABCDEF": + tokens[i].value = tokens[i].value[:-1] + + expr = "".join([str(x.value) for x in tokens]) + expr = expr.replace("&&"," and ") + expr = expr.replace("||"," or ") + expr = expr.replace("!"," not ") + try: + result = eval(expr) + except StandardError: + self.error(self.source,tokens[0].lineno,"Couldn't evaluate expression") + result = 0 + return result + + # ---------------------------------------------------------------------- + # parsegen() + # + # Parse an input string/ + # ---------------------------------------------------------------------- + def parsegen(self,input,source=None): + + # Replace trigraph sequences + t = trigraph(input) + lines = self.group_lines(t) + + if not source: + source = "" + + self.define("__FILE__ \"%s\"" % source) + + self.source = source + chunk = [] + enable = True + iftrigger = False + ifstack = [] + + for x in lines: + for i,tok in enumerate(x): + if tok.type not in self.t_WS: break + if tok.value == '#': + # Preprocessor directive + + for tok in x: + if tok in self.t_WS and '\n' in tok.value: + chunk.append(tok) + + dirtokens = self.tokenstrip(x[i+1:]) + if dirtokens: + name = dirtokens[0].value + args = self.tokenstrip(dirtokens[1:]) + else: + name = "" + args = [] + + if name == 'define': + if enable: + for tok in self.expand_macros(chunk): + yield tok + chunk = [] + self.define(args) + elif name == 'include': + if enable: + for tok in self.expand_macros(chunk): + yield tok + chunk = [] + oldfile = self.macros['__FILE__'] + for tok in self.include(args): + yield tok + self.macros['__FILE__'] = oldfile + self.source = source + elif name == 'undef': + if enable: + for tok in self.expand_macros(chunk): + yield tok + chunk = [] + self.undef(args) + elif name == 'ifdef': + ifstack.append((enable,iftrigger)) + if enable: + if not args[0].value in self.macros: + enable = False + iftrigger = False + else: + iftrigger = True + elif name == 'ifndef': + ifstack.append((enable,iftrigger)) + if enable: + if args[0].value in self.macros: + enable = False + iftrigger = False + else: + iftrigger = True + elif name == 'if': + ifstack.append((enable,iftrigger)) + if enable: + result = self.evalexpr(args) + if not result: + enable = False + iftrigger = False + else: + iftrigger = True + elif name == 'elif': + if ifstack: + if ifstack[-1][0]: # We only pay attention if outer "if" allows this + if enable: # If already true, we flip enable False + enable = False + elif not iftrigger: # If False, but not triggered yet, we'll check expression + result = self.evalexpr(args) + if result: + enable = True + iftrigger = True + else: + self.error(self.source,dirtokens[0].lineno,"Misplaced #elif") + + elif name == 'else': + if ifstack: + if ifstack[-1][0]: + if enable: + enable = False + elif not iftrigger: + enable = True + iftrigger = True + else: + self.error(self.source,dirtokens[0].lineno,"Misplaced #else") + + elif name == 'endif': + if ifstack: + enable,iftrigger = ifstack.pop() + else: + self.error(self.source,dirtokens[0].lineno,"Misplaced #endif") + else: + # Unknown preprocessor directive + pass + + else: + # Normal text + if enable: + chunk.extend(x) + + for tok in self.expand_macros(chunk): + yield tok + chunk = [] + + # ---------------------------------------------------------------------- + # include() + # + # Implementation of file-inclusion + # ---------------------------------------------------------------------- + + def include(self,tokens): + # Try to extract the filename and then process an include file + if not tokens: + return + if tokens: + if tokens[0].value != '<' and tokens[0].type != self.t_STRING: + tokens = self.expand_macros(tokens) + + if tokens[0].value == '<': + # Include <...> + i = 1 + while i < len(tokens): + if tokens[i].value == '>': + break + i += 1 + else: + print "Malformed #include <...>" + return + filename = "".join([x.value for x in tokens[1:i]]) + path = self.path + [""] + self.temp_path + elif tokens[0].type == self.t_STRING: + filename = tokens[0].value[1:-1] + path = self.temp_path + [""] + self.path + else: + print "Malformed #include statement" + return + for p in path: + iname = os.path.join(p,filename) + try: + data = open(iname,"r").read() + dname = os.path.dirname(iname) + if dname: + self.temp_path.insert(0,dname) + for tok in self.parsegen(data,filename): + yield tok + if dname: + del self.temp_path[0] + break + except IOError,e: + pass + else: + print "Couldn't find '%s'" % filename + + # ---------------------------------------------------------------------- + # define() + # + # Define a new macro + # ---------------------------------------------------------------------- + + def define(self,tokens): + if isinstance(tokens,(str,unicode)): + tokens = self.tokenize(tokens) + + linetok = tokens + try: + name = linetok[0] + if len(linetok) > 1: + mtype = linetok[1] + else: + mtype = None + if not mtype: + m = Macro(name.value,[]) + self.macros[name.value] = m + elif mtype.type in self.t_WS: + # A normal macro + m = Macro(name.value,self.tokenstrip(linetok[2:])) + self.macros[name.value] = m + elif mtype.value == '(': + # A macro with arguments + tokcount, args, positions = self.collect_args(linetok[1:]) + variadic = False + for a in args: + if variadic: + print "No more arguments may follow a variadic argument" + break + astr = "".join([str(_i.value) for _i in a]) + if astr == "...": + variadic = True + a[0].type = self.t_ID + a[0].value = '__VA_ARGS__' + variadic = True + del a[1:] + continue + elif astr[-3:] == "..." and a[0].type == self.t_ID: + variadic = True + del a[1:] + # If, for some reason, "." is part of the identifier, strip off the name for the purposes + # of macro expansion + if a[0].value[-3:] == '...': + a[0].value = a[0].value[:-3] + continue + if len(a) > 1 or a[0].type != self.t_ID: + print "Invalid macro argument" + break + else: + mvalue = self.tokenstrip(linetok[1+tokcount:]) + i = 0 + while i < len(mvalue): + if i+1 < len(mvalue): + if mvalue[i].type in self.t_WS and mvalue[i+1].value == '##': + del mvalue[i] + continue + elif mvalue[i].value == '##' and mvalue[i+1].type in self.t_WS: + del mvalue[i+1] + i += 1 + m = Macro(name.value,mvalue,[x[0].value for x in args],variadic) + self.macro_prescan(m) + self.macros[name.value] = m + else: + print "Bad macro definition" + except LookupError: + print "Bad macro definition" + + # ---------------------------------------------------------------------- + # undef() + # + # Undefine a macro + # ---------------------------------------------------------------------- + + def undef(self,tokens): + id = tokens[0].value + try: + del self.macros[id] + except LookupError: + pass + + # ---------------------------------------------------------------------- + # parse() + # + # Parse input text. + # ---------------------------------------------------------------------- + def parse(self,input,source=None,ignore={}): + self.ignore = ignore + self.parser = self.parsegen(input,source) + + # ---------------------------------------------------------------------- + # token() + # + # Method to return individual tokens + # ---------------------------------------------------------------------- + def token(self): + try: + while True: + tok = self.parser.next() + if tok.type not in self.ignore: return tok + except StopIteration: + self.parser = None + return None + +if __name__ == '__main__': + import ply.lex as lex + lexer = lex.lex() + + # Run a preprocessor + import sys + f = open(sys.argv[1]) + input = f.read() + + p = Preprocessor(lexer) + p.parse(input,sys.argv[1]) + while True: + tok = p.token() + if not tok: break + print p.source, tok + + + + + + + + + + + diff --git a/plugins/pycparser/ply/ctokens.py b/plugins/pycparser/ply/ctokens.py new file mode 100644 index 0000000..dd5f102 --- /dev/null +++ b/plugins/pycparser/ply/ctokens.py @@ -0,0 +1,133 @@ +# ---------------------------------------------------------------------- +# ctokens.py +# +# Token specifications for symbols in ANSI C and C++. This file is +# meant to be used as a library in other tokenizers. +# ---------------------------------------------------------------------- + +# Reserved words + +tokens = [ + # Literals (identifier, integer constant, float constant, string constant, char const) + 'ID', 'TYPEID', 'ICONST', 'FCONST', 'SCONST', 'CCONST', + + # Operators (+,-,*,/,%,|,&,~,^,<<,>>, ||, &&, !, <, <=, >, >=, ==, !=) + 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MOD', + 'OR', 'AND', 'NOT', 'XOR', 'LSHIFT', 'RSHIFT', + 'LOR', 'LAND', 'LNOT', + 'LT', 'LE', 'GT', 'GE', 'EQ', 'NE', + + # Assignment (=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=) + 'EQUALS', 'TIMESEQUAL', 'DIVEQUAL', 'MODEQUAL', 'PLUSEQUAL', 'MINUSEQUAL', + 'LSHIFTEQUAL','RSHIFTEQUAL', 'ANDEQUAL', 'XOREQUAL', 'OREQUAL', + + # Increment/decrement (++,--) + 'PLUSPLUS', 'MINUSMINUS', + + # Structure dereference (->) + 'ARROW', + + # Ternary operator (?) + 'TERNARY', + + # Delimeters ( ) [ ] { } , . ; : + 'LPAREN', 'RPAREN', + 'LBRACKET', 'RBRACKET', + 'LBRACE', 'RBRACE', + 'COMMA', 'PERIOD', 'SEMI', 'COLON', + + # Ellipsis (...) + 'ELLIPSIS', +] + +# Operators +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_MODULO = r'%' +t_OR = r'\|' +t_AND = r'&' +t_NOT = r'~' +t_XOR = r'\^' +t_LSHIFT = r'<<' +t_RSHIFT = r'>>' +t_LOR = r'\|\|' +t_LAND = r'&&' +t_LNOT = r'!' +t_LT = r'<' +t_GT = r'>' +t_LE = r'<=' +t_GE = r'>=' +t_EQ = r'==' +t_NE = r'!=' + +# Assignment operators + +t_EQUALS = r'=' +t_TIMESEQUAL = r'\*=' +t_DIVEQUAL = r'/=' +t_MODEQUAL = r'%=' +t_PLUSEQUAL = r'\+=' +t_MINUSEQUAL = r'-=' +t_LSHIFTEQUAL = r'<<=' +t_RSHIFTEQUAL = r'>>=' +t_ANDEQUAL = r'&=' +t_OREQUAL = r'\|=' +t_XOREQUAL = r'^=' + +# Increment/decrement +t_INCREMENT = r'\+\+' +t_DECREMENT = r'--' + +# -> +t_ARROW = r'->' + +# ? +t_TERNARY = r'\?' + +# Delimeters +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_LBRACKET = r'\[' +t_RBRACKET = r'\]' +t_LBRACE = r'\{' +t_RBRACE = r'\}' +t_COMMA = r',' +t_PERIOD = r'\.' +t_SEMI = r';' +t_COLON = r':' +t_ELLIPSIS = r'\.\.\.' + +# Identifiers +t_ID = r'[A-Za-z_][A-Za-z0-9_]*' + +# Integer literal +t_INTEGER = r'\d+([uU]|[lL]|[uU][lL]|[lL][uU])?' + +# Floating literal +t_FLOAT = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?' + +# String literal +t_STRING = r'\"([^\\\n]|(\\.))*?\"' + +# Character constant 'c' or L'c' +t_CHARACTER = r'(L)?\'([^\\\n]|(\\.))*?\'' + +# Comment (C-Style) +def t_COMMENT(t): + r'/\*(.|\n)*?\*/' + t.lexer.lineno += t.value.count('\n') + return t + +# Comment (C++-Style) +def t_CPPCOMMENT(t): + r'//.*\n' + t.lexer.lineno += 1 + return t + + + + + + diff --git a/plugins/pycparser/ply/lex.py b/plugins/pycparser/ply/lex.py new file mode 100644 index 0000000..37a9993 --- /dev/null +++ b/plugins/pycparser/ply/lex.py @@ -0,0 +1,1021 @@ +# ----------------------------------------------------------------------------- +# ply: lex.py +# +# Copyright (C) 2001-2009, +# David M. Beazley (Dabeaz LLC) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the David Beazley or Dabeaz LLC may be used to +# endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ----------------------------------------------------------------------------- + +__version__ = "3.3" +__tabversion__ = "3.2" # Version of table file used + +import re, sys, types, copy, os + +# This tuple contains known string types +try: + # Python 2.6 + StringTypes = (types.StringType, types.UnicodeType) +except AttributeError: + # Python 3.0 + StringTypes = (str, bytes) + +# Extract the code attribute of a function. Different implementations +# are for Python 2/3 compatibility. + +if sys.version_info[0] < 3: + def func_code(f): + return f.func_code +else: + def func_code(f): + return f.__code__ + +# This regular expression is used to match valid token names +_is_identifier = re.compile(r'^[a-zA-Z0-9_]+$') + +# Exception thrown when invalid token encountered and no default error +# handler is defined. + +class LexError(Exception): + def __init__(self,message,s): + self.args = (message,) + self.text = s + +# Token class. This class is used to represent the tokens produced. +class LexToken(object): + def __str__(self): + return "LexToken(%s,%r,%d,%d)" % (self.type,self.value,self.lineno,self.lexpos) + def __repr__(self): + return str(self) + +# This object is a stand-in for a logging object created by the +# logging module. + +class PlyLogger(object): + def __init__(self,f): + self.f = f + def critical(self,msg,*args,**kwargs): + self.f.write((msg % args) + "\n") + + def warning(self,msg,*args,**kwargs): + self.f.write("WARNING: "+ (msg % args) + "\n") + + def error(self,msg,*args,**kwargs): + self.f.write("ERROR: " + (msg % args) + "\n") + + info = critical + debug = critical + +# Null logger is used when no output is generated. Does nothing. +class NullLogger(object): + def __getattribute__(self,name): + return self + def __call__(self,*args,**kwargs): + return self + +# ----------------------------------------------------------------------------- +# === Lexing Engine === +# +# The following Lexer class implements the lexer runtime. There are only +# a few public methods and attributes: +# +# input() - Store a new string in the lexer +# token() - Get the next token +# clone() - Clone the lexer +# +# lineno - Current line number +# lexpos - Current position in the input string +# ----------------------------------------------------------------------------- + +class Lexer: + def __init__(self): + self.lexre = None # Master regular expression. This is a list of + # tuples (re,findex) where re is a compiled + # regular expression and findex is a list + # mapping regex group numbers to rules + self.lexretext = None # Current regular expression strings + self.lexstatere = {} # Dictionary mapping lexer states to master regexs + self.lexstateretext = {} # Dictionary mapping lexer states to regex strings + self.lexstaterenames = {} # Dictionary mapping lexer states to symbol names + self.lexstate = "INITIAL" # Current lexer state + self.lexstatestack = [] # Stack of lexer states + self.lexstateinfo = None # State information + self.lexstateignore = {} # Dictionary of ignored characters for each state + self.lexstateerrorf = {} # Dictionary of error functions for each state + self.lexreflags = 0 # Optional re compile flags + self.lexdata = None # Actual input data (as a string) + self.lexpos = 0 # Current position in input text + self.lexlen = 0 # Length of the input text + self.lexerrorf = None # Error rule (if any) + self.lextokens = None # List of valid tokens + self.lexignore = "" # Ignored characters + self.lexliterals = "" # Literal characters that can be passed through + self.lexmodule = None # Module + self.lineno = 1 # Current line number + self.lexoptimize = 0 # Optimized mode + + def clone(self,object=None): + c = copy.copy(self) + + # If the object parameter has been supplied, it means we are attaching the + # lexer to a new object. In this case, we have to rebind all methods in + # the lexstatere and lexstateerrorf tables. + + if object: + newtab = { } + for key, ritem in self.lexstatere.items(): + newre = [] + for cre, findex in ritem: + newfindex = [] + for f in findex: + if not f or not f[0]: + newfindex.append(f) + continue + newfindex.append((getattr(object,f[0].__name__),f[1])) + newre.append((cre,newfindex)) + newtab[key] = newre + c.lexstatere = newtab + c.lexstateerrorf = { } + for key, ef in self.lexstateerrorf.items(): + c.lexstateerrorf[key] = getattr(object,ef.__name__) + c.lexmodule = object + return c + + # ------------------------------------------------------------ + # writetab() - Write lexer information to a table file + # ------------------------------------------------------------ + def writetab(self,tabfile,outputdir=""): + return + + # ------------------------------------------------------------ + # readtab() - Read lexer information from a tab file + # ------------------------------------------------------------ + def readtab(self,tabfile,fdict): + if isinstance(tabfile,types.ModuleType): + lextab = tabfile + else: + if sys.version_info[0] < 3: + exec("import %s as lextab" % tabfile) + else: + env = { } + exec("import %s as lextab" % tabfile, env,env) + lextab = env['lextab'] + + if getattr(lextab,"_tabversion","0.0") != __version__: + raise ImportError("Inconsistent PLY version") + + self.lextokens = lextab._lextokens + self.lexreflags = lextab._lexreflags + self.lexliterals = lextab._lexliterals + self.lexstateinfo = lextab._lexstateinfo + self.lexstateignore = lextab._lexstateignore + self.lexstatere = { } + self.lexstateretext = { } + for key,lre in lextab._lexstatere.items(): + titem = [] + txtitem = [] + for i in range(len(lre)): + titem.append((re.compile(lre[i][0],lextab._lexreflags | re.VERBOSE),_names_to_funcs(lre[i][1],fdict))) + txtitem.append(lre[i][0]) + self.lexstatere[key] = titem + self.lexstateretext[key] = txtitem + self.lexstateerrorf = { } + for key,ef in lextab._lexstateerrorf.items(): + self.lexstateerrorf[key] = fdict[ef] + self.begin('INITIAL') + + # ------------------------------------------------------------ + # input() - Push a new string into the lexer + # ------------------------------------------------------------ + def input(self,s): + # Pull off the first character to see if s looks like a string + c = s[:1] + if not isinstance(c,StringTypes): + raise ValueError("Expected a string") + self.lexdata = s + self.lexpos = 0 + self.lexlen = len(s) + + # ------------------------------------------------------------ + # begin() - Changes the lexing state + # ------------------------------------------------------------ + def begin(self,state): + if not state in self.lexstatere: + raise ValueError("Undefined state") + self.lexre = self.lexstatere[state] + self.lexretext = self.lexstateretext[state] + self.lexignore = self.lexstateignore.get(state,"") + self.lexerrorf = self.lexstateerrorf.get(state,None) + self.lexstate = state + + # ------------------------------------------------------------ + # push_state() - Changes the lexing state and saves old on stack + # ------------------------------------------------------------ + def push_state(self,state): + self.lexstatestack.append(self.lexstate) + self.begin(state) + + # ------------------------------------------------------------ + # pop_state() - Restores the previous state + # ------------------------------------------------------------ + def pop_state(self): + self.begin(self.lexstatestack.pop()) + + # ------------------------------------------------------------ + # current_state() - Returns the current lexing state + # ------------------------------------------------------------ + def current_state(self): + return self.lexstate + + # ------------------------------------------------------------ + # skip() - Skip ahead n characters + # ------------------------------------------------------------ + def skip(self,n): + self.lexpos += n + + # ------------------------------------------------------------ + # opttoken() - Return the next token from the Lexer + # + # Note: This function has been carefully implemented to be as fast + # as possible. Don't make changes unless you really know what + # you are doing + # ------------------------------------------------------------ + def token(self): + # Make local copies of frequently referenced attributes + lexpos = self.lexpos + lexlen = self.lexlen + lexignore = self.lexignore + lexdata = self.lexdata + + while lexpos < lexlen: + # This code provides some short-circuit code for whitespace, tabs, and other ignored characters + if lexdata[lexpos] in lexignore: + lexpos += 1 + continue + + # Look for a regular expression match + for lexre,lexindexfunc in self.lexre: + m = lexre.match(lexdata,lexpos) + if not m: continue + + # Create a token for return + tok = LexToken() + tok.value = m.group() + tok.lineno = self.lineno + tok.lexpos = lexpos + + i = m.lastindex + func,tok.type = lexindexfunc[i] + + if not func: + # If no token type was set, it's an ignored token + if tok.type: + self.lexpos = m.end() + return tok + else: + lexpos = m.end() + break + + lexpos = m.end() + + # If token is processed by a function, call it + + tok.lexer = self # Set additional attributes useful in token rules + self.lexmatch = m + self.lexpos = lexpos + + newtok = func(tok) + + # Every function must return a token, if nothing, we just move to next token + if not newtok: + lexpos = self.lexpos # This is here in case user has updated lexpos. + lexignore = self.lexignore # This is here in case there was a state change + break + + # Verify type of the token. If not in the token map, raise an error + if not self.lexoptimize: + if not newtok.type in self.lextokens: + raise LexError("%s:%d: Rule '%s' returned an unknown token type '%s'" % ( + func_code(func).co_filename, func_code(func).co_firstlineno, + func.__name__, newtok.type),lexdata[lexpos:]) + + return newtok + else: + # No match, see if in literals + if lexdata[lexpos] in self.lexliterals: + tok = LexToken() + tok.value = lexdata[lexpos] + tok.lineno = self.lineno + tok.type = tok.value + tok.lexpos = lexpos + self.lexpos = lexpos + 1 + return tok + + # No match. Call t_error() if defined. + if self.lexerrorf: + tok = LexToken() + tok.value = self.lexdata[lexpos:] + tok.lineno = self.lineno + tok.type = "error" + tok.lexer = self + tok.lexpos = lexpos + self.lexpos = lexpos + newtok = self.lexerrorf(tok) + if lexpos == self.lexpos: + # Error method didn't change text position at all. This is an error. + raise LexError("Scanning error. Illegal character '%s'" % (lexdata[lexpos]), lexdata[lexpos:]) + lexpos = self.lexpos + if not newtok: continue + return newtok + + self.lexpos = lexpos + raise LexError("Illegal character '%s' at index %d" % (lexdata[lexpos],lexpos), lexdata[lexpos:]) + + self.lexpos = lexpos + 1 + if self.lexdata is None: + raise RuntimeError("No input string given with input()") + return None + + # Iterator interface + def __iter__(self): + return self + + def next(self): + t = self.token() + if t is None: + raise StopIteration + return t + + __next__ = next + +# ----------------------------------------------------------------------------- +# ==== Lex Builder === +# +# The functions and classes below are used to collect lexing information +# and build a Lexer object from it. +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# get_caller_module_dict() +# +# This function returns a dictionary containing all of the symbols defined within +# a caller further down the call stack. This is used to get the environment +# associated with the yacc() call if none was provided. +# ----------------------------------------------------------------------------- + +def get_caller_module_dict(levels): + try: + raise RuntimeError + except RuntimeError: + e,b,t = sys.exc_info() + f = t.tb_frame + while levels > 0: + f = f.f_back + levels -= 1 + ldict = f.f_globals.copy() + if f.f_globals != f.f_locals: + ldict.update(f.f_locals) + + return ldict + +# ----------------------------------------------------------------------------- +# _funcs_to_names() +# +# Given a list of regular expression functions, this converts it to a list +# suitable for output to a table file +# ----------------------------------------------------------------------------- + +def _funcs_to_names(funclist,namelist): + result = [] + for f,name in zip(funclist,namelist): + if f and f[0]: + result.append((name, f[1])) + else: + result.append(f) + return result + +# ----------------------------------------------------------------------------- +# _names_to_funcs() +# +# Given a list of regular expression function names, this converts it back to +# functions. +# ----------------------------------------------------------------------------- + +def _names_to_funcs(namelist,fdict): + result = [] + for n in namelist: + if n and n[0]: + result.append((fdict[n[0]],n[1])) + else: + result.append(n) + return result + +# ----------------------------------------------------------------------------- +# _form_master_re() +# +# This function takes a list of all of the regex components and attempts to +# form the master regular expression. Given limitations in the Python re +# module, it may be necessary to break the master regex into separate expressions. +# ----------------------------------------------------------------------------- + +def _form_master_re(relist,reflags,ldict,toknames): + if not relist: return [] + regex = "|".join(relist) + try: + lexre = re.compile(regex,re.VERBOSE | reflags) + + # Build the index to function map for the matching engine + lexindexfunc = [ None ] * (max(lexre.groupindex.values())+1) + lexindexnames = lexindexfunc[:] + + for f,i in lexre.groupindex.items(): + handle = ldict.get(f,None) + if type(handle) in (types.FunctionType, types.MethodType): + lexindexfunc[i] = (handle,toknames[f]) + lexindexnames[i] = f + elif handle is not None: + lexindexnames[i] = f + if f.find("ignore_") > 0: + lexindexfunc[i] = (None,None) + else: + lexindexfunc[i] = (None, toknames[f]) + + return [(lexre,lexindexfunc)],[regex],[lexindexnames] + except Exception: + m = int(len(relist)/2) + if m == 0: m = 1 + llist, lre, lnames = _form_master_re(relist[:m],reflags,ldict,toknames) + rlist, rre, rnames = _form_master_re(relist[m:],reflags,ldict,toknames) + return llist+rlist, lre+rre, lnames+rnames + +# ----------------------------------------------------------------------------- +# def _statetoken(s,names) +# +# Given a declaration name s of the form "t_" and a dictionary whose keys are +# state names, this function returns a tuple (states,tokenname) where states +# is a tuple of state names and tokenname is the name of the token. For example, +# calling this with s = "t_foo_bar_SPAM" might return (('foo','bar'),'SPAM') +# ----------------------------------------------------------------------------- + +def _statetoken(s,names): + nonstate = 1 + parts = s.split("_") + for i in range(1,len(parts)): + if not parts[i] in names and parts[i] != 'ANY': break + if i > 1: + states = tuple(parts[1:i]) + else: + states = ('INITIAL',) + + if 'ANY' in states: + states = tuple(names) + + tokenname = "_".join(parts[i:]) + return (states,tokenname) + + +# ----------------------------------------------------------------------------- +# LexerReflect() +# +# This class represents information needed to build a lexer as extracted from a +# user's input file. +# ----------------------------------------------------------------------------- +class LexerReflect(object): + def __init__(self,ldict,log=None,reflags=0): + self.ldict = ldict + self.error_func = None + self.tokens = [] + self.reflags = reflags + self.stateinfo = { 'INITIAL' : 'inclusive'} + self.files = {} + self.error = 0 + + if log is None: + self.log = PlyLogger(sys.stderr) + else: + self.log = log + + # Get all of the basic information + def get_all(self): + self.get_tokens() + self.get_literals() + self.get_states() + self.get_rules() + + # Validate all of the information + def validate_all(self): + self.validate_tokens() + self.validate_literals() + self.validate_rules() + return self.error + + # Get the tokens map + def get_tokens(self): + tokens = self.ldict.get("tokens",None) + if not tokens: + self.log.error("No token list is defined") + self.error = 1 + return + + if not isinstance(tokens,(list, tuple)): + self.log.error("tokens must be a list or tuple") + self.error = 1 + return + + if not tokens: + self.log.error("tokens is empty") + self.error = 1 + return + + self.tokens = tokens + + # Validate the tokens + def validate_tokens(self): + terminals = {} + for n in self.tokens: + if not _is_identifier.match(n): + self.log.error("Bad token name '%s'",n) + self.error = 1 + if n in terminals: + self.log.warning("Token '%s' multiply defined", n) + terminals[n] = 1 + + # Get the literals specifier + def get_literals(self): + self.literals = self.ldict.get("literals","") + + # Validate literals + def validate_literals(self): + try: + for c in self.literals: + if not isinstance(c,StringTypes) or len(c) > 1: + self.log.error("Invalid literal %s. Must be a single character", repr(c)) + self.error = 1 + continue + + except TypeError: + self.log.error("Invalid literals specification. literals must be a sequence of characters") + self.error = 1 + + def get_states(self): + self.states = self.ldict.get("states",None) + # Build statemap + if self.states: + if not isinstance(self.states,(tuple,list)): + self.log.error("states must be defined as a tuple or list") + self.error = 1 + else: + for s in self.states: + if not isinstance(s,tuple) or len(s) != 2: + self.log.error("Invalid state specifier %s. Must be a tuple (statename,'exclusive|inclusive')",repr(s)) + self.error = 1 + continue + name, statetype = s + if not isinstance(name,StringTypes): + self.log.error("State name %s must be a string", repr(name)) + self.error = 1 + continue + if not (statetype == 'inclusive' or statetype == 'exclusive'): + self.log.error("State type for state %s must be 'inclusive' or 'exclusive'",name) + self.error = 1 + continue + if name in self.stateinfo: + self.log.error("State '%s' already defined",name) + self.error = 1 + continue + self.stateinfo[name] = statetype + + # Get all of the symbols with a t_ prefix and sort them into various + # categories (functions, strings, error functions, and ignore characters) + + def get_rules(self): + tsymbols = [f for f in self.ldict if f[:2] == 't_' ] + + # Now build up a list of functions and a list of strings + + self.toknames = { } # Mapping of symbols to token names + self.funcsym = { } # Symbols defined as functions + self.strsym = { } # Symbols defined as strings + self.ignore = { } # Ignore strings by state + self.errorf = { } # Error functions by state + + for s in self.stateinfo: + self.funcsym[s] = [] + self.strsym[s] = [] + + if len(tsymbols) == 0: + self.log.error("No rules of the form t_rulename are defined") + self.error = 1 + return + + for f in tsymbols: + t = self.ldict[f] + states, tokname = _statetoken(f,self.stateinfo) + self.toknames[f] = tokname + + if hasattr(t,"__call__"): + if tokname == 'error': + for s in states: + self.errorf[s] = t + elif tokname == 'ignore': + line = func_code(t).co_firstlineno + file = func_code(t).co_filename + self.log.error("%s:%d: Rule '%s' must be defined as a string",file,line,t.__name__) + self.error = 1 + else: + for s in states: + self.funcsym[s].append((f,t)) + elif isinstance(t, StringTypes): + if tokname == 'ignore': + for s in states: + self.ignore[s] = t + if "\\" in t: + self.log.warning("%s contains a literal backslash '\\'",f) + + elif tokname == 'error': + self.log.error("Rule '%s' must be defined as a function", f) + self.error = 1 + else: + for s in states: + self.strsym[s].append((f,t)) + else: + self.log.error("%s not defined as a function or string", f) + self.error = 1 + + # Sort the functions by line number + for f in self.funcsym.values(): + if sys.version_info[0] < 3: + f.sort(lambda x,y: cmp(func_code(x[1]).co_firstlineno,func_code(y[1]).co_firstlineno)) + else: + # Python 3.0 + f.sort(key=lambda x: func_code(x[1]).co_firstlineno) + + # Sort the strings by regular expression length + for s in self.strsym.values(): + if sys.version_info[0] < 3: + s.sort(lambda x,y: (len(x[1]) < len(y[1])) - (len(x[1]) > len(y[1]))) + else: + # Python 3.0 + s.sort(key=lambda x: len(x[1]),reverse=True) + + # Validate all of the t_rules collected + def validate_rules(self): + for state in self.stateinfo: + # Validate all rules defined by functions + + + + for fname, f in self.funcsym[state]: + line = func_code(f).co_firstlineno + file = func_code(f).co_filename + self.files[file] = 1 + + tokname = self.toknames[fname] + if isinstance(f, types.MethodType): + reqargs = 2 + else: + reqargs = 1 + nargs = func_code(f).co_argcount + if nargs > reqargs: + self.log.error("%s:%d: Rule '%s' has too many arguments",file,line,f.__name__) + self.error = 1 + continue + + if nargs < reqargs: + self.log.error("%s:%d: Rule '%s' requires an argument", file,line,f.__name__) + self.error = 1 + continue + + if not f.__doc__: + self.log.error("%s:%d: No regular expression defined for rule '%s'",file,line,f.__name__) + self.error = 1 + continue + + try: + c = re.compile("(?P<%s>%s)" % (fname,f.__doc__), re.VERBOSE | self.reflags) + if c.match(""): + self.log.error("%s:%d: Regular expression for rule '%s' matches empty string", file,line,f.__name__) + self.error = 1 + except re.error: + _etype, e, _etrace = sys.exc_info() + self.log.error("%s:%d: Invalid regular expression for rule '%s'. %s", file,line,f.__name__,e) + if '#' in f.__doc__: + self.log.error("%s:%d. Make sure '#' in rule '%s' is escaped with '\\#'",file,line, f.__name__) + self.error = 1 + + # Validate all rules defined by strings + for name,r in self.strsym[state]: + tokname = self.toknames[name] + if tokname == 'error': + self.log.error("Rule '%s' must be defined as a function", name) + self.error = 1 + continue + + if not tokname in self.tokens and tokname.find("ignore_") < 0: + self.log.error("Rule '%s' defined for an unspecified token %s",name,tokname) + self.error = 1 + continue + + try: + c = re.compile("(?P<%s>%s)" % (name,r),re.VERBOSE | self.reflags) + if (c.match("")): + self.log.error("Regular expression for rule '%s' matches empty string",name) + self.error = 1 + except re.error: + _etype, e, _etrace = sys.exc_info() + self.log.error("Invalid regular expression for rule '%s'. %s",name,e) + if '#' in r: + self.log.error("Make sure '#' in rule '%s' is escaped with '\\#'",name) + self.error = 1 + + if not self.funcsym[state] and not self.strsym[state]: + self.log.error("No rules defined for state '%s'",state) + self.error = 1 + + # Validate the error function + efunc = self.errorf.get(state,None) + if efunc: + f = efunc + line = func_code(f).co_firstlineno + file = func_code(f).co_filename + self.files[file] = 1 + + if isinstance(f, types.MethodType): + reqargs = 2 + else: + reqargs = 1 + nargs = func_code(f).co_argcount + if nargs > reqargs: + self.log.error("%s:%d: Rule '%s' has too many arguments",file,line,f.__name__) + self.error = 1 + + if nargs < reqargs: + self.log.error("%s:%d: Rule '%s' requires an argument", file,line,f.__name__) + self.error = 1 + + for f in self.files: + self.validate_file(f) + + + # ----------------------------------------------------------------------------- + # validate_file() + # + # This checks to see if there are duplicated t_rulename() functions or strings + # in the parser input file. This is done using a simple regular expression + # match on each line in the given file. + # ----------------------------------------------------------------------------- + + def validate_file(self,filename): + import os.path + base,ext = os.path.splitext(filename) + if ext != '.py': return # No idea what the file is. Return OK + + try: + f = open(filename) + lines = f.readlines() + f.close() + except IOError: + return # Couldn't find the file. Don't worry about it + + fre = re.compile(r'\s*def\s+(t_[a-zA-Z_0-9]*)\(') + sre = re.compile(r'\s*(t_[a-zA-Z_0-9]*)\s*=') + + counthash = { } + linen = 1 + for l in lines: + m = fre.match(l) + if not m: + m = sre.match(l) + if m: + name = m.group(1) + prev = counthash.get(name) + if not prev: + counthash[name] = linen + else: + self.log.error("%s:%d: Rule %s redefined. Previously defined on line %d",filename,linen,name,prev) + self.error = 1 + linen += 1 + +# ----------------------------------------------------------------------------- +# lex(module) +# +# Build all of the regular expression rules from definitions in the supplied module +# ----------------------------------------------------------------------------- +def lex(module=None,object=None,debug=0,optimize=0,lextab="lextab",reflags=0,nowarn=0,outputdir="", debuglog=None, errorlog=None): + global lexer + ldict = None + stateinfo = { 'INITIAL' : 'inclusive'} + lexobj = Lexer() + lexobj.lexoptimize = optimize + global token,input + + if errorlog is None: + errorlog = PlyLogger(sys.stderr) + + if debug: + if debuglog is None: + debuglog = PlyLogger(sys.stderr) + + # Get the module dictionary used for the lexer + if object: module = object + + if module: + _items = [(k,getattr(module,k)) for k in dir(module)] + ldict = dict(_items) + else: + ldict = get_caller_module_dict(2) + + # Collect parser information from the dictionary + linfo = LexerReflect(ldict,log=errorlog,reflags=reflags) + linfo.get_all() + if not optimize: + if linfo.validate_all(): + raise SyntaxError("Can't build lexer") + + if optimize and lextab: + try: + lexobj.readtab(lextab,ldict) + token = lexobj.token + input = lexobj.input + lexer = lexobj + return lexobj + + except ImportError: + pass + + # Dump some basic debugging information + if debug: + debuglog.info("lex: tokens = %r", linfo.tokens) + debuglog.info("lex: literals = %r", linfo.literals) + debuglog.info("lex: states = %r", linfo.stateinfo) + + # Build a dictionary of valid token names + lexobj.lextokens = { } + for n in linfo.tokens: + lexobj.lextokens[n] = 1 + + # Get literals specification + if isinstance(linfo.literals,(list,tuple)): + lexobj.lexliterals = type(linfo.literals[0])().join(linfo.literals) + else: + lexobj.lexliterals = linfo.literals + + # Get the stateinfo dictionary + stateinfo = linfo.stateinfo + + regexs = { } + # Build the master regular expressions + for state in stateinfo: + regex_list = [] + + # Add rules defined by functions first + for fname, f in linfo.funcsym[state]: + line = func_code(f).co_firstlineno + file = func_code(f).co_filename + regex_list.append("(?P<%s>%s)" % (fname,f.__doc__)) + if debug: + debuglog.info("lex: Adding rule %s -> '%s' (state '%s')",fname,f.__doc__, state) + + # Now add all of the simple rules + for name,r in linfo.strsym[state]: + regex_list.append("(?P<%s>%s)" % (name,r)) + if debug: + debuglog.info("lex: Adding rule %s -> '%s' (state '%s')",name,r, state) + + regexs[state] = regex_list + + # Build the master regular expressions + + if debug: + debuglog.info("lex: ==== MASTER REGEXS FOLLOW ====") + + for state in regexs: + lexre, re_text, re_names = _form_master_re(regexs[state],reflags,ldict,linfo.toknames) + lexobj.lexstatere[state] = lexre + lexobj.lexstateretext[state] = re_text + lexobj.lexstaterenames[state] = re_names + if debug: + for i in range(len(re_text)): + debuglog.info("lex: state '%s' : regex[%d] = '%s'",state, i, re_text[i]) + + # For inclusive states, we need to add the regular expressions from the INITIAL state + for state,stype in stateinfo.items(): + if state != "INITIAL" and stype == 'inclusive': + lexobj.lexstatere[state].extend(lexobj.lexstatere['INITIAL']) + lexobj.lexstateretext[state].extend(lexobj.lexstateretext['INITIAL']) + lexobj.lexstaterenames[state].extend(lexobj.lexstaterenames['INITIAL']) + + lexobj.lexstateinfo = stateinfo + lexobj.lexre = lexobj.lexstatere["INITIAL"] + lexobj.lexretext = lexobj.lexstateretext["INITIAL"] + lexobj.lexreflags = reflags + + # Set up ignore variables + lexobj.lexstateignore = linfo.ignore + lexobj.lexignore = lexobj.lexstateignore.get("INITIAL","") + + # Set up error functions + lexobj.lexstateerrorf = linfo.errorf + lexobj.lexerrorf = linfo.errorf.get("INITIAL",None) + if not lexobj.lexerrorf: + errorlog.warning("No t_error rule is defined") + + # Check state information for ignore and error rules + for s,stype in stateinfo.items(): + if stype == 'exclusive': + if not s in linfo.errorf: + errorlog.warning("No error rule is defined for exclusive state '%s'", s) + if not s in linfo.ignore and lexobj.lexignore: + errorlog.warning("No ignore rule is defined for exclusive state '%s'", s) + elif stype == 'inclusive': + if not s in linfo.errorf: + linfo.errorf[s] = linfo.errorf.get("INITIAL",None) + if not s in linfo.ignore: + linfo.ignore[s] = linfo.ignore.get("INITIAL","") + + # Create global versions of the token() and input() functions + token = lexobj.token + input = lexobj.input + lexer = lexobj + + # If in optimize mode, we write the lextab + if lextab and optimize: + lexobj.writetab(lextab,outputdir) + + return lexobj + +# ----------------------------------------------------------------------------- +# runmain() +# +# This runs the lexer as a main program +# ----------------------------------------------------------------------------- + +def runmain(lexer=None,data=None): + if not data: + try: + filename = sys.argv[1] + f = open(filename) + data = f.read() + f.close() + except IndexError: + sys.stdout.write("Reading from standard input (type EOF to end):\n") + data = sys.stdin.read() + + if lexer: + _input = lexer.input + else: + _input = input + _input(data) + if lexer: + _token = lexer.token + else: + _token = token + + while 1: + tok = _token() + if not tok: break + sys.stdout.write("(%s,%r,%d,%d)\n" % (tok.type, tok.value, tok.lineno,tok.lexpos)) + +# ----------------------------------------------------------------------------- +# @TOKEN(regex) +# +# This decorator function can be used to set the regex expression on a function +# when its docstring might need to be set in an alternative way +# ----------------------------------------------------------------------------- + +def TOKEN(r): + def set_doc(f): + if hasattr(r,"__call__"): + f.__doc__ = r.__doc__ + else: + f.__doc__ = r + return f + return set_doc + +# Alternative spelling of the TOKEN decorator +Token = TOKEN + diff --git a/plugins/pycparser/ply/yacc.py b/plugins/pycparser/ply/yacc.py new file mode 100644 index 0000000..818de6d --- /dev/null +++ b/plugins/pycparser/ply/yacc.py @@ -0,0 +1,3165 @@ +# ----------------------------------------------------------------------------- +# ply: yacc.py +# +# Copyright (C) 2001-2009, +# David M. Beazley (Dabeaz LLC) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the David Beazley or Dabeaz LLC may be used to +# endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ----------------------------------------------------------------------------- +# +# This implements an LR parser that is constructed from grammar rules defined +# as Python functions. The grammer is specified by supplying the BNF inside +# Python documentation strings. The inspiration for this technique was borrowed +# from John Aycock's Spark parsing system. PLY might be viewed as cross between +# Spark and the GNU bison utility. +# +# The current implementation is only somewhat object-oriented. The +# LR parser itself is defined in terms of an object (which allows multiple +# parsers to co-exist). However, most of the variables used during table +# construction are defined in terms of global variables. Users shouldn't +# notice unless they are trying to define multiple parsers at the same +# time using threads (in which case they should have their head examined). +# +# This implementation supports both SLR and LALR(1) parsing. LALR(1) +# support was originally implemented by Elias Ioup (ezioup@alumni.uchicago.edu), +# using the algorithm found in Aho, Sethi, and Ullman "Compilers: Principles, +# Techniques, and Tools" (The Dragon Book). LALR(1) has since been replaced +# by the more efficient DeRemer and Pennello algorithm. +# +# :::::::: WARNING ::::::: +# +# Construction of LR parsing tables is fairly complicated and expensive. +# To make this module run fast, a *LOT* of work has been put into +# optimization---often at the expensive of readability and what might +# consider to be good Python "coding style." Modify the code at your +# own risk! +# ---------------------------------------------------------------------------- + +__version__ = "3.3" +__tabversion__ = "3.2" # Table version + +#----------------------------------------------------------------------------- +# === User configurable parameters === +# +# Change these to modify the default behavior of yacc (if you wish) +#----------------------------------------------------------------------------- + +yaccdebug = 1 # Debugging mode. If set, yacc generates a + # a 'parser.out' file in the current directory + +debug_file = 'parser.out' # Default name of the debugging file +tab_module = 'parsetab' # Default name of the table module +default_lr = 'LALR' # Default LR table generation method + +error_count = 3 # Number of symbols that must be shifted to leave recovery mode + +yaccdevel = 0 # Set to True if developing yacc. This turns off optimized + # implementations of certain functions. + +resultlimit = 40 # Size limit of results when running in debug mode. + +pickle_protocol = 0 # Protocol to use when writing pickle files + +import re, types, sys, os.path + +# Compatibility function for python 2.6/3.0 +if sys.version_info[0] < 3: + def func_code(f): + return f.func_code +else: + def func_code(f): + return f.__code__ + +# Compatibility +try: + MAXINT = sys.maxint +except AttributeError: + MAXINT = sys.maxsize + +# Python 2.x/3.0 compatibility. +def load_ply_lex(): + if sys.version_info[0] < 3: + import lex + else: + import ply.lex as lex + return lex + +# This object is a stand-in for a logging object created by the +# logging module. PLY will use this by default to create things +# such as the parser.out file. If a user wants more detailed +# information, they can create their own logging object and pass +# it into PLY. + +class PlyLogger(object): + def __init__(self,f): + self.f = f + def debug(self,msg,*args,**kwargs): + self.f.write((msg % args) + "\n") + info = debug + + def warning(self,msg,*args,**kwargs): + self.f.write("WARNING: "+ (msg % args) + "\n") + + def error(self,msg,*args,**kwargs): + self.f.write("ERROR: " + (msg % args) + "\n") + + critical = debug + +# Null logger is used when no output is generated. Does nothing. +class NullLogger(object): + def __getattribute__(self,name): + return self + def __call__(self,*args,**kwargs): + return self + +# Exception raised for yacc-related errors +class YaccError(Exception): pass + +# Format the result message that the parser produces when running in debug mode. +def format_result(r): + repr_str = repr(r) + if '\n' in repr_str: repr_str = repr(repr_str) + if len(repr_str) > resultlimit: + repr_str = repr_str[:resultlimit]+" ..." + result = "<%s @ 0x%x> (%s)" % (type(r).__name__,id(r),repr_str) + return result + + +# Format stack entries when the parser is running in debug mode +def format_stack_entry(r): + repr_str = repr(r) + if '\n' in repr_str: repr_str = repr(repr_str) + if len(repr_str) < 16: + return repr_str + else: + return "<%s @ 0x%x>" % (type(r).__name__,id(r)) + +#----------------------------------------------------------------------------- +# === LR Parsing Engine === +# +# The following classes are used for the LR parser itself. These are not +# used during table construction and are independent of the actual LR +# table generation algorithm +#----------------------------------------------------------------------------- + +# This class is used to hold non-terminal grammar symbols during parsing. +# It normally has the following attributes set: +# .type = Grammar symbol type +# .value = Symbol value +# .lineno = Starting line number +# .endlineno = Ending line number (optional, set automatically) +# .lexpos = Starting lex position +# .endlexpos = Ending lex position (optional, set automatically) + +class YaccSymbol: + def __str__(self): return self.type + def __repr__(self): return str(self) + +# This class is a wrapper around the objects actually passed to each +# grammar rule. Index lookup and assignment actually assign the +# .value attribute of the underlying YaccSymbol object. +# The lineno() method returns the line number of a given +# item (or 0 if not defined). The linespan() method returns +# a tuple of (startline,endline) representing the range of lines +# for a symbol. The lexspan() method returns a tuple (lexpos,endlexpos) +# representing the range of positional information for a symbol. + +class YaccProduction: + def __init__(self,s,stack=None): + self.slice = s + self.stack = stack + self.lexer = None + self.parser= None + def __getitem__(self,n): + if n >= 0: return self.slice[n].value + else: return self.stack[n].value + + def __setitem__(self,n,v): + self.slice[n].value = v + + def __getslice__(self,i,j): + return [s.value for s in self.slice[i:j]] + + def __len__(self): + return len(self.slice) + + def lineno(self,n): + return getattr(self.slice[n],"lineno",0) + + def set_lineno(self,n,lineno): + self.slice[n].lineno = lineno + + def linespan(self,n): + startline = getattr(self.slice[n],"lineno",0) + endline = getattr(self.slice[n],"endlineno",startline) + return startline,endline + + def lexpos(self,n): + return getattr(self.slice[n],"lexpos",0) + + def lexspan(self,n): + startpos = getattr(self.slice[n],"lexpos",0) + endpos = getattr(self.slice[n],"endlexpos",startpos) + return startpos,endpos + + def error(self): + raise SyntaxError + + +# ----------------------------------------------------------------------------- +# == LRParser == +# +# The LR Parsing engine. +# ----------------------------------------------------------------------------- + +class LRParser: + def __init__(self,lrtab,errorf): + self.productions = lrtab.lr_productions + self.action = lrtab.lr_action + self.goto = lrtab.lr_goto + self.errorfunc = errorf + + def errok(self): + self.errorok = 1 + + def restart(self): + del self.statestack[:] + del self.symstack[:] + sym = YaccSymbol() + sym.type = '$end' + self.symstack.append(sym) + self.statestack.append(0) + + def parse(self,input=None,lexer=None,debug=0,tracking=0,tokenfunc=None): + if debug or yaccdevel: + if isinstance(debug,int): + debug = PlyLogger(sys.stderr) + return self.parsedebug(input,lexer,debug,tracking,tokenfunc) + elif tracking: + return self.parseopt(input,lexer,debug,tracking,tokenfunc) + else: + return self.parseopt_notrack(input,lexer,debug,tracking,tokenfunc) + + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # parsedebug(). + # + # This is the debugging enabled version of parse(). All changes made to the + # parsing engine should be made here. For the non-debugging version, + # copy this code to a method parseopt() and delete all of the sections + # enclosed in: + # + # #--! DEBUG + # statements + # #--! DEBUG + # + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + def parsedebug(self,input=None,lexer=None,debug=None,tracking=0,tokenfunc=None): + lookahead = None # Current lookahead symbol + lookaheadstack = [ ] # Stack of lookahead symbols + actions = self.action # Local reference to action table (to avoid lookup on self.) + goto = self.goto # Local reference to goto table (to avoid lookup on self.) + prod = self.productions # Local reference to production list (to avoid lookup on self.) + pslice = YaccProduction(None) # Production object passed to grammar rules + errorcount = 0 # Used during error recovery + + # --! DEBUG + debug.info("PLY: PARSE DEBUG START") + # --! DEBUG + + # If no lexer was given, we will try to use the lex module + if not lexer: + lex = load_ply_lex() + lexer = lex.lexer + + # Set up the lexer and parser objects on pslice + pslice.lexer = lexer + pslice.parser = self + + # If input was supplied, pass to lexer + if input is not None: + lexer.input(input) + + if tokenfunc is None: + # Tokenize function + get_token = lexer.token + else: + get_token = tokenfunc + + # Set up the state and symbol stacks + + statestack = [ ] # Stack of parsing states + self.statestack = statestack + symstack = [ ] # Stack of grammar symbols + self.symstack = symstack + + pslice.stack = symstack # Put in the production + errtoken = None # Err token + + # The start state is assumed to be (0,$end) + + statestack.append(0) + sym = YaccSymbol() + sym.type = "$end" + symstack.append(sym) + state = 0 + while 1: + # Get the next symbol on the input. If a lookahead symbol + # is already set, we just use that. Otherwise, we'll pull + # the next token off of the lookaheadstack or from the lexer + + # --! DEBUG + debug.debug('') + debug.debug('State : %s', state) + # --! DEBUG + + if not lookahead: + if not lookaheadstack: + lookahead = get_token() # Get the next token + else: + lookahead = lookaheadstack.pop() + if not lookahead: + lookahead = YaccSymbol() + lookahead.type = "$end" + + # --! DEBUG + debug.debug('Stack : %s', + ("%s . %s" % (" ".join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip()) + # --! DEBUG + + # Check the action table + ltype = lookahead.type + t = actions[state].get(ltype) + + if t is not None: + if t > 0: + # shift a symbol on the stack + statestack.append(t) + state = t + + # --! DEBUG + debug.debug("Action : Shift and goto state %s", t) + # --! DEBUG + + symstack.append(lookahead) + lookahead = None + + # Decrease error count on successful shift + if errorcount: errorcount -=1 + continue + + if t < 0: + # reduce a symbol on the stack, emit a production + p = prod[-t] + pname = p.name + plen = p.len + + # Get production function + sym = YaccSymbol() + sym.type = pname # Production name + sym.value = None + + # --! DEBUG + if plen: + debug.info("Action : Reduce rule [%s] with %s and goto state %d", p.str, "["+",".join([format_stack_entry(_v.value) for _v in symstack[-plen:]])+"]",-t) + else: + debug.info("Action : Reduce rule [%s] with %s and goto state %d", p.str, [],-t) + + # --! DEBUG + + if plen: + targ = symstack[-plen-1:] + targ[0] = sym + + # --! TRACKING + if tracking: + t1 = targ[1] + sym.lineno = t1.lineno + sym.lexpos = t1.lexpos + t1 = targ[-1] + sym.endlineno = getattr(t1,"endlineno",t1.lineno) + sym.endlexpos = getattr(t1,"endlexpos",t1.lexpos) + + # --! TRACKING + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # The code enclosed in this section is duplicated + # below as a performance optimization. Make sure + # changes get made in both locations. + + pslice.slice = targ + + try: + # Call the grammar rule with our special slice object + del symstack[-plen:] + del statestack[-plen:] + p.callable(pslice) + # --! DEBUG + debug.info("Result : %s", format_result(pslice[0])) + # --! DEBUG + symstack.append(sym) + state = goto[statestack[-1]][pname] + statestack.append(state) + except SyntaxError: + # If an error was set. Enter error recovery state + lookaheadstack.append(lookahead) + symstack.pop() + statestack.pop() + state = statestack[-1] + sym.type = 'error' + lookahead = sym + errorcount = error_count + self.errorok = 0 + continue + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + else: + + # --! TRACKING + if tracking: + sym.lineno = lexer.lineno + sym.lexpos = lexer.lexpos + # --! TRACKING + + targ = [ sym ] + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # The code enclosed in this section is duplicated + # above as a performance optimization. Make sure + # changes get made in both locations. + + pslice.slice = targ + + try: + # Call the grammar rule with our special slice object + p.callable(pslice) + # --! DEBUG + debug.info("Result : %s", format_result(pslice[0])) + # --! DEBUG + symstack.append(sym) + state = goto[statestack[-1]][pname] + statestack.append(state) + except SyntaxError: + # If an error was set. Enter error recovery state + lookaheadstack.append(lookahead) + symstack.pop() + statestack.pop() + state = statestack[-1] + sym.type = 'error' + lookahead = sym + errorcount = error_count + self.errorok = 0 + continue + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + if t == 0: + n = symstack[-1] + result = getattr(n,"value",None) + # --! DEBUG + debug.info("Done : Returning %s", format_result(result)) + debug.info("PLY: PARSE DEBUG END") + # --! DEBUG + return result + + if t == None: + + # --! DEBUG + debug.error('Error : %s', + ("%s . %s" % (" ".join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip()) + # --! DEBUG + + # We have some kind of parsing error here. To handle + # this, we are going to push the current token onto + # the tokenstack and replace it with an 'error' token. + # If there are any synchronization rules, they may + # catch it. + # + # In addition to pushing the error token, we call call + # the user defined p_error() function if this is the + # first syntax error. This function is only called if + # errorcount == 0. + if errorcount == 0 or self.errorok: + errorcount = error_count + self.errorok = 0 + errtoken = lookahead + if errtoken.type == "$end": + errtoken = None # End of file! + if self.errorfunc: + global errok,token,restart + errok = self.errok # Set some special functions available in error recovery + token = get_token + restart = self.restart + if errtoken and not hasattr(errtoken,'lexer'): + errtoken.lexer = lexer + tok = self.errorfunc(errtoken) + del errok, token, restart # Delete special functions + + if self.errorok: + # User must have done some kind of panic + # mode recovery on their own. The + # returned token is the next lookahead + lookahead = tok + errtoken = None + continue + else: + if errtoken: + if hasattr(errtoken,"lineno"): lineno = lookahead.lineno + else: lineno = 0 + if lineno: + sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type)) + else: + sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type) + else: + sys.stderr.write("yacc: Parse error in input. EOF\n") + return + + else: + errorcount = error_count + + # case 1: the statestack only has 1 entry on it. If we're in this state, the + # entire parse has been rolled back and we're completely hosed. The token is + # discarded and we just keep going. + + if len(statestack) <= 1 and lookahead.type != "$end": + lookahead = None + errtoken = None + state = 0 + # Nuke the pushback stack + del lookaheadstack[:] + continue + + # case 2: the statestack has a couple of entries on it, but we're + # at the end of the file. nuke the top entry and generate an error token + + # Start nuking entries on the stack + if lookahead.type == "$end": + # Whoa. We're really hosed here. Bail out + return + + if lookahead.type != 'error': + sym = symstack[-1] + if sym.type == 'error': + # Hmmm. Error is on top of stack, we'll just nuke input + # symbol and continue + lookahead = None + continue + t = YaccSymbol() + t.type = 'error' + if hasattr(lookahead,"lineno"): + t.lineno = lookahead.lineno + t.value = lookahead + lookaheadstack.append(lookahead) + lookahead = t + else: + symstack.pop() + statestack.pop() + state = statestack[-1] # Potential bug fix + + continue + + # Call an error function here + raise RuntimeError("yacc: internal parser error!!!\n") + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # parseopt(). + # + # Optimized version of parse() method. DO NOT EDIT THIS CODE DIRECTLY. + # Edit the debug version above, then copy any modifications to the method + # below while removing #--! DEBUG sections. + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + + def parseopt(self,input=None,lexer=None,debug=0,tracking=0,tokenfunc=None): + lookahead = None # Current lookahead symbol + lookaheadstack = [ ] # Stack of lookahead symbols + actions = self.action # Local reference to action table (to avoid lookup on self.) + goto = self.goto # Local reference to goto table (to avoid lookup on self.) + prod = self.productions # Local reference to production list (to avoid lookup on self.) + pslice = YaccProduction(None) # Production object passed to grammar rules + errorcount = 0 # Used during error recovery + + # If no lexer was given, we will try to use the lex module + if not lexer: + lex = load_ply_lex() + lexer = lex.lexer + + # Set up the lexer and parser objects on pslice + pslice.lexer = lexer + pslice.parser = self + + # If input was supplied, pass to lexer + if input is not None: + lexer.input(input) + + if tokenfunc is None: + # Tokenize function + get_token = lexer.token + else: + get_token = tokenfunc + + # Set up the state and symbol stacks + + statestack = [ ] # Stack of parsing states + self.statestack = statestack + symstack = [ ] # Stack of grammar symbols + self.symstack = symstack + + pslice.stack = symstack # Put in the production + errtoken = None # Err token + + # The start state is assumed to be (0,$end) + + statestack.append(0) + sym = YaccSymbol() + sym.type = '$end' + symstack.append(sym) + state = 0 + while 1: + # Get the next symbol on the input. If a lookahead symbol + # is already set, we just use that. Otherwise, we'll pull + # the next token off of the lookaheadstack or from the lexer + + if not lookahead: + if not lookaheadstack: + lookahead = get_token() # Get the next token + else: + lookahead = lookaheadstack.pop() + if not lookahead: + lookahead = YaccSymbol() + lookahead.type = '$end' + + # Check the action table + ltype = lookahead.type + t = actions[state].get(ltype) + + if t is not None: + if t > 0: + # shift a symbol on the stack + statestack.append(t) + state = t + + symstack.append(lookahead) + lookahead = None + + # Decrease error count on successful shift + if errorcount: errorcount -=1 + continue + + if t < 0: + # reduce a symbol on the stack, emit a production + p = prod[-t] + pname = p.name + plen = p.len + + # Get production function + sym = YaccSymbol() + sym.type = pname # Production name + sym.value = None + + if plen: + targ = symstack[-plen-1:] + targ[0] = sym + + # --! TRACKING + if tracking: + t1 = targ[1] + sym.lineno = t1.lineno + sym.lexpos = t1.lexpos + t1 = targ[-1] + sym.endlineno = getattr(t1,"endlineno",t1.lineno) + sym.endlexpos = getattr(t1,"endlexpos",t1.lexpos) + + # --! TRACKING + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # The code enclosed in this section is duplicated + # below as a performance optimization. Make sure + # changes get made in both locations. + + pslice.slice = targ + + try: + # Call the grammar rule with our special slice object + del symstack[-plen:] + del statestack[-plen:] + p.callable(pslice) + symstack.append(sym) + state = goto[statestack[-1]][pname] + statestack.append(state) + except SyntaxError: + # If an error was set. Enter error recovery state + lookaheadstack.append(lookahead) + symstack.pop() + statestack.pop() + state = statestack[-1] + sym.type = 'error' + lookahead = sym + errorcount = error_count + self.errorok = 0 + continue + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + else: + + # --! TRACKING + if tracking: + sym.lineno = lexer.lineno + sym.lexpos = lexer.lexpos + # --! TRACKING + + targ = [ sym ] + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # The code enclosed in this section is duplicated + # above as a performance optimization. Make sure + # changes get made in both locations. + + pslice.slice = targ + + try: + # Call the grammar rule with our special slice object + p.callable(pslice) + symstack.append(sym) + state = goto[statestack[-1]][pname] + statestack.append(state) + except SyntaxError: + # If an error was set. Enter error recovery state + lookaheadstack.append(lookahead) + symstack.pop() + statestack.pop() + state = statestack[-1] + sym.type = 'error' + lookahead = sym + errorcount = error_count + self.errorok = 0 + continue + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + if t == 0: + n = symstack[-1] + return getattr(n,"value",None) + + if t == None: + + # We have some kind of parsing error here. To handle + # this, we are going to push the current token onto + # the tokenstack and replace it with an 'error' token. + # If there are any synchronization rules, they may + # catch it. + # + # In addition to pushing the error token, we call call + # the user defined p_error() function if this is the + # first syntax error. This function is only called if + # errorcount == 0. + if errorcount == 0 or self.errorok: + errorcount = error_count + self.errorok = 0 + errtoken = lookahead + if errtoken.type == '$end': + errtoken = None # End of file! + if self.errorfunc: + global errok,token,restart + errok = self.errok # Set some special functions available in error recovery + token = get_token + restart = self.restart + if errtoken and not hasattr(errtoken,'lexer'): + errtoken.lexer = lexer + tok = self.errorfunc(errtoken) + del errok, token, restart # Delete special functions + + if self.errorok: + # User must have done some kind of panic + # mode recovery on their own. The + # returned token is the next lookahead + lookahead = tok + errtoken = None + continue + else: + if errtoken: + if hasattr(errtoken,"lineno"): lineno = lookahead.lineno + else: lineno = 0 + if lineno: + sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type)) + else: + sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type) + else: + sys.stderr.write("yacc: Parse error in input. EOF\n") + return + + else: + errorcount = error_count + + # case 1: the statestack only has 1 entry on it. If we're in this state, the + # entire parse has been rolled back and we're completely hosed. The token is + # discarded and we just keep going. + + if len(statestack) <= 1 and lookahead.type != '$end': + lookahead = None + errtoken = None + state = 0 + # Nuke the pushback stack + del lookaheadstack[:] + continue + + # case 2: the statestack has a couple of entries on it, but we're + # at the end of the file. nuke the top entry and generate an error token + + # Start nuking entries on the stack + if lookahead.type == '$end': + # Whoa. We're really hosed here. Bail out + return + + if lookahead.type != 'error': + sym = symstack[-1] + if sym.type == 'error': + # Hmmm. Error is on top of stack, we'll just nuke input + # symbol and continue + lookahead = None + continue + t = YaccSymbol() + t.type = 'error' + if hasattr(lookahead,"lineno"): + t.lineno = lookahead.lineno + t.value = lookahead + lookaheadstack.append(lookahead) + lookahead = t + else: + symstack.pop() + statestack.pop() + state = statestack[-1] # Potential bug fix + + continue + + # Call an error function here + raise RuntimeError("yacc: internal parser error!!!\n") + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # parseopt_notrack(). + # + # Optimized version of parseopt() with line number tracking removed. + # DO NOT EDIT THIS CODE DIRECTLY. Copy the optimized version and remove + # code in the #--! TRACKING sections + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + def parseopt_notrack(self,input=None,lexer=None,debug=0,tracking=0,tokenfunc=None): + lookahead = None # Current lookahead symbol + lookaheadstack = [ ] # Stack of lookahead symbols + actions = self.action # Local reference to action table (to avoid lookup on self.) + goto = self.goto # Local reference to goto table (to avoid lookup on self.) + prod = self.productions # Local reference to production list (to avoid lookup on self.) + pslice = YaccProduction(None) # Production object passed to grammar rules + errorcount = 0 # Used during error recovery + + # If no lexer was given, we will try to use the lex module + if not lexer: + lex = load_ply_lex() + lexer = lex.lexer + + # Set up the lexer and parser objects on pslice + pslice.lexer = lexer + pslice.parser = self + + # If input was supplied, pass to lexer + if input is not None: + lexer.input(input) + + if tokenfunc is None: + # Tokenize function + get_token = lexer.token + else: + get_token = tokenfunc + + # Set up the state and symbol stacks + + statestack = [ ] # Stack of parsing states + self.statestack = statestack + symstack = [ ] # Stack of grammar symbols + self.symstack = symstack + + pslice.stack = symstack # Put in the production + errtoken = None # Err token + + # The start state is assumed to be (0,$end) + + statestack.append(0) + sym = YaccSymbol() + sym.type = '$end' + symstack.append(sym) + state = 0 + while 1: + # Get the next symbol on the input. If a lookahead symbol + # is already set, we just use that. Otherwise, we'll pull + # the next token off of the lookaheadstack or from the lexer + + if not lookahead: + if not lookaheadstack: + lookahead = get_token() # Get the next token + else: + lookahead = lookaheadstack.pop() + if not lookahead: + lookahead = YaccSymbol() + lookahead.type = '$end' + + # Check the action table + ltype = lookahead.type + t = actions[state].get(ltype) + + if t is not None: + if t > 0: + # shift a symbol on the stack + statestack.append(t) + state = t + + symstack.append(lookahead) + lookahead = None + + # Decrease error count on successful shift + if errorcount: errorcount -=1 + continue + + if t < 0: + # reduce a symbol on the stack, emit a production + p = prod[-t] + pname = p.name + plen = p.len + + # Get production function + sym = YaccSymbol() + sym.type = pname # Production name + sym.value = None + + if plen: + targ = symstack[-plen-1:] + targ[0] = sym + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # The code enclosed in this section is duplicated + # below as a performance optimization. Make sure + # changes get made in both locations. + + pslice.slice = targ + + try: + # Call the grammar rule with our special slice object + del symstack[-plen:] + del statestack[-plen:] + p.callable(pslice) + symstack.append(sym) + state = goto[statestack[-1]][pname] + statestack.append(state) + except SyntaxError: + # If an error was set. Enter error recovery state + lookaheadstack.append(lookahead) + symstack.pop() + statestack.pop() + state = statestack[-1] + sym.type = 'error' + lookahead = sym + errorcount = error_count + self.errorok = 0 + continue + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + else: + + targ = [ sym ] + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # The code enclosed in this section is duplicated + # above as a performance optimization. Make sure + # changes get made in both locations. + + pslice.slice = targ + + try: + # Call the grammar rule with our special slice object + p.callable(pslice) + symstack.append(sym) + state = goto[statestack[-1]][pname] + statestack.append(state) + except SyntaxError: + # If an error was set. Enter error recovery state + lookaheadstack.append(lookahead) + symstack.pop() + statestack.pop() + state = statestack[-1] + sym.type = 'error' + lookahead = sym + errorcount = error_count + self.errorok = 0 + continue + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + if t == 0: + n = symstack[-1] + return getattr(n,"value",None) + + if t == None: + + # We have some kind of parsing error here. To handle + # this, we are going to push the current token onto + # the tokenstack and replace it with an 'error' token. + # If there are any synchronization rules, they may + # catch it. + # + # In addition to pushing the error token, we call call + # the user defined p_error() function if this is the + # first syntax error. This function is only called if + # errorcount == 0. + if errorcount == 0 or self.errorok: + errorcount = error_count + self.errorok = 0 + errtoken = lookahead + if errtoken.type == '$end': + errtoken = None # End of file! + if self.errorfunc: + global errok,token,restart + errok = self.errok # Set some special functions available in error recovery + token = get_token + restart = self.restart + if errtoken and not hasattr(errtoken,'lexer'): + errtoken.lexer = lexer + tok = self.errorfunc(errtoken) + del errok, token, restart # Delete special functions + + if self.errorok: + # User must have done some kind of panic + # mode recovery on their own. The + # returned token is the next lookahead + lookahead = tok + errtoken = None + continue + else: + if errtoken: + if hasattr(errtoken,"lineno"): lineno = lookahead.lineno + else: lineno = 0 + if lineno: + sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type)) + else: + sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type) + else: + sys.stderr.write("yacc: Parse error in input. EOF\n") + return + + else: + errorcount = error_count + + # case 1: the statestack only has 1 entry on it. If we're in this state, the + # entire parse has been rolled back and we're completely hosed. The token is + # discarded and we just keep going. + + if len(statestack) <= 1 and lookahead.type != '$end': + lookahead = None + errtoken = None + state = 0 + # Nuke the pushback stack + del lookaheadstack[:] + continue + + # case 2: the statestack has a couple of entries on it, but we're + # at the end of the file. nuke the top entry and generate an error token + + # Start nuking entries on the stack + if lookahead.type == '$end': + # Whoa. We're really hosed here. Bail out + return + + if lookahead.type != 'error': + sym = symstack[-1] + if sym.type == 'error': + # Hmmm. Error is on top of stack, we'll just nuke input + # symbol and continue + lookahead = None + continue + t = YaccSymbol() + t.type = 'error' + if hasattr(lookahead,"lineno"): + t.lineno = lookahead.lineno + t.value = lookahead + lookaheadstack.append(lookahead) + lookahead = t + else: + symstack.pop() + statestack.pop() + state = statestack[-1] # Potential bug fix + + continue + + # Call an error function here + raise RuntimeError("yacc: internal parser error!!!\n") + +# ----------------------------------------------------------------------------- +# === Grammar Representation === +# +# The following functions, classes, and variables are used to represent and +# manipulate the rules that make up a grammar. +# ----------------------------------------------------------------------------- + +import re + +# regex matching identifiers +_is_identifier = re.compile(r'^[a-zA-Z0-9_-]+$') + +# ----------------------------------------------------------------------------- +# class Production: +# +# This class stores the raw information about a single production or grammar rule. +# A grammar rule refers to a specification such as this: +# +# expr : expr PLUS term +# +# Here are the basic attributes defined on all productions +# +# name - Name of the production. For example 'expr' +# prod - A list of symbols on the right side ['expr','PLUS','term'] +# prec - Production precedence level +# number - Production number. +# func - Function that executes on reduce +# file - File where production function is defined +# lineno - Line number where production function is defined +# +# The following attributes are defined or optional. +# +# len - Length of the production (number of symbols on right hand side) +# usyms - Set of unique symbols found in the production +# ----------------------------------------------------------------------------- + +class Production(object): + reduced = 0 + def __init__(self,number,name,prod,precedence=('right',0),func=None,file='',line=0): + self.name = name + self.prod = tuple(prod) + self.number = number + self.func = func + self.callable = None + self.file = file + self.line = line + self.prec = precedence + + # Internal settings used during table construction + + self.len = len(self.prod) # Length of the production + + # Create a list of unique production symbols used in the production + self.usyms = [ ] + for s in self.prod: + if s not in self.usyms: + self.usyms.append(s) + + # List of all LR items for the production + self.lr_items = [] + self.lr_next = None + + # Create a string representation + if self.prod: + self.str = "%s -> %s" % (self.name," ".join(self.prod)) + else: + self.str = "%s -> " % self.name + + def __str__(self): + return self.str + + def __repr__(self): + return "Production("+str(self)+")" + + def __len__(self): + return len(self.prod) + + def __nonzero__(self): + return 1 + + def __getitem__(self,index): + return self.prod[index] + + # Return the nth lr_item from the production (or None if at the end) + def lr_item(self,n): + if n > len(self.prod): return None + p = LRItem(self,n) + + # Precompute the list of productions immediately following. Hack. Remove later + try: + p.lr_after = Prodnames[p.prod[n+1]] + except (IndexError,KeyError): + p.lr_after = [] + try: + p.lr_before = p.prod[n-1] + except IndexError: + p.lr_before = None + + return p + + # Bind the production function name to a callable + def bind(self,pdict): + if self.func: + self.callable = pdict[self.func] + +# This class serves as a minimal standin for Production objects when +# reading table data from files. It only contains information +# actually used by the LR parsing engine, plus some additional +# debugging information. +class MiniProduction(object): + def __init__(self,str,name,len,func,file,line): + self.name = name + self.len = len + self.func = func + self.callable = None + self.file = file + self.line = line + self.str = str + def __str__(self): + return self.str + def __repr__(self): + return "MiniProduction(%s)" % self.str + + # Bind the production function name to a callable + def bind(self,pdict): + if self.func: + self.callable = pdict[self.func] + + +# ----------------------------------------------------------------------------- +# class LRItem +# +# This class represents a specific stage of parsing a production rule. For +# example: +# +# expr : expr . PLUS term +# +# In the above, the "." represents the current location of the parse. Here +# basic attributes: +# +# name - Name of the production. For example 'expr' +# prod - A list of symbols on the right side ['expr','.', 'PLUS','term'] +# number - Production number. +# +# lr_next Next LR item. Example, if we are ' expr -> expr . PLUS term' +# then lr_next refers to 'expr -> expr PLUS . term' +# lr_index - LR item index (location of the ".") in the prod list. +# lookaheads - LALR lookahead symbols for this item +# len - Length of the production (number of symbols on right hand side) +# lr_after - List of all productions that immediately follow +# lr_before - Grammar symbol immediately before +# ----------------------------------------------------------------------------- + +class LRItem(object): + def __init__(self,p,n): + self.name = p.name + self.prod = list(p.prod) + self.number = p.number + self.lr_index = n + self.lookaheads = { } + self.prod.insert(n,".") + self.prod = tuple(self.prod) + self.len = len(self.prod) + self.usyms = p.usyms + + def __str__(self): + if self.prod: + s = "%s -> %s" % (self.name," ".join(self.prod)) + else: + s = "%s -> " % self.name + return s + + def __repr__(self): + return "LRItem("+str(self)+")" + +# ----------------------------------------------------------------------------- +# rightmost_terminal() +# +# Return the rightmost terminal from a list of symbols. Used in add_production() +# ----------------------------------------------------------------------------- +def rightmost_terminal(symbols, terminals): + i = len(symbols) - 1 + while i >= 0: + if symbols[i] in terminals: + return symbols[i] + i -= 1 + return None + +# ----------------------------------------------------------------------------- +# === GRAMMAR CLASS === +# +# The following class represents the contents of the specified grammar along +# with various computed properties such as first sets, follow sets, LR items, etc. +# This data is used for critical parts of the table generation process later. +# ----------------------------------------------------------------------------- + +class GrammarError(YaccError): pass + +class Grammar(object): + def __init__(self,terminals): + self.Productions = [None] # A list of all of the productions. The first + # entry is always reserved for the purpose of + # building an augmented grammar + + self.Prodnames = { } # A dictionary mapping the names of nonterminals to a list of all + # productions of that nonterminal. + + self.Prodmap = { } # A dictionary that is only used to detect duplicate + # productions. + + self.Terminals = { } # A dictionary mapping the names of terminal symbols to a + # list of the rules where they are used. + + for term in terminals: + self.Terminals[term] = [] + + self.Terminals['error'] = [] + + self.Nonterminals = { } # A dictionary mapping names of nonterminals to a list + # of rule numbers where they are used. + + self.First = { } # A dictionary of precomputed FIRST(x) symbols + + self.Follow = { } # A dictionary of precomputed FOLLOW(x) symbols + + self.Precedence = { } # Precedence rules for each terminal. Contains tuples of the + # form ('right',level) or ('nonassoc', level) or ('left',level) + + self.UsedPrecedence = { } # Precedence rules that were actually used by the grammer. + # This is only used to provide error checking and to generate + # a warning about unused precedence rules. + + self.Start = None # Starting symbol for the grammar + + + def __len__(self): + return len(self.Productions) + + def __getitem__(self,index): + return self.Productions[index] + + # ----------------------------------------------------------------------------- + # set_precedence() + # + # Sets the precedence for a given terminal. assoc is the associativity such as + # 'left','right', or 'nonassoc'. level is a numeric level. + # + # ----------------------------------------------------------------------------- + + def set_precedence(self,term,assoc,level): + assert self.Productions == [None],"Must call set_precedence() before add_production()" + if term in self.Precedence: + raise GrammarError("Precedence already specified for terminal '%s'" % term) + if assoc not in ['left','right','nonassoc']: + raise GrammarError("Associativity must be one of 'left','right', or 'nonassoc'") + self.Precedence[term] = (assoc,level) + + # ----------------------------------------------------------------------------- + # add_production() + # + # Given an action function, this function assembles a production rule and + # computes its precedence level. + # + # The production rule is supplied as a list of symbols. For example, + # a rule such as 'expr : expr PLUS term' has a production name of 'expr' and + # symbols ['expr','PLUS','term']. + # + # Precedence is determined by the precedence of the right-most non-terminal + # or the precedence of a terminal specified by %prec. + # + # A variety of error checks are performed to make sure production symbols + # are valid and that %prec is used correctly. + # ----------------------------------------------------------------------------- + + def add_production(self,prodname,syms,func=None,file='',line=0): + + if prodname in self.Terminals: + raise GrammarError("%s:%d: Illegal rule name '%s'. Already defined as a token" % (file,line,prodname)) + if prodname == 'error': + raise GrammarError("%s:%d: Illegal rule name '%s'. error is a reserved word" % (file,line,prodname)) + if not _is_identifier.match(prodname): + raise GrammarError("%s:%d: Illegal rule name '%s'" % (file,line,prodname)) + + # Look for literal tokens + for n,s in enumerate(syms): + if s[0] in "'\"": + try: + c = eval(s) + if (len(c) > 1): + raise GrammarError("%s:%d: Literal token %s in rule '%s' may only be a single character" % (file,line,s, prodname)) + if not c in self.Terminals: + self.Terminals[c] = [] + syms[n] = c + continue + except SyntaxError: + pass + if not _is_identifier.match(s) and s != '%prec': + raise GrammarError("%s:%d: Illegal name '%s' in rule '%s'" % (file,line,s, prodname)) + + # Determine the precedence level + if '%prec' in syms: + if syms[-1] == '%prec': + raise GrammarError("%s:%d: Syntax error. Nothing follows %%prec" % (file,line)) + if syms[-2] != '%prec': + raise GrammarError("%s:%d: Syntax error. %%prec can only appear at the end of a grammar rule" % (file,line)) + precname = syms[-1] + prodprec = self.Precedence.get(precname,None) + if not prodprec: + raise GrammarError("%s:%d: Nothing known about the precedence of '%s'" % (file,line,precname)) + else: + self.UsedPrecedence[precname] = 1 + del syms[-2:] # Drop %prec from the rule + else: + # If no %prec, precedence is determined by the rightmost terminal symbol + precname = rightmost_terminal(syms,self.Terminals) + prodprec = self.Precedence.get(precname,('right',0)) + + # See if the rule is already in the rulemap + map = "%s -> %s" % (prodname,syms) + if map in self.Prodmap: + m = self.Prodmap[map] + raise GrammarError("%s:%d: Duplicate rule %s. " % (file,line, m) + + "Previous definition at %s:%d" % (m.file, m.line)) + + # From this point on, everything is valid. Create a new Production instance + pnumber = len(self.Productions) + if not prodname in self.Nonterminals: + self.Nonterminals[prodname] = [ ] + + # Add the production number to Terminals and Nonterminals + for t in syms: + if t in self.Terminals: + self.Terminals[t].append(pnumber) + else: + if not t in self.Nonterminals: + self.Nonterminals[t] = [ ] + self.Nonterminals[t].append(pnumber) + + # Create a production and add it to the list of productions + p = Production(pnumber,prodname,syms,prodprec,func,file,line) + self.Productions.append(p) + self.Prodmap[map] = p + + # Add to the global productions list + try: + self.Prodnames[prodname].append(p) + except KeyError: + self.Prodnames[prodname] = [ p ] + return 0 + + # ----------------------------------------------------------------------------- + # set_start() + # + # Sets the starting symbol and creates the augmented grammar. Production + # rule 0 is S' -> start where start is the start symbol. + # ----------------------------------------------------------------------------- + + def set_start(self,start=None): + if not start: + start = self.Productions[1].name + if start not in self.Nonterminals: + raise GrammarError("start symbol %s undefined" % start) + self.Productions[0] = Production(0,"S'",[start]) + self.Nonterminals[start].append(0) + self.Start = start + + # ----------------------------------------------------------------------------- + # find_unreachable() + # + # Find all of the nonterminal symbols that can't be reached from the starting + # symbol. Returns a list of nonterminals that can't be reached. + # ----------------------------------------------------------------------------- + + def find_unreachable(self): + + # Mark all symbols that are reachable from a symbol s + def mark_reachable_from(s): + if reachable[s]: + # We've already reached symbol s. + return + reachable[s] = 1 + for p in self.Prodnames.get(s,[]): + for r in p.prod: + mark_reachable_from(r) + + reachable = { } + for s in list(self.Terminals) + list(self.Nonterminals): + reachable[s] = 0 + + mark_reachable_from( self.Productions[0].prod[0] ) + + return [s for s in list(self.Nonterminals) + if not reachable[s]] + + # ----------------------------------------------------------------------------- + # infinite_cycles() + # + # This function looks at the various parsing rules and tries to detect + # infinite recursion cycles (grammar rules where there is no possible way + # to derive a string of only terminals). + # ----------------------------------------------------------------------------- + + def infinite_cycles(self): + terminates = {} + + # Terminals: + for t in self.Terminals: + terminates[t] = 1 + + terminates['$end'] = 1 + + # Nonterminals: + + # Initialize to false: + for n in self.Nonterminals: + terminates[n] = 0 + + # Then propagate termination until no change: + while 1: + some_change = 0 + for (n,pl) in self.Prodnames.items(): + # Nonterminal n terminates iff any of its productions terminates. + for p in pl: + # Production p terminates iff all of its rhs symbols terminate. + for s in p.prod: + if not terminates[s]: + # The symbol s does not terminate, + # so production p does not terminate. + p_terminates = 0 + break + else: + # didn't break from the loop, + # so every symbol s terminates + # so production p terminates. + p_terminates = 1 + + if p_terminates: + # symbol n terminates! + if not terminates[n]: + terminates[n] = 1 + some_change = 1 + # Don't need to consider any more productions for this n. + break + + if not some_change: + break + + infinite = [] + for (s,term) in terminates.items(): + if not term: + if not s in self.Prodnames and not s in self.Terminals and s != 'error': + # s is used-but-not-defined, and we've already warned of that, + # so it would be overkill to say that it's also non-terminating. + pass + else: + infinite.append(s) + + return infinite + + + # ----------------------------------------------------------------------------- + # undefined_symbols() + # + # Find all symbols that were used the grammar, but not defined as tokens or + # grammar rules. Returns a list of tuples (sym, prod) where sym in the symbol + # and prod is the production where the symbol was used. + # ----------------------------------------------------------------------------- + def undefined_symbols(self): + result = [] + for p in self.Productions: + if not p: continue + + for s in p.prod: + if not s in self.Prodnames and not s in self.Terminals and s != 'error': + result.append((s,p)) + return result + + # ----------------------------------------------------------------------------- + # unused_terminals() + # + # Find all terminals that were defined, but not used by the grammar. Returns + # a list of all symbols. + # ----------------------------------------------------------------------------- + def unused_terminals(self): + unused_tok = [] + for s,v in self.Terminals.items(): + if s != 'error' and not v: + unused_tok.append(s) + + return unused_tok + + # ------------------------------------------------------------------------------ + # unused_rules() + # + # Find all grammar rules that were defined, but not used (maybe not reachable) + # Returns a list of productions. + # ------------------------------------------------------------------------------ + + def unused_rules(self): + unused_prod = [] + for s,v in self.Nonterminals.items(): + if not v: + p = self.Prodnames[s][0] + unused_prod.append(p) + return unused_prod + + # ----------------------------------------------------------------------------- + # unused_precedence() + # + # Returns a list of tuples (term,precedence) corresponding to precedence + # rules that were never used by the grammar. term is the name of the terminal + # on which precedence was applied and precedence is a string such as 'left' or + # 'right' corresponding to the type of precedence. + # ----------------------------------------------------------------------------- + + def unused_precedence(self): + unused = [] + for termname in self.Precedence: + if not (termname in self.Terminals or termname in self.UsedPrecedence): + unused.append((termname,self.Precedence[termname][0])) + + return unused + + # ------------------------------------------------------------------------- + # _first() + # + # Compute the value of FIRST1(beta) where beta is a tuple of symbols. + # + # During execution of compute_first1, the result may be incomplete. + # Afterward (e.g., when called from compute_follow()), it will be complete. + # ------------------------------------------------------------------------- + def _first(self,beta): + + # We are computing First(x1,x2,x3,...,xn) + result = [ ] + for x in beta: + x_produces_empty = 0 + + # Add all the non- symbols of First[x] to the result. + for f in self.First[x]: + if f == '': + x_produces_empty = 1 + else: + if f not in result: result.append(f) + + if x_produces_empty: + # We have to consider the next x in beta, + # i.e. stay in the loop. + pass + else: + # We don't have to consider any further symbols in beta. + break + else: + # There was no 'break' from the loop, + # so x_produces_empty was true for all x in beta, + # so beta produces empty as well. + result.append('') + + return result + + # ------------------------------------------------------------------------- + # compute_first() + # + # Compute the value of FIRST1(X) for all symbols + # ------------------------------------------------------------------------- + def compute_first(self): + if self.First: + return self.First + + # Terminals: + for t in self.Terminals: + self.First[t] = [t] + + self.First['$end'] = ['$end'] + + # Nonterminals: + + # Initialize to the empty set: + for n in self.Nonterminals: + self.First[n] = [] + + # Then propagate symbols until no change: + while 1: + some_change = 0 + for n in self.Nonterminals: + for p in self.Prodnames[n]: + for f in self._first(p.prod): + if f not in self.First[n]: + self.First[n].append( f ) + some_change = 1 + if not some_change: + break + + return self.First + + # --------------------------------------------------------------------- + # compute_follow() + # + # Computes all of the follow sets for every non-terminal symbol. The + # follow set is the set of all symbols that might follow a given + # non-terminal. See the Dragon book, 2nd Ed. p. 189. + # --------------------------------------------------------------------- + def compute_follow(self,start=None): + # If already computed, return the result + if self.Follow: + return self.Follow + + # If first sets not computed yet, do that first. + if not self.First: + self.compute_first() + + # Add '$end' to the follow list of the start symbol + for k in self.Nonterminals: + self.Follow[k] = [ ] + + if not start: + start = self.Productions[1].name + + self.Follow[start] = [ '$end' ] + + while 1: + didadd = 0 + for p in self.Productions[1:]: + # Here is the production set + for i in range(len(p.prod)): + B = p.prod[i] + if B in self.Nonterminals: + # Okay. We got a non-terminal in a production + fst = self._first(p.prod[i+1:]) + hasempty = 0 + for f in fst: + if f != '' and f not in self.Follow[B]: + self.Follow[B].append(f) + didadd = 1 + if f == '': + hasempty = 1 + if hasempty or i == (len(p.prod)-1): + # Add elements of follow(a) to follow(b) + for f in self.Follow[p.name]: + if f not in self.Follow[B]: + self.Follow[B].append(f) + didadd = 1 + if not didadd: break + return self.Follow + + + # ----------------------------------------------------------------------------- + # build_lritems() + # + # This function walks the list of productions and builds a complete set of the + # LR items. The LR items are stored in two ways: First, they are uniquely + # numbered and placed in the list _lritems. Second, a linked list of LR items + # is built for each production. For example: + # + # E -> E PLUS E + # + # Creates the list + # + # [E -> . E PLUS E, E -> E . PLUS E, E -> E PLUS . E, E -> E PLUS E . ] + # ----------------------------------------------------------------------------- + + def build_lritems(self): + for p in self.Productions: + lastlri = p + i = 0 + lr_items = [] + while 1: + if i > len(p): + lri = None + else: + lri = LRItem(p,i) + # Precompute the list of productions immediately following + try: + lri.lr_after = self.Prodnames[lri.prod[i+1]] + except (IndexError,KeyError): + lri.lr_after = [] + try: + lri.lr_before = lri.prod[i-1] + except IndexError: + lri.lr_before = None + + lastlri.lr_next = lri + if not lri: break + lr_items.append(lri) + lastlri = lri + i += 1 + p.lr_items = lr_items + +# ----------------------------------------------------------------------------- +# == Class LRTable == +# +# This basic class represents a basic table of LR parsing information. +# Methods for generating the tables are not defined here. They are defined +# in the derived class LRGeneratedTable. +# ----------------------------------------------------------------------------- + +class VersionError(YaccError): pass + +class LRTable(object): + def __init__(self): + self.lr_action = None + self.lr_goto = None + self.lr_productions = None + self.lr_method = None + + def read_table(self,module): + if isinstance(module,types.ModuleType): + parsetab = module + else: + if sys.version_info[0] < 3: + exec("import %s as parsetab" % module) + else: + env = { } + exec("import %s as parsetab" % module, env, env) + parsetab = env['parsetab'] + + if parsetab._tabversion != __tabversion__: + raise VersionError("yacc table file version is out of date") + + self.lr_action = parsetab._lr_action + self.lr_goto = parsetab._lr_goto + + self.lr_productions = [] + for p in parsetab._lr_productions: + self.lr_productions.append(MiniProduction(*p)) + + self.lr_method = parsetab._lr_method + return parsetab._lr_signature + + def read_pickle(self,filename): + try: + import cPickle as pickle + except ImportError: + import pickle + + in_f = open(filename,"rb") + + tabversion = pickle.load(in_f) + if tabversion != __tabversion__: + raise VersionError("yacc table file version is out of date") + self.lr_method = pickle.load(in_f) + signature = pickle.load(in_f) + self.lr_action = pickle.load(in_f) + self.lr_goto = pickle.load(in_f) + productions = pickle.load(in_f) + + self.lr_productions = [] + for p in productions: + self.lr_productions.append(MiniProduction(*p)) + + in_f.close() + return signature + + # Bind all production function names to callable objects in pdict + def bind_callables(self,pdict): + for p in self.lr_productions: + p.bind(pdict) + +# ----------------------------------------------------------------------------- +# === LR Generator === +# +# The following classes and functions are used to generate LR parsing tables on +# a grammar. +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# digraph() +# traverse() +# +# The following two functions are used to compute set valued functions +# of the form: +# +# F(x) = F'(x) U U{F(y) | x R y} +# +# This is used to compute the values of Read() sets as well as FOLLOW sets +# in LALR(1) generation. +# +# Inputs: X - An input set +# R - A relation +# FP - Set-valued function +# ------------------------------------------------------------------------------ + +def digraph(X,R,FP): + N = { } + for x in X: + N[x] = 0 + stack = [] + F = { } + for x in X: + if N[x] == 0: traverse(x,N,stack,F,X,R,FP) + return F + +def traverse(x,N,stack,F,X,R,FP): + stack.append(x) + d = len(stack) + N[x] = d + F[x] = FP(x) # F(X) <- F'(x) + + rel = R(x) # Get y's related to x + for y in rel: + if N[y] == 0: + traverse(y,N,stack,F,X,R,FP) + N[x] = min(N[x],N[y]) + for a in F.get(y,[]): + if a not in F[x]: F[x].append(a) + if N[x] == d: + N[stack[-1]] = MAXINT + F[stack[-1]] = F[x] + element = stack.pop() + while element != x: + N[stack[-1]] = MAXINT + F[stack[-1]] = F[x] + element = stack.pop() + +class LALRError(YaccError): pass + +# ----------------------------------------------------------------------------- +# == LRGeneratedTable == +# +# This class implements the LR table generation algorithm. There are no +# public methods except for write() +# ----------------------------------------------------------------------------- + +class LRGeneratedTable(LRTable): + def __init__(self,grammar,method='LALR',log=None): + if method not in ['SLR','LALR']: + raise LALRError("Unsupported method %s" % method) + + self.grammar = grammar + self.lr_method = method + + # Set up the logger + if not log: + log = NullLogger() + self.log = log + + # Internal attributes + self.lr_action = {} # Action table + self.lr_goto = {} # Goto table + self.lr_productions = grammar.Productions # Copy of grammar Production array + self.lr_goto_cache = {} # Cache of computed gotos + self.lr0_cidhash = {} # Cache of closures + + self._add_count = 0 # Internal counter used to detect cycles + + # Diagonistic information filled in by the table generator + self.sr_conflict = 0 + self.rr_conflict = 0 + self.conflicts = [] # List of conflicts + + self.sr_conflicts = [] + self.rr_conflicts = [] + + # Build the tables + self.grammar.build_lritems() + self.grammar.compute_first() + self.grammar.compute_follow() + self.lr_parse_table() + + # Compute the LR(0) closure operation on I, where I is a set of LR(0) items. + + def lr0_closure(self,I): + self._add_count += 1 + + # Add everything in I to J + J = I[:] + didadd = 1 + while didadd: + didadd = 0 + for j in J: + for x in j.lr_after: + if getattr(x,"lr0_added",0) == self._add_count: continue + # Add B --> .G to J + J.append(x.lr_next) + x.lr0_added = self._add_count + didadd = 1 + + return J + + # Compute the LR(0) goto function goto(I,X) where I is a set + # of LR(0) items and X is a grammar symbol. This function is written + # in a way that guarantees uniqueness of the generated goto sets + # (i.e. the same goto set will never be returned as two different Python + # objects). With uniqueness, we can later do fast set comparisons using + # id(obj) instead of element-wise comparison. + + def lr0_goto(self,I,x): + # First we look for a previously cached entry + g = self.lr_goto_cache.get((id(I),x),None) + if g: return g + + # Now we generate the goto set in a way that guarantees uniqueness + # of the result + + s = self.lr_goto_cache.get(x,None) + if not s: + s = { } + self.lr_goto_cache[x] = s + + gs = [ ] + for p in I: + n = p.lr_next + if n and n.lr_before == x: + s1 = s.get(id(n),None) + if not s1: + s1 = { } + s[id(n)] = s1 + gs.append(n) + s = s1 + g = s.get('$end',None) + if not g: + if gs: + g = self.lr0_closure(gs) + s['$end'] = g + else: + s['$end'] = gs + self.lr_goto_cache[(id(I),x)] = g + return g + + # Compute the LR(0) sets of item function + def lr0_items(self): + + C = [ self.lr0_closure([self.grammar.Productions[0].lr_next]) ] + i = 0 + for I in C: + self.lr0_cidhash[id(I)] = i + i += 1 + + # Loop over the items in C and each grammar symbols + i = 0 + while i < len(C): + I = C[i] + i += 1 + + # Collect all of the symbols that could possibly be in the goto(I,X) sets + asyms = { } + for ii in I: + for s in ii.usyms: + asyms[s] = None + + for x in asyms: + g = self.lr0_goto(I,x) + if not g: continue + if id(g) in self.lr0_cidhash: continue + self.lr0_cidhash[id(g)] = len(C) + C.append(g) + + return C + + # ----------------------------------------------------------------------------- + # ==== LALR(1) Parsing ==== + # + # LALR(1) parsing is almost exactly the same as SLR except that instead of + # relying upon Follow() sets when performing reductions, a more selective + # lookahead set that incorporates the state of the LR(0) machine is utilized. + # Thus, we mainly just have to focus on calculating the lookahead sets. + # + # The method used here is due to DeRemer and Pennelo (1982). + # + # DeRemer, F. L., and T. J. Pennelo: "Efficient Computation of LALR(1) + # Lookahead Sets", ACM Transactions on Programming Languages and Systems, + # Vol. 4, No. 4, Oct. 1982, pp. 615-649 + # + # Further details can also be found in: + # + # J. Tremblay and P. Sorenson, "The Theory and Practice of Compiler Writing", + # McGraw-Hill Book Company, (1985). + # + # ----------------------------------------------------------------------------- + + # ----------------------------------------------------------------------------- + # compute_nullable_nonterminals() + # + # Creates a dictionary containing all of the non-terminals that might produce + # an empty production. + # ----------------------------------------------------------------------------- + + def compute_nullable_nonterminals(self): + nullable = {} + num_nullable = 0 + while 1: + for p in self.grammar.Productions[1:]: + if p.len == 0: + nullable[p.name] = 1 + continue + for t in p.prod: + if not t in nullable: break + else: + nullable[p.name] = 1 + if len(nullable) == num_nullable: break + num_nullable = len(nullable) + return nullable + + # ----------------------------------------------------------------------------- + # find_nonterminal_trans(C) + # + # Given a set of LR(0) items, this functions finds all of the non-terminal + # transitions. These are transitions in which a dot appears immediately before + # a non-terminal. Returns a list of tuples of the form (state,N) where state + # is the state number and N is the nonterminal symbol. + # + # The input C is the set of LR(0) items. + # ----------------------------------------------------------------------------- + + def find_nonterminal_transitions(self,C): + trans = [] + for state in range(len(C)): + for p in C[state]: + if p.lr_index < p.len - 1: + t = (state,p.prod[p.lr_index+1]) + if t[1] in self.grammar.Nonterminals: + if t not in trans: trans.append(t) + state = state + 1 + return trans + + # ----------------------------------------------------------------------------- + # dr_relation() + # + # Computes the DR(p,A) relationships for non-terminal transitions. The input + # is a tuple (state,N) where state is a number and N is a nonterminal symbol. + # + # Returns a list of terminals. + # ----------------------------------------------------------------------------- + + def dr_relation(self,C,trans,nullable): + dr_set = { } + state,N = trans + terms = [] + + g = self.lr0_goto(C[state],N) + for p in g: + if p.lr_index < p.len - 1: + a = p.prod[p.lr_index+1] + if a in self.grammar.Terminals: + if a not in terms: terms.append(a) + + # This extra bit is to handle the start state + if state == 0 and N == self.grammar.Productions[0].prod[0]: + terms.append('$end') + + return terms + + # ----------------------------------------------------------------------------- + # reads_relation() + # + # Computes the READS() relation (p,A) READS (t,C). + # ----------------------------------------------------------------------------- + + def reads_relation(self,C, trans, empty): + # Look for empty transitions + rel = [] + state, N = trans + + g = self.lr0_goto(C[state],N) + j = self.lr0_cidhash.get(id(g),-1) + for p in g: + if p.lr_index < p.len - 1: + a = p.prod[p.lr_index + 1] + if a in empty: + rel.append((j,a)) + + return rel + + # ----------------------------------------------------------------------------- + # compute_lookback_includes() + # + # Determines the lookback and includes relations + # + # LOOKBACK: + # + # This relation is determined by running the LR(0) state machine forward. + # For example, starting with a production "N : . A B C", we run it forward + # to obtain "N : A B C ." We then build a relationship between this final + # state and the starting state. These relationships are stored in a dictionary + # lookdict. + # + # INCLUDES: + # + # Computes the INCLUDE() relation (p,A) INCLUDES (p',B). + # + # This relation is used to determine non-terminal transitions that occur + # inside of other non-terminal transition states. (p,A) INCLUDES (p', B) + # if the following holds: + # + # B -> LAT, where T -> epsilon and p' -L-> p + # + # L is essentially a prefix (which may be empty), T is a suffix that must be + # able to derive an empty string. State p' must lead to state p with the string L. + # + # ----------------------------------------------------------------------------- + + def compute_lookback_includes(self,C,trans,nullable): + + lookdict = {} # Dictionary of lookback relations + includedict = {} # Dictionary of include relations + + # Make a dictionary of non-terminal transitions + dtrans = {} + for t in trans: + dtrans[t] = 1 + + # Loop over all transitions and compute lookbacks and includes + for state,N in trans: + lookb = [] + includes = [] + for p in C[state]: + if p.name != N: continue + + # Okay, we have a name match. We now follow the production all the way + # through the state machine until we get the . on the right hand side + + lr_index = p.lr_index + j = state + while lr_index < p.len - 1: + lr_index = lr_index + 1 + t = p.prod[lr_index] + + # Check to see if this symbol and state are a non-terminal transition + if (j,t) in dtrans: + # Yes. Okay, there is some chance that this is an includes relation + # the only way to know for certain is whether the rest of the + # production derives empty + + li = lr_index + 1 + while li < p.len: + if p.prod[li] in self.grammar.Terminals: break # No forget it + if not p.prod[li] in nullable: break + li = li + 1 + else: + # Appears to be a relation between (j,t) and (state,N) + includes.append((j,t)) + + g = self.lr0_goto(C[j],t) # Go to next set + j = self.lr0_cidhash.get(id(g),-1) # Go to next state + + # When we get here, j is the final state, now we have to locate the production + for r in C[j]: + if r.name != p.name: continue + if r.len != p.len: continue + i = 0 + # This look is comparing a production ". A B C" with "A B C ." + while i < r.lr_index: + if r.prod[i] != p.prod[i+1]: break + i = i + 1 + else: + lookb.append((j,r)) + for i in includes: + if not i in includedict: includedict[i] = [] + includedict[i].append((state,N)) + lookdict[(state,N)] = lookb + + return lookdict,includedict + + # ----------------------------------------------------------------------------- + # compute_read_sets() + # + # Given a set of LR(0) items, this function computes the read sets. + # + # Inputs: C = Set of LR(0) items + # ntrans = Set of nonterminal transitions + # nullable = Set of empty transitions + # + # Returns a set containing the read sets + # ----------------------------------------------------------------------------- + + def compute_read_sets(self,C, ntrans, nullable): + FP = lambda x: self.dr_relation(C,x,nullable) + R = lambda x: self.reads_relation(C,x,nullable) + F = digraph(ntrans,R,FP) + return F + + # ----------------------------------------------------------------------------- + # compute_follow_sets() + # + # Given a set of LR(0) items, a set of non-terminal transitions, a readset, + # and an include set, this function computes the follow sets + # + # Follow(p,A) = Read(p,A) U U {Follow(p',B) | (p,A) INCLUDES (p',B)} + # + # Inputs: + # ntrans = Set of nonterminal transitions + # readsets = Readset (previously computed) + # inclsets = Include sets (previously computed) + # + # Returns a set containing the follow sets + # ----------------------------------------------------------------------------- + + def compute_follow_sets(self,ntrans,readsets,inclsets): + FP = lambda x: readsets[x] + R = lambda x: inclsets.get(x,[]) + F = digraph(ntrans,R,FP) + return F + + # ----------------------------------------------------------------------------- + # add_lookaheads() + # + # Attaches the lookahead symbols to grammar rules. + # + # Inputs: lookbacks - Set of lookback relations + # followset - Computed follow set + # + # This function directly attaches the lookaheads to productions contained + # in the lookbacks set + # ----------------------------------------------------------------------------- + + def add_lookaheads(self,lookbacks,followset): + for trans,lb in lookbacks.items(): + # Loop over productions in lookback + for state,p in lb: + if not state in p.lookaheads: + p.lookaheads[state] = [] + f = followset.get(trans,[]) + for a in f: + if a not in p.lookaheads[state]: p.lookaheads[state].append(a) + + # ----------------------------------------------------------------------------- + # add_lalr_lookaheads() + # + # This function does all of the work of adding lookahead information for use + # with LALR parsing + # ----------------------------------------------------------------------------- + + def add_lalr_lookaheads(self,C): + # Determine all of the nullable nonterminals + nullable = self.compute_nullable_nonterminals() + + # Find all non-terminal transitions + trans = self.find_nonterminal_transitions(C) + + # Compute read sets + readsets = self.compute_read_sets(C,trans,nullable) + + # Compute lookback/includes relations + lookd, included = self.compute_lookback_includes(C,trans,nullable) + + # Compute LALR FOLLOW sets + followsets = self.compute_follow_sets(trans,readsets,included) + + # Add all of the lookaheads + self.add_lookaheads(lookd,followsets) + + # ----------------------------------------------------------------------------- + # lr_parse_table() + # + # This function constructs the parse tables for SLR or LALR + # ----------------------------------------------------------------------------- + def lr_parse_table(self): + Productions = self.grammar.Productions + Precedence = self.grammar.Precedence + goto = self.lr_goto # Goto array + action = self.lr_action # Action array + log = self.log # Logger for output + + actionp = { } # Action production array (temporary) + + log.info("Parsing method: %s", self.lr_method) + + # Step 1: Construct C = { I0, I1, ... IN}, collection of LR(0) items + # This determines the number of states + + C = self.lr0_items() + + if self.lr_method == 'LALR': + self.add_lalr_lookaheads(C) + + # Build the parser table, state by state + st = 0 + for I in C: + # Loop over each production in I + actlist = [ ] # List of actions + st_action = { } + st_actionp = { } + st_goto = { } + log.info("") + log.info("state %d", st) + log.info("") + for p in I: + log.info(" (%d) %s", p.number, str(p)) + log.info("") + + for p in I: + if p.len == p.lr_index + 1: + if p.name == "S'": + # Start symbol. Accept! + st_action["$end"] = 0 + st_actionp["$end"] = p + else: + # We are at the end of a production. Reduce! + if self.lr_method == 'LALR': + laheads = p.lookaheads[st] + else: + laheads = self.grammar.Follow[p.name] + for a in laheads: + actlist.append((a,p,"reduce using rule %d (%s)" % (p.number,p))) + r = st_action.get(a,None) + if r is not None: + # Whoa. Have a shift/reduce or reduce/reduce conflict + if r > 0: + # Need to decide on shift or reduce here + # By default we favor shifting. Need to add + # some precedence rules here. + sprec,slevel = Productions[st_actionp[a].number].prec + rprec,rlevel = Precedence.get(a,('right',0)) + if (slevel < rlevel) or ((slevel == rlevel) and (rprec == 'left')): + # We really need to reduce here. + st_action[a] = -p.number + st_actionp[a] = p + if not slevel and not rlevel: + log.info(" ! shift/reduce conflict for %s resolved as reduce",a) + self.sr_conflicts.append((st,a,'reduce')) + Productions[p.number].reduced += 1 + elif (slevel == rlevel) and (rprec == 'nonassoc'): + st_action[a] = None + else: + # Hmmm. Guess we'll keep the shift + if not rlevel: + log.info(" ! shift/reduce conflict for %s resolved as shift",a) + self.sr_conflicts.append((st,a,'shift')) + elif r < 0: + # Reduce/reduce conflict. In this case, we favor the rule + # that was defined first in the grammar file + oldp = Productions[-r] + pp = Productions[p.number] + if oldp.line > pp.line: + st_action[a] = -p.number + st_actionp[a] = p + chosenp,rejectp = pp,oldp + Productions[p.number].reduced += 1 + Productions[oldp.number].reduced -= 1 + else: + chosenp,rejectp = oldp,pp + self.rr_conflicts.append((st,chosenp,rejectp)) + log.info(" ! reduce/reduce conflict for %s resolved using rule %d (%s)", a,st_actionp[a].number, st_actionp[a]) + else: + raise LALRError("Unknown conflict in state %d" % st) + else: + st_action[a] = -p.number + st_actionp[a] = p + Productions[p.number].reduced += 1 + else: + i = p.lr_index + a = p.prod[i+1] # Get symbol right after the "." + if a in self.grammar.Terminals: + g = self.lr0_goto(I,a) + j = self.lr0_cidhash.get(id(g),-1) + if j >= 0: + # We are in a shift state + actlist.append((a,p,"shift and go to state %d" % j)) + r = st_action.get(a,None) + if r is not None: + # Whoa have a shift/reduce or shift/shift conflict + if r > 0: + if r != j: + raise LALRError("Shift/shift conflict in state %d" % st) + elif r < 0: + # Do a precedence check. + # - if precedence of reduce rule is higher, we reduce. + # - if precedence of reduce is same and left assoc, we reduce. + # - otherwise we shift + rprec,rlevel = Productions[st_actionp[a].number].prec + sprec,slevel = Precedence.get(a,('right',0)) + if (slevel > rlevel) or ((slevel == rlevel) and (rprec == 'right')): + # We decide to shift here... highest precedence to shift + Productions[st_actionp[a].number].reduced -= 1 + st_action[a] = j + st_actionp[a] = p + if not rlevel: + log.info(" ! shift/reduce conflict for %s resolved as shift",a) + self.sr_conflicts.append((st,a,'shift')) + elif (slevel == rlevel) and (rprec == 'nonassoc'): + st_action[a] = None + else: + # Hmmm. Guess we'll keep the reduce + if not slevel and not rlevel: + log.info(" ! shift/reduce conflict for %s resolved as reduce",a) + self.sr_conflicts.append((st,a,'reduce')) + + else: + raise LALRError("Unknown conflict in state %d" % st) + else: + st_action[a] = j + st_actionp[a] = p + + # Print the actions associated with each terminal + _actprint = { } + for a,p,m in actlist: + if a in st_action: + if p is st_actionp[a]: + log.info(" %-15s %s",a,m) + _actprint[(a,m)] = 1 + log.info("") + # Print the actions that were not used. (debugging) + not_used = 0 + for a,p,m in actlist: + if a in st_action: + if p is not st_actionp[a]: + if not (a,m) in _actprint: + log.debug(" ! %-15s [ %s ]",a,m) + not_used = 1 + _actprint[(a,m)] = 1 + if not_used: + log.debug("") + + # Construct the goto table for this state + + nkeys = { } + for ii in I: + for s in ii.usyms: + if s in self.grammar.Nonterminals: + nkeys[s] = None + for n in nkeys: + g = self.lr0_goto(I,n) + j = self.lr0_cidhash.get(id(g),-1) + if j >= 0: + st_goto[n] = j + log.info(" %-30s shift and go to state %d",n,j) + + action[st] = st_action + actionp[st] = st_actionp + goto[st] = st_goto + st += 1 + + + # ----------------------------------------------------------------------------- + # write() + # + # This function writes the LR parsing tables to a file + # ----------------------------------------------------------------------------- + + def write_table(self,modulename,outputdir='',signature=""): + return + + + # ----------------------------------------------------------------------------- + # pickle_table() + # + # This function pickles the LR parsing tables to a supplied file object + # ----------------------------------------------------------------------------- + + def pickle_table(self,filename,signature=""): + try: + import cPickle as pickle + except ImportError: + import pickle + outf = open(filename,"wb") + pickle.dump(__tabversion__,outf,pickle_protocol) + pickle.dump(self.lr_method,outf,pickle_protocol) + pickle.dump(signature,outf,pickle_protocol) + pickle.dump(self.lr_action,outf,pickle_protocol) + pickle.dump(self.lr_goto,outf,pickle_protocol) + + outp = [] + for p in self.lr_productions: + if p.func: + outp.append((p.str,p.name, p.len, p.func,p.file,p.line)) + else: + outp.append((str(p),p.name,p.len,None,None,None)) + pickle.dump(outp,outf,pickle_protocol) + outf.close() + +# ----------------------------------------------------------------------------- +# === INTROSPECTION === +# +# The following functions and classes are used to implement the PLY +# introspection features followed by the yacc() function itself. +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# get_caller_module_dict() +# +# This function returns a dictionary containing all of the symbols defined within +# a caller further down the call stack. This is used to get the environment +# associated with the yacc() call if none was provided. +# ----------------------------------------------------------------------------- + +def get_caller_module_dict(levels): + try: + raise RuntimeError + except RuntimeError: + e,b,t = sys.exc_info() + f = t.tb_frame + while levels > 0: + f = f.f_back + levels -= 1 + ldict = f.f_globals.copy() + if f.f_globals != f.f_locals: + ldict.update(f.f_locals) + + return ldict + +# ----------------------------------------------------------------------------- +# parse_grammar() +# +# This takes a raw grammar rule string and parses it into production data +# ----------------------------------------------------------------------------- +def parse_grammar(doc,file,line): + grammar = [] + # Split the doc string into lines + pstrings = doc.splitlines() + lastp = None + dline = line + for ps in pstrings: + dline += 1 + p = ps.split() + if not p: continue + try: + if p[0] == '|': + # This is a continuation of a previous rule + if not lastp: + raise SyntaxError("%s:%d: Misplaced '|'" % (file,dline)) + prodname = lastp + syms = p[1:] + else: + prodname = p[0] + lastp = prodname + syms = p[2:] + assign = p[1] + if assign != ':' and assign != '::=': + raise SyntaxError("%s:%d: Syntax error. Expected ':'" % (file,dline)) + + grammar.append((file,dline,prodname,syms)) + except SyntaxError: + raise + except Exception: + raise SyntaxError("%s:%d: Syntax error in rule '%s'" % (file,dline,ps.strip())) + + return grammar + +# ----------------------------------------------------------------------------- +# ParserReflect() +# +# This class represents information extracted for building a parser including +# start symbol, error function, tokens, precedence list, action functions, +# etc. +# ----------------------------------------------------------------------------- +class ParserReflect(object): + def __init__(self,pdict,log=None): + self.pdict = pdict + self.start = None + self.error_func = None + self.tokens = None + self.files = {} + self.grammar = [] + self.error = 0 + + if log is None: + self.log = PlyLogger(sys.stderr) + else: + self.log = log + + # Get all of the basic information + def get_all(self): + self.get_start() + self.get_error_func() + self.get_tokens() + self.get_precedence() + self.get_pfunctions() + + # Validate all of the information + def validate_all(self): + self.validate_start() + self.validate_error_func() + self.validate_tokens() + self.validate_precedence() + self.validate_pfunctions() + self.validate_files() + return self.error + + # Compute a signature over the grammar + def signature(self): + try: + from hashlib import md5 + except ImportError: + from md5 import md5 + try: + sig = md5() + if self.start: + sig.update(self.start.encode('latin-1')) + if self.prec: + sig.update("".join(["".join(p) for p in self.prec]).encode('latin-1')) + if self.tokens: + sig.update(" ".join(self.tokens).encode('latin-1')) + for f in self.pfuncs: + if f[3]: + sig.update(f[3].encode('latin-1')) + except (TypeError,ValueError): + pass + return sig.digest() + + # ----------------------------------------------------------------------------- + # validate_file() + # + # This method checks to see if there are duplicated p_rulename() functions + # in the parser module file. Without this function, it is really easy for + # users to make mistakes by cutting and pasting code fragments (and it's a real + # bugger to try and figure out why the resulting parser doesn't work). Therefore, + # we just do a little regular expression pattern matching of def statements + # to try and detect duplicates. + # ----------------------------------------------------------------------------- + + def validate_files(self): + # Match def p_funcname( + fre = re.compile(r'\s*def\s+(p_[a-zA-Z_0-9]*)\(') + + for filename in self.files.keys(): + base,ext = os.path.splitext(filename) + if ext != '.py': return 1 # No idea. Assume it's okay. + + try: + f = open(filename) + lines = f.readlines() + f.close() + except IOError: + continue + + counthash = { } + for linen,l in enumerate(lines): + linen += 1 + m = fre.match(l) + if m: + name = m.group(1) + prev = counthash.get(name) + if not prev: + counthash[name] = linen + else: + self.log.warning("%s:%d: Function %s redefined. Previously defined on line %d", filename,linen,name,prev) + + # Get the start symbol + def get_start(self): + self.start = self.pdict.get('start') + + # Validate the start symbol + def validate_start(self): + if self.start is not None: + if not isinstance(self.start,str): + self.log.error("'start' must be a string") + + # Look for error handler + def get_error_func(self): + self.error_func = self.pdict.get('p_error') + + # Validate the error function + def validate_error_func(self): + if self.error_func: + if isinstance(self.error_func,types.FunctionType): + ismethod = 0 + elif isinstance(self.error_func, types.MethodType): + ismethod = 1 + else: + self.log.error("'p_error' defined, but is not a function or method") + self.error = 1 + return + + eline = func_code(self.error_func).co_firstlineno + efile = func_code(self.error_func).co_filename + self.files[efile] = 1 + + if (func_code(self.error_func).co_argcount != 1+ismethod): + self.log.error("%s:%d: p_error() requires 1 argument",efile,eline) + self.error = 1 + + # Get the tokens map + def get_tokens(self): + tokens = self.pdict.get("tokens",None) + if not tokens: + self.log.error("No token list is defined") + self.error = 1 + return + + if not isinstance(tokens,(list, tuple)): + self.log.error("tokens must be a list or tuple") + self.error = 1 + return + + if not tokens: + self.log.error("tokens is empty") + self.error = 1 + return + + self.tokens = tokens + + # Validate the tokens + def validate_tokens(self): + # Validate the tokens. + if 'error' in self.tokens: + self.log.error("Illegal token name 'error'. Is a reserved word") + self.error = 1 + return + + terminals = {} + for n in self.tokens: + if n in terminals: + self.log.warning("Token '%s' multiply defined", n) + terminals[n] = 1 + + # Get the precedence map (if any) + def get_precedence(self): + self.prec = self.pdict.get("precedence",None) + + # Validate and parse the precedence map + def validate_precedence(self): + preclist = [] + if self.prec: + if not isinstance(self.prec,(list,tuple)): + self.log.error("precedence must be a list or tuple") + self.error = 1 + return + for level,p in enumerate(self.prec): + if not isinstance(p,(list,tuple)): + self.log.error("Bad precedence table") + self.error = 1 + return + + if len(p) < 2: + self.log.error("Malformed precedence entry %s. Must be (assoc, term, ..., term)",p) + self.error = 1 + return + assoc = p[0] + if not isinstance(assoc,str): + self.log.error("precedence associativity must be a string") + self.error = 1 + return + for term in p[1:]: + if not isinstance(term,str): + self.log.error("precedence items must be strings") + self.error = 1 + return + preclist.append((term,assoc,level+1)) + self.preclist = preclist + + # Get all p_functions from the grammar + def get_pfunctions(self): + p_functions = [] + for name, item in self.pdict.items(): + if name[:2] != 'p_': continue + if name == 'p_error': continue + if isinstance(item,(types.FunctionType,types.MethodType)): + line = func_code(item).co_firstlineno + file = func_code(item).co_filename + p_functions.append((line,file,name,item.__doc__)) + + # Sort all of the actions by line number + p_functions.sort() + self.pfuncs = p_functions + + + # Validate all of the p_functions + def validate_pfunctions(self): + grammar = [] + # Check for non-empty symbols + if len(self.pfuncs) == 0: + self.log.error("no rules of the form p_rulename are defined") + self.error = 1 + return + + for line, file, name, doc in self.pfuncs: + func = self.pdict[name] + if isinstance(func, types.MethodType): + reqargs = 2 + else: + reqargs = 1 + if func_code(func).co_argcount > reqargs: + self.log.error("%s:%d: Rule '%s' has too many arguments",file,line,func.__name__) + self.error = 1 + elif func_code(func).co_argcount < reqargs: + self.log.error("%s:%d: Rule '%s' requires an argument",file,line,func.__name__) + self.error = 1 + elif not func.__doc__: + self.log.warning("%s:%d: No documentation string specified in function '%s' (ignored)",file,line,func.__name__) + else: + try: + parsed_g = parse_grammar(doc,file,line) + for g in parsed_g: + grammar.append((name, g)) + except SyntaxError: + e = sys.exc_info()[1] + self.log.error(str(e)) + self.error = 1 + + # Looks like a valid grammar rule + # Mark the file in which defined. + self.files[file] = 1 + + # Secondary validation step that looks for p_ definitions that are not functions + # or functions that look like they might be grammar rules. + + for n,v in self.pdict.items(): + if n[0:2] == 'p_' and isinstance(v, (types.FunctionType, types.MethodType)): continue + if n[0:2] == 't_': continue + if n[0:2] == 'p_' and n != 'p_error': + self.log.warning("'%s' not defined as a function", n) + if ((isinstance(v,types.FunctionType) and func_code(v).co_argcount == 1) or + (isinstance(v,types.MethodType) and func_code(v).co_argcount == 2)): + try: + doc = v.__doc__.split(" ") + if doc[1] == ':': + self.log.warning("%s:%d: Possible grammar rule '%s' defined without p_ prefix", + func_code(v).co_filename, func_code(v).co_firstlineno,n) + except Exception: + pass + + self.grammar = grammar + +# ----------------------------------------------------------------------------- +# yacc(module) +# +# Build a parser +# ----------------------------------------------------------------------------- + +def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, start=None, + check_recursion=1, optimize=0, write_tables=1, debugfile=debug_file,outputdir='', + debuglog=None, errorlog = None, picklefile=None): + + global parse # Reference to the parsing method of the last built parser + + # If pickling is enabled, table files are not created + + if picklefile: + write_tables = 0 + + if errorlog is None: + errorlog = PlyLogger(sys.stderr) + + # Get the module dictionary used for the parser + if module: + _items = [(k,getattr(module,k)) for k in dir(module)] + pdict = dict(_items) + else: + pdict = get_caller_module_dict(2) + + # Collect parser information from the dictionary + pinfo = ParserReflect(pdict,log=errorlog) + pinfo.get_all() + + if pinfo.error: + raise YaccError("Unable to build parser") + + # Check signature against table files (if any) + signature = pinfo.signature() + + # Read the tables + try: + lr = LRTable() + if picklefile: + read_signature = lr.read_pickle(picklefile) + else: + read_signature = lr.read_table(tabmodule) + if optimize or (read_signature == signature): + try: + lr.bind_callables(pinfo.pdict) + parser = LRParser(lr,pinfo.error_func) + parse = parser.parse + return parser + except Exception: + e = sys.exc_info()[1] + errorlog.warning("There was a problem loading the table file: %s", repr(e)) + except VersionError: + e = sys.exc_info() + errorlog.warning(str(e)) + except Exception: + pass + + if debuglog is None: + if debug: + debuglog = PlyLogger(open(debugfile,"w")) + else: + debuglog = NullLogger() + + debuglog.info("Created by PLY version %s (http://www.dabeaz.com/ply)", __version__) + + + errors = 0 + + # Validate the parser information + if pinfo.validate_all(): + raise YaccError("Unable to build parser") + + if not pinfo.error_func: + errorlog.warning("no p_error() function is defined") + + # Create a grammar object + grammar = Grammar(pinfo.tokens) + + # Set precedence level for terminals + for term, assoc, level in pinfo.preclist: + try: + grammar.set_precedence(term,assoc,level) + except GrammarError: + e = sys.exc_info()[1] + errorlog.warning("%s",str(e)) + + # Add productions to the grammar + for funcname, gram in pinfo.grammar: + file, line, prodname, syms = gram + try: + grammar.add_production(prodname,syms,funcname,file,line) + except GrammarError: + e = sys.exc_info()[1] + errorlog.error("%s",str(e)) + errors = 1 + + # Set the grammar start symbols + try: + if start is None: + grammar.set_start(pinfo.start) + else: + grammar.set_start(start) + except GrammarError: + e = sys.exc_info()[1] + errorlog.error(str(e)) + errors = 1 + + if errors: + raise YaccError("Unable to build parser") + + # Verify the grammar structure + undefined_symbols = grammar.undefined_symbols() + for sym, prod in undefined_symbols: + errorlog.error("%s:%d: Symbol '%s' used, but not defined as a token or a rule",prod.file,prod.line,sym) + errors = 1 + + unused_terminals = grammar.unused_terminals() + if unused_terminals: + debuglog.info("") + debuglog.info("Unused terminals:") + debuglog.info("") + for term in unused_terminals: + errorlog.warning("Token '%s' defined, but not used", term) + debuglog.info(" %s", term) + + # Print out all productions to the debug log + if debug: + debuglog.info("") + debuglog.info("Grammar") + debuglog.info("") + for n,p in enumerate(grammar.Productions): + debuglog.info("Rule %-5d %s", n, p) + + # Find unused non-terminals + unused_rules = grammar.unused_rules() + for prod in unused_rules: + errorlog.warning("%s:%d: Rule '%s' defined, but not used", prod.file, prod.line, prod.name) + + if len(unused_terminals) == 1: + errorlog.warning("There is 1 unused token") + if len(unused_terminals) > 1: + errorlog.warning("There are %d unused tokens", len(unused_terminals)) + + if len(unused_rules) == 1: + errorlog.warning("There is 1 unused rule") + if len(unused_rules) > 1: + errorlog.warning("There are %d unused rules", len(unused_rules)) + + if debug: + debuglog.info("") + debuglog.info("Terminals, with rules where they appear") + debuglog.info("") + terms = list(grammar.Terminals) + terms.sort() + for term in terms: + debuglog.info("%-20s : %s", term, " ".join([str(s) for s in grammar.Terminals[term]])) + + debuglog.info("") + debuglog.info("Nonterminals, with rules where they appear") + debuglog.info("") + nonterms = list(grammar.Nonterminals) + nonterms.sort() + for nonterm in nonterms: + debuglog.info("%-20s : %s", nonterm, " ".join([str(s) for s in grammar.Nonterminals[nonterm]])) + debuglog.info("") + + if check_recursion: + unreachable = grammar.find_unreachable() + for u in unreachable: + errorlog.warning("Symbol '%s' is unreachable",u) + + infinite = grammar.infinite_cycles() + for inf in infinite: + errorlog.error("Infinite recursion detected for symbol '%s'", inf) + errors = 1 + + unused_prec = grammar.unused_precedence() + for term, assoc in unused_prec: + errorlog.error("Precedence rule '%s' defined for unknown symbol '%s'", assoc, term) + errors = 1 + + if errors: + raise YaccError("Unable to build parser") + + # Run the LRGeneratedTable on the grammar + if debug: + errorlog.debug("Generating %s tables", method) + + lr = LRGeneratedTable(grammar,method,debuglog) + + if debug: + num_sr = len(lr.sr_conflicts) + + # Report shift/reduce and reduce/reduce conflicts + if num_sr == 1: + errorlog.warning("1 shift/reduce conflict") + elif num_sr > 1: + errorlog.warning("%d shift/reduce conflicts", num_sr) + + num_rr = len(lr.rr_conflicts) + if num_rr == 1: + errorlog.warning("1 reduce/reduce conflict") + elif num_rr > 1: + errorlog.warning("%d reduce/reduce conflicts", num_rr) + + # Write out conflicts to the output file + if debug and (lr.sr_conflicts or lr.rr_conflicts): + debuglog.warning("") + debuglog.warning("Conflicts:") + debuglog.warning("") + + for state, tok, resolution in lr.sr_conflicts: + debuglog.warning("shift/reduce conflict for %s in state %d resolved as %s", tok, state, resolution) + + already_reported = {} + for state, rule, rejected in lr.rr_conflicts: + if (state,id(rule),id(rejected)) in already_reported: + continue + debuglog.warning("reduce/reduce conflict in state %d resolved using rule (%s)", state, rule) + debuglog.warning("rejected rule (%s) in state %d", rejected,state) + errorlog.warning("reduce/reduce conflict in state %d resolved using rule (%s)", state, rule) + errorlog.warning("rejected rule (%s) in state %d", rejected, state) + already_reported[state,id(rule),id(rejected)] = 1 + + warned_never = [] + for state, rule, rejected in lr.rr_conflicts: + if not rejected.reduced and (rejected not in warned_never): + debuglog.warning("Rule (%s) is never reduced", rejected) + errorlog.warning("Rule (%s) is never reduced", rejected) + warned_never.append(rejected) + + # Write the table file if requested + if write_tables: + lr.write_table(tabmodule,outputdir,signature) + + # Write a pickled version of the tables + if picklefile: + lr.pickle_table(picklefile,signature) + + # Build the parser + lr.bind_callables(pinfo.pdict) + parser = LRParser(lr,pinfo.error_func) + + parse = parser.parse + return parser diff --git a/plugins/pycparser/pycparser/__init__.py b/plugins/pycparser/pycparser/__init__.py new file mode 100644 index 0000000..6219bb2 --- /dev/null +++ b/plugins/pycparser/pycparser/__init__.py @@ -0,0 +1,75 @@ +#----------------------------------------------------------------- +# pycparser: __init__.py +# +# This package file exports some convenience functions for +# interacting with pycparser +# +# Copyright (C) 2008-2009, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- + +__all__ = ['c_lexer', 'c_parser', 'c_ast'] +__version__ = '1.05' + +from subprocess import Popen, PIPE +from types import ListType + +from c_parser import CParser + + +def parse_file( filename, use_cpp=False, + cpp_path='cpp', cpp_args=''): + """ Parse a C file using pycparser. + + filename: + Name of the file you want to parse. + + use_cpp: + Set to True if you want to execute the C pre-processor + on the file prior to parsing it. + + cpp_path: + If use_cpp is True, this is the path to 'cpp' on your + system. If no path is provided, it attempts to just + execute 'cpp', so it must be in your PATH. + + cpp_args: + If use_cpp is True, set this to the command line + arguments strings to cpp. Be careful with quotes - + it's best to pass a raw string (r'') here. + For example: + r'-I../utils/fake_libc_include' + If several arguments are required, pass a list of + strings. + + When successful, an AST is returned. ParseError can be + thrown if the file doesn't parse successfully. + + Errors from cpp will be printed out. + """ + if use_cpp: + path_list = [cpp_path] + if isinstance(cpp_args, ListType): + path_list += cpp_args + elif cpp_args != '': + path_list += [cpp_args] + path_list += [filename] + + # Note the use of universal_newlines to treat all newlines + # as \n for Python's purpose + # + pipe = Popen( path_list, + stdout=PIPE, + universal_newlines=True) + text = pipe.communicate()[0] + else: + text = open(filename).read() + + parser = CParser() + return parser.parse(text, filename) + + +if __name__ == "__main__": + pass + + diff --git a/plugins/pycparser/pycparser/_ast_gen.py b/plugins/pycparser/pycparser/_ast_gen.py new file mode 100644 index 0000000..47ba148 --- /dev/null +++ b/plugins/pycparser/pycparser/_ast_gen.py @@ -0,0 +1,249 @@ +#----------------------------------------------------------------- +# _ast_gen.py +# +# Generates the AST Node classes from a specification given in +# a .yaml file +# +# The design of this module was inspired by astgen.py from the +# Python 2.5 code-base. +# +# Copyright (C) 2008-2009, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- + +import pprint +from string import Template + +import yaml + + +class ASTCodeGenerator(object): + def __init__(self, cfg_filename='_c_ast.yaml'): + """ Initialize the code generator from a configuration + file. + """ + self.cfg_filename = cfg_filename + cfg = yaml.load(open(cfg_filename).read()) + self.node_cfg = [NodeCfg(name, cfg[name]) for name in cfg] + + #~ pprint.pprint(self.node_cfg) + #~ print '' + + def generate(self, file=None): + """ Generates the code into file, an open file buffer. + """ + src = Template(_PROLOGUE_COMMENT).substitute( + cfg_filename=self.cfg_filename) + + src += _PROLOGUE_CODE + for node_cfg in self.node_cfg: + src += node_cfg.generate_source() + '\n\n' + + file.write(src) + + +class NodeCfg(object): + def __init__(self, name, contents): + self.name = name + self.all_entries = [] + self.attr = [] + self.child = [] + self.seq_child = [] + + for entry in contents: + clean_entry = entry.rstrip('*') + self.all_entries.append(clean_entry) + + if entry.endswith('**'): + self.seq_child.append(clean_entry) + elif entry.endswith('*'): + self.child.append(clean_entry) + else: + self.attr.append(entry) + + def generate_source(self): + src = self._gen_init() + src += '\n' + self._gen_children() + src += '\n' + self._gen_show() + return src + + def _gen_init(self): + src = "class %s(Node):\n" % self.name + + if self.all_entries: + args = ', '.join(self.all_entries) + arglist = '(self, %s, coord=None)' % args + else: + arglist = '(self, coord=None)' + + src += " def __init__%s:\n" % arglist + + for name in self.all_entries + ['coord']: + src += " self.%s = %s\n" % (name, name) + + return src + + def _gen_children(self): + src = ' def children(self):\n' + + if self.all_entries: + src += ' nodelist = []\n' + + template = ('' + + ' if self.%s is not None:' + + ' nodelist.%s(self.%s)\n') + + for child in self.child: + src += template % ( + child, 'append', child) + + for seq_child in self.seq_child: + src += template % ( + seq_child, 'extend', seq_child) + + src += ' return tuple(nodelist)\n' + else: + src += ' return ()\n' + + return src + + def _gen_show(self): + src = ' def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):\n' + src += " lead = ' ' * offset\n" + + src += " buf.write(lead + '%s: ')\n\n" % self.name + + if self.attr: + src += " if attrnames:\n" + src += " attrstr = ', '.join('%s=%s' % nv for nv in [" + src += ', '.join('("%s", repr(%s))' % (nv, 'self.%s' % nv) for nv in self.attr) + src += '])\n' + src += " else:\n" + src += " attrstr = ', '.join('%s' % v for v in [" + src += ', '.join('self.%s' % v for v in self.attr) + src += '])\n' + src += " buf.write(attrstr)\n\n" + + src += " if showcoord:\n" + src += " buf.write(' (at %s)' % self.coord)\n" + src += " buf.write('\\n')\n\n" + + src += " for c in self.children():\n" + src += " c.show(buf, offset + 2, attrnames, showcoord)\n" + + return src + + +_PROLOGUE_COMMENT = \ +r'''#----------------------------------------------------------------- +# ** ATTENTION ** +# This code was automatically generated from the file: +# $cfg_filename +# +# Do not modify it directly. Modify the configuration file and +# run the generator again. +# ** ** *** ** ** +# +# pycparser: c_ast.py +# +# AST Node classes. +# +# Copyright (C) 2008, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- + +''' + +_PROLOGUE_CODE = r''' +import sys + + +class Node(object): + """ Abstract base class for AST nodes. + """ + def children(self): + """ A sequence of all children that are Nodes + """ + pass + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + """ Pretty print the Node and all its attributes and + children (recursively) to a buffer. + + file: + Open IO buffer into which the Node is printed. + + offset: + Initial offset (amount of leading spaces) + + attrnames: + True if you want to see the attribute names in + name=value pairs. False to only see the values. + + showcoord: + Do you want the coordinates of each Node to be + displayed. + """ + pass + + +class NodeVisitor(object): + """ A base NodeVisitor class for visiting c_ast nodes. + Subclass it and define your own visit_XXX methods, where + XXX is the class name you want to visit with these + methods. + + For example: + + class ConstantVisitor(NodeVisitor): + def __init__(self): + self.values = [] + + def visit_Constant(self, node): + self.values.append(node.value) + + Creates a list of values of all the constant nodes + encountered below the given node. To use it: + + cv = ConstantVisitor() + cv.visit(node) + + Notes: + + * generic_visit() will be called for AST nodes for which + no visit_XXX method was defined. + * The children of nodes for which a visit_XXX was + defined will not be visited - if you need this, call + generic_visit() on the node. + You can use: + NodeVisitor.generic_visit(self, node) + * Modeled after Python's own AST visiting facilities + (the ast module of Python 3.0) + """ + def visit(self, node): + """ Visit a node. + """ + method = 'visit_' + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + return visitor(node) + + def generic_visit(self, node): + """ Called if no explicit visitor function exists for a + node. Implements preorder visiting of the node. + """ + for c in node.children(): + self.visit(c) + + +''' + + + +if __name__ == "__main__": + import sys + + ast_gen = ASTCodeGenerator('_c_ast.yaml') + ast_gen.generate(open('c_ast.py', 'w')) + + + diff --git a/plugins/pycparser/pycparser/_build_tables.py b/plugins/pycparser/pycparser/_build_tables.py new file mode 100644 index 0000000..0f02387 --- /dev/null +++ b/plugins/pycparser/pycparser/_build_tables.py @@ -0,0 +1,31 @@ +#----------------------------------------------------------------- +# pycparser: _build_tables.py +# +# A dummy for generating the lexing/parsing tables and and +# compiling them into .pyc for faster execution in optimized mode. +# Also generates AST code from the _c_ast.yaml configuration file. +# +# Copyright (C) 2008, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- + +# Generate c_ast.py +# +from _ast_gen import ASTCodeGenerator +ast_gen = ASTCodeGenerator('_c_ast.yaml') +ast_gen.generate(open('c_ast.py', 'w')) + +import c_parser + +# Generates the tables +# +c_parser.CParser( + lex_optimize=True, + yacc_debug=False, + yacc_optimize=True) + +# Load to compile into .pyc +# +import lextab +import yacctab +import c_ast diff --git a/plugins/pycparser/pycparser/_c_ast.yaml b/plugins/pycparser/pycparser/_c_ast.yaml new file mode 100644 index 0000000..c954e38 --- /dev/null +++ b/plugins/pycparser/pycparser/_c_ast.yaml @@ -0,0 +1,164 @@ +#----------------------------------------------------------------- +# pycparser: _c_ast_gen.yaml +# +# Defines the AST Node classes used in pycparser. +# +# Each entry is a Node sub-class name, listing the attributes +# and child nodes of the class: +# * - a child node +# ** - a sequence of child nodes +# - an attribute +# +# Copyright (C) 2008-2009, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- + + +ArrayDecl: [type*, dim*] + +ArrayRef: [name*, subscript*] + +# op: =, +=, /= etc. +# +Assignment: [op, lvalue*, rvalue*] + +BinaryOp: [op, left*, right*] + +Break: [] + +Case: [expr*, stmt*] + +Cast: [to_type*, expr*] + +# Compound statement: { declarations... statements...} +# +Compound: [decls**, stmts**] + +# type: int, char, float, etc. see CLexer for constant token types +# +Constant: [type, value] + +Continue: [] + +# name: the variable being declared +# quals: list of qualifiers (const, volatile) +# storage: list of storage specifiers (extern, register, etc.) +# type: declaration type (probably nested with all the modifiers) +# init: initialization value, or None +# bitsize: bit field size, or None +# +Decl: [name, quals, storage, type*, init*, bitsize*] + +Default: [stmt*] + +DoWhile: [cond*, stmt*] + +# Represents the ellipsis (...) parameter in a function +# declaration +# +EllipsisParam: [] + +# Enumeration type specifier +# name: an optional ID +# values: an EnumeratorList +# +Enum: [name, values*] + +# A name/value pair for enumeration values +# +Enumerator: [name, value*] + +# A list of enumerators +# +EnumeratorList: [enumerators**] + +# a list of comma separated expressions +# +ExprList: [exprs**] + +# This is the top of the AST, representing a single C file (a +# translation unit in K&R jargon). It contains a list of +# "external-declaration"s, which is either declarations (Decl), +# Typedef or function definitions (FuncDef). +# +FileAST: [ext**] + +# for (init; cond; next) stmt +# +For: [init*, cond*, next*, stmt*] + +# name: Id +# args: ExprList +# +FuncCall: [name*, args*] + +# type (args) +# +FuncDecl: [args*, type*] + +# Function definition: a declarator for the function name and +# a body, which is a compound statement. +# There's an optional list of parameter declarations for old +# K&R-style definitions +# +FuncDef: [decl*, param_decls**, body*] + +Goto: [name] + +ID: [name] + +# Holder for types that are a simple identifier (e.g. the built +# ins void, char etc. and typedef-defined types) +# +IdentifierType: [names] + +If: [cond*, iftrue*, iffalse*] + +Label: [name, stmt*] + +# a list of comma separated function parameter declarations +# +ParamList: [params**] + +PtrDecl: [quals, type*] + +Return: [expr*] + +# name: struct tag name +# decls: declaration of members +# +Struct: [name, decls**] + +# type: . or -> +# name.field or name->field +# +StructRef: [name*, type, field*] + +Switch: [cond*, stmt*] + +# cond ? iftrue : iffalse +# +TernaryOp: [cond*, iftrue*, iffalse*] + +# A base type declaration +# +TypeDecl: [declname, quals, type*] + +# A typedef declaration. +# Very similar to Decl, but without some attributes +# +Typedef: [name, quals, storage, type*] + +Typename: [quals, type*] + +UnaryOp: [op, expr*] + +# name: union tag name +# decls: declaration of members +# +Union: [name, decls**] + +While: [cond*, stmt*] + + + diff --git a/plugins/pycparser/pycparser/c_ast.py b/plugins/pycparser/pycparser/c_ast.py new file mode 100644 index 0000000..90cfb79 --- /dev/null +++ b/plugins/pycparser/pycparser/c_ast.py @@ -0,0 +1,1163 @@ +#----------------------------------------------------------------- +# ** ATTENTION ** +# This code was automatically generated from the file: +# _c_ast.yaml +# +# Do not modify it directly. Modify the configuration file and +# run the generator again. +# ** ** *** ** ** +# +# pycparser: c_ast.py +# +# AST Node classes. +# +# Copyright (C) 2008, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- + + +import sys + + +class Node(object): + """ Abstract base class for AST nodes. + """ + def children(self): + """ A sequence of all children that are Nodes + """ + pass + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + """ Pretty print the Node and all its attributes and + children (recursively) to a buffer. + + file: + Open IO buffer into which the Node is printed. + + offset: + Initial offset (amount of leading spaces) + + attrnames: + True if you want to see the attribute names in + name=value pairs. False to only see the values. + + showcoord: + Do you want the coordinates of each Node to be + displayed. + """ + pass + + +class NodeVisitor(object): + """ A base NodeVisitor class for visiting c_ast nodes. + Subclass it and define your own visit_XXX methods, where + XXX is the class name you want to visit with these + methods. + + For example: + + class ConstantVisitor(NodeVisitor): + def __init__(self): + self.values = [] + + def visit_Constant(self, node): + self.values.append(node.value) + + Creates a list of values of all the constant nodes + encountered below the given node. To use it: + + cv = ConstantVisitor() + cv.visit(node) + + Notes: + + * generic_visit() will be called for AST nodes for which + no visit_XXX method was defined. + * The children of nodes for which a visit_XXX was + defined will not be visited - if you need this, call + generic_visit() on the node. + You can use: + NodeVisitor.generic_visit(self, node) + * Modeled after Python's own AST visiting facilities + (the ast module of Python 3.0) + """ + def visit(self, node): + """ Visit a node. + """ + method = 'visit_' + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + return visitor(node) + + def generic_visit(self, node): + """ Called if no explicit visitor function exists for a + node. Implements preorder visiting of the node. + """ + for c in node.children(): + self.visit(c) + + +class Typedef(Node): + def __init__(self, name, quals, storage, type, coord=None): + self.name = name + self.quals = quals + self.storage = storage + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Typedef: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name)), ("quals", repr(self.quals)), ("storage", repr(self.storage))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name, self.quals, self.storage]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Struct(Node): + def __init__(self, name, decls, coord=None): + self.name = name + self.decls = decls + self.coord = coord + + def children(self): + nodelist = [] + if self.decls is not None: nodelist.extend(self.decls) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Struct: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class FuncCall(Node): + def __init__(self, name, args, coord=None): + self.name = name + self.args = args + self.coord = coord + + def children(self): + nodelist = [] + if self.name is not None: nodelist.append(self.name) + if self.args is not None: nodelist.append(self.args) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'FuncCall: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class UnaryOp(Node): + def __init__(self, op, expr, coord=None): + self.op = op + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: nodelist.append(self.expr) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'UnaryOp: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))]) + else: + attrstr = ', '.join('%s' % v for v in [self.op]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Union(Node): + def __init__(self, name, decls, coord=None): + self.name = name + self.decls = decls + self.coord = coord + + def children(self): + nodelist = [] + if self.decls is not None: nodelist.extend(self.decls) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Union: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class TernaryOp(Node): + def __init__(self, cond, iftrue, iffalse, coord=None): + self.cond = cond + self.iftrue = iftrue + self.iffalse = iffalse + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(self.cond) + if self.iftrue is not None: nodelist.append(self.iftrue) + if self.iffalse is not None: nodelist.append(self.iffalse) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'TernaryOp: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Label(Node): + def __init__(self, name, stmt, coord=None): + self.name = name + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Label: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class IdentifierType(Node): + def __init__(self, names, coord=None): + self.names = names + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'IdentifierType: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("names", repr(self.names))]) + else: + attrstr = ', '.join('%s' % v for v in [self.names]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class FuncDef(Node): + def __init__(self, decl, param_decls, body, coord=None): + self.decl = decl + self.param_decls = param_decls + self.body = body + self.coord = coord + + def children(self): + nodelist = [] + if self.decl is not None: nodelist.append(self.decl) + if self.body is not None: nodelist.append(self.body) + if self.param_decls is not None: nodelist.extend(self.param_decls) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'FuncDef: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Enumerator(Node): + def __init__(self, name, value, coord=None): + self.name = name + self.value = value + self.coord = coord + + def children(self): + nodelist = [] + if self.value is not None: nodelist.append(self.value) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Enumerator: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class For(Node): + def __init__(self, init, cond, next, stmt, coord=None): + self.init = init + self.cond = cond + self.next = next + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.init is not None: nodelist.append(self.init) + if self.cond is not None: nodelist.append(self.cond) + if self.next is not None: nodelist.append(self.next) + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'For: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Assignment(Node): + def __init__(self, op, lvalue, rvalue, coord=None): + self.op = op + self.lvalue = lvalue + self.rvalue = rvalue + self.coord = coord + + def children(self): + nodelist = [] + if self.lvalue is not None: nodelist.append(self.lvalue) + if self.rvalue is not None: nodelist.append(self.rvalue) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Assignment: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))]) + else: + attrstr = ', '.join('%s' % v for v in [self.op]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class FuncDecl(Node): + def __init__(self, args, type, coord=None): + self.args = args + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.args is not None: nodelist.append(self.args) + if self.type is not None: nodelist.append(self.type) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'FuncDecl: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Enum(Node): + def __init__(self, name, values, coord=None): + self.name = name + self.values = values + self.coord = coord + + def children(self): + nodelist = [] + if self.values is not None: nodelist.append(self.values) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Enum: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class ExprList(Node): + def __init__(self, exprs, coord=None): + self.exprs = exprs + self.coord = coord + + def children(self): + nodelist = [] + if self.exprs is not None: nodelist.extend(self.exprs) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'ExprList: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Break(Node): + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Break: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class DoWhile(Node): + def __init__(self, cond, stmt, coord=None): + self.cond = cond + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(self.cond) + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'DoWhile: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class StructRef(Node): + def __init__(self, name, type, field, coord=None): + self.name = name + self.type = type + self.field = field + self.coord = coord + + def children(self): + nodelist = [] + if self.name is not None: nodelist.append(self.name) + if self.field is not None: nodelist.append(self.field) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'StructRef: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("type", repr(self.type))]) + else: + attrstr = ', '.join('%s' % v for v in [self.type]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class BinaryOp(Node): + def __init__(self, op, left, right, coord=None): + self.op = op + self.left = left + self.right = right + self.coord = coord + + def children(self): + nodelist = [] + if self.left is not None: nodelist.append(self.left) + if self.right is not None: nodelist.append(self.right) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'BinaryOp: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))]) + else: + attrstr = ', '.join('%s' % v for v in [self.op]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Compound(Node): + def __init__(self, decls, stmts, coord=None): + self.decls = decls + self.stmts = stmts + self.coord = coord + + def children(self): + nodelist = [] + if self.decls is not None: nodelist.extend(self.decls) + if self.stmts is not None: nodelist.extend(self.stmts) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Compound: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class ArrayDecl(Node): + def __init__(self, type, dim, coord=None): + self.type = type + self.dim = dim + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + if self.dim is not None: nodelist.append(self.dim) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'ArrayDecl: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Case(Node): + def __init__(self, expr, stmt, coord=None): + self.expr = expr + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: nodelist.append(self.expr) + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Case: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Cast(Node): + def __init__(self, to_type, expr, coord=None): + self.to_type = to_type + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.to_type is not None: nodelist.append(self.to_type) + if self.expr is not None: nodelist.append(self.expr) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Cast: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class TypeDecl(Node): + def __init__(self, declname, quals, type, coord=None): + self.declname = declname + self.quals = quals + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'TypeDecl: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("declname", repr(self.declname)), ("quals", repr(self.quals))]) + else: + attrstr = ', '.join('%s' % v for v in [self.declname, self.quals]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Default(Node): + def __init__(self, stmt, coord=None): + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Default: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class PtrDecl(Node): + def __init__(self, quals, type, coord=None): + self.quals = quals + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'PtrDecl: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("quals", repr(self.quals))]) + else: + attrstr = ', '.join('%s' % v for v in [self.quals]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Switch(Node): + def __init__(self, cond, stmt, coord=None): + self.cond = cond + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(self.cond) + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Switch: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Continue(Node): + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Continue: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class ParamList(Node): + def __init__(self, params, coord=None): + self.params = params + self.coord = coord + + def children(self): + nodelist = [] + if self.params is not None: nodelist.extend(self.params) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'ParamList: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Return(Node): + def __init__(self, expr, coord=None): + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: nodelist.append(self.expr) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Return: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Typename(Node): + def __init__(self, quals, type, coord=None): + self.quals = quals + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Typename: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("quals", repr(self.quals))]) + else: + attrstr = ', '.join('%s' % v for v in [self.quals]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class ID(Node): + def __init__(self, name, coord=None): + self.name = name + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'ID: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Goto(Node): + def __init__(self, name, coord=None): + self.name = name + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Goto: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Decl(Node): + def __init__(self, name, quals, storage, type, init, bitsize, coord=None): + self.name = name + self.quals = quals + self.storage = storage + self.type = type + self.init = init + self.bitsize = bitsize + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + if self.init is not None: nodelist.append(self.init) + if self.bitsize is not None: nodelist.append(self.bitsize) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Decl: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name)), ("quals", repr(self.quals)), ("storage", repr(self.storage))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name, self.quals, self.storage]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Constant(Node): + def __init__(self, type, value, coord=None): + self.type = type + self.value = value + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Constant: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("type", repr(self.type)), ("value", repr(self.value))]) + else: + attrstr = ', '.join('%s' % v for v in [self.type, self.value]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class FileAST(Node): + def __init__(self, ext, coord=None): + self.ext = ext + self.coord = coord + + def children(self): + nodelist = [] + if self.ext is not None: nodelist.extend(self.ext) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'FileAST: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class ArrayRef(Node): + def __init__(self, name, subscript, coord=None): + self.name = name + self.subscript = subscript + self.coord = coord + + def children(self): + nodelist = [] + if self.name is not None: nodelist.append(self.name) + if self.subscript is not None: nodelist.append(self.subscript) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'ArrayRef: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class While(Node): + def __init__(self, cond, stmt, coord=None): + self.cond = cond + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(self.cond) + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'While: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class EnumeratorList(Node): + def __init__(self, enumerators, coord=None): + self.enumerators = enumerators + self.coord = coord + + def children(self): + nodelist = [] + if self.enumerators is not None: nodelist.extend(self.enumerators) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'EnumeratorList: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class EllipsisParam(Node): + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'EllipsisParam: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class If(Node): + def __init__(self, cond, iftrue, iffalse, coord=None): + self.cond = cond + self.iftrue = iftrue + self.iffalse = iffalse + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(self.cond) + if self.iftrue is not None: nodelist.append(self.iftrue) + if self.iffalse is not None: nodelist.append(self.iffalse) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'If: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + diff --git a/plugins/pycparser/pycparser/c_lexer.py b/plugins/pycparser/pycparser/c_lexer.py new file mode 100644 index 0000000..28638df --- /dev/null +++ b/plugins/pycparser/pycparser/c_lexer.py @@ -0,0 +1,443 @@ +#----------------------------------------------------------------- +# pycparser: clex.py +# +# CLexer class: lexer for the C language +# +# Copyright (C) 2008, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- + +import re +import sys + +import ply.lex +from ply.lex import TOKEN + + +class CLexer(object): + """ A lexer for the C language. After building it, set the + input text with input(), and call token() to get new + tokens. + + The public attribute filename can be set to an initial + filaneme, but the lexer will update it upon #line + directives. + """ + def __init__(self, error_func, type_lookup_func): + """ Create a new Lexer. + + error_func: + An error function. Will be called with an error + message, line and column as arguments, in case of + an error during lexing. + + type_lookup_func: + A type lookup function. Given a string, it must + return True IFF this string is a name of a type + that was defined with a typedef earlier. + """ + self.error_func = error_func + self.type_lookup_func = type_lookup_func + self.filename = '' + + # Allow either "# line" or "# " to support GCC's + # cpp output + # + self.line_pattern = re.compile('([ \t]*line\W)|([ \t]*\d+)') + + def build(self, **kwargs): + """ Builds the lexer from the specification. Must be + called after the lexer object is created. + + This method exists separately, because the PLY + manual warns against calling lex.lex inside + __init__ + """ + self.lexer = ply.lex.lex(object=self, **kwargs) + + def reset_lineno(self): + """ Resets the internal line number counter of the lexer. + """ + self.lexer.lineno = 1 + + def input(self, text): + self.lexer.input(text) + + def token(self): + g = self.lexer.token() + return g + + ######################-- PRIVATE --###################### + + ## + ## Internal auxiliary methods + ## + def _error(self, msg, token): + location = self._make_tok_location(token) + self.error_func(msg, location[0], location[1]) + self.lexer.skip(1) + + def _find_tok_column(self, token): + i = token.lexpos + while i > 0: + if self.lexer.lexdata[i] == '\n': break + i -= 1 + return (token.lexpos - i) + 1 + + def _make_tok_location(self, token): + return (token.lineno, self._find_tok_column(token)) + + ## + ## Reserved keywords + ## + keywords = ( + 'AUTO', 'BREAK', 'CASE', 'CHAR', 'CONST', 'CONTINUE', + 'DEFAULT', 'DO', 'DOUBLE', 'ELSE', 'ENUM', 'EXTERN', + 'FLOAT', 'FOR', 'GOTO', 'IF', 'INT', 'LONG', 'REGISTER', + 'RETURN', 'SHORT', 'SIGNED', 'SIZEOF', 'STATIC', 'STRUCT', + 'SWITCH', 'TYPEDEF', 'UNION', 'UNSIGNED', 'VOID', + 'VOLATILE', 'WHILE', + ) + + keyword_map = {} + for r in keywords: + keyword_map[r.lower()] = r + + ## + ## All the tokens recognized by the lexer + ## + tokens = keywords + ( + # Identifiers + 'ID', + + # Type identifiers (identifiers previously defined as + # types with typedef) + 'TYPEID', + + # constants + 'INT_CONST_DEC', 'INT_CONST_OCT', 'INT_CONST_HEX', + 'FLOAT_CONST', + 'CHAR_CONST', + 'WCHAR_CONST', + + # String literals + 'STRING_LITERAL', + 'WSTRING_LITERAL', + + # Operators + 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MOD', + 'OR', 'AND', 'NOT', 'XOR', 'LSHIFT', 'RSHIFT', + 'LOR', 'LAND', 'LNOT', + 'LT', 'LE', 'GT', 'GE', 'EQ', 'NE', + + # Assignment + 'EQUALS', 'TIMESEQUAL', 'DIVEQUAL', 'MODEQUAL', + 'PLUSEQUAL', 'MINUSEQUAL', + 'LSHIFTEQUAL','RSHIFTEQUAL', 'ANDEQUAL', 'XOREQUAL', + 'OREQUAL', + + # Increment/decrement + 'PLUSPLUS', 'MINUSMINUS', + + # Structure dereference (->) + 'ARROW', + + # Conditional operator (?) + 'CONDOP', + + # Delimeters + 'LPAREN', 'RPAREN', # ( ) + 'LBRACKET', 'RBRACKET', # [ ] + 'LBRACE', 'RBRACE', # { } + 'COMMA', 'PERIOD', # . , + 'SEMI', 'COLON', # ; : + + # Ellipsis (...) + 'ELLIPSIS', + + # pre-processor + 'PPHASH', # '#' + ) + + ## + ## Regexes for use in tokens + ## + ## + + # valid C identifiers (K&R2: A.2.3) + identifier = r'[a-zA-Z_][0-9a-zA-Z_]*' + + # integer constants (K&R2: A.2.5.1) + integer_suffix_opt = r'(([uU][lL])|([lL][uU])|[uU]|[lL])?' + decimal_constant = '(0'+integer_suffix_opt+')|([1-9][0-9]*'+integer_suffix_opt+')' + octal_constant = '0[0-7]*'+integer_suffix_opt + hex_constant = '0[xX][0-9a-fA-F]+'+integer_suffix_opt + + bad_octal_constant = '0[0-7]*[89]' + + # character constants (K&R2: A.2.5.2) + # Note: a-zA-Z are allowed as escape chars to support #line + # directives with Windows paths as filenames (\dir\file...) + # + simple_escape = r"""([a-zA-Z\\?'"])""" + octal_escape = r"""([0-7]{1,3})""" + hex_escape = r"""(x[0-9a-fA-F]+)""" + bad_escape = r"""([\\][^a-zA-Z\\?'"x0-7])""" + + escape_sequence = r"""(\\("""+simple_escape+'|'+octal_escape+'|'+hex_escape+'))' + cconst_char = r"""([^'\\\n]|"""+escape_sequence+')' + char_const = "'"+cconst_char+"'" + wchar_const = 'L'+char_const + unmatched_quote = "('"+cconst_char+"*\\n)|('"+cconst_char+"*$)" + bad_char_const = r"""('"""+cconst_char+"""[^'\n]+')|('')|('"""+bad_escape+r"""[^'\n]*')""" + + # string literals (K&R2: A.2.6) + string_char = r"""([^"\\\n]|"""+escape_sequence+')' + string_literal = '"'+string_char+'*"' + wstring_literal = 'L'+string_literal + bad_string_literal = '"'+string_char+'*'+bad_escape+string_char+'*"' + + # floating constants (K&R2: A.2.5.3) + exponent_part = r"""([eE][-+]?[0-9]+)""" + fractional_constant = r"""([0-9]*\.[0-9]+)|([0-9]+\.)""" + floating_constant = '(((('+fractional_constant+')'+exponent_part+'?)|([0-9]+'+exponent_part+'))[FfLl]?)' + + ## + ## Lexer states + ## + states = ( + # ppline: preprocessor line directives + # + ('ppline', 'exclusive'), + ) + + def t_PPHASH(self, t): + r'[ \t]*\#' + m = self.line_pattern.match( + t.lexer.lexdata, pos=t.lexer.lexpos) + + if m: + t.lexer.begin('ppline') + self.pp_line = self.pp_filename = None + #~ print "ppline starts on line %s" % t.lexer.lineno + else: + t.type = 'PPHASH' + return t + + ## + ## Rules for the ppline state + ## + @TOKEN(string_literal) + def t_ppline_FILENAME(self, t): + if self.pp_line is None: + self._error('filename before line number in #line', t) + else: + self.pp_filename = t.value.lstrip('"').rstrip('"') + #~ print "PP got filename: ", self.pp_filename + + @TOKEN(decimal_constant) + def t_ppline_LINE_NUMBER(self, t): + if self.pp_line is None: + self.pp_line = t.value + else: + # Ignore: GCC's cpp sometimes inserts a numeric flag + # after the file name + pass + + def t_ppline_NEWLINE(self, t): + r'\n' + + if self.pp_line is None: + self._error('line number missing in #line', t) + else: + self.lexer.lineno = int(self.pp_line) + + if self.pp_filename is not None: + self.filename = self.pp_filename + + t.lexer.begin('INITIAL') + + def t_ppline_PPLINE(self, t): + r'line' + pass + + t_ppline_ignore = ' \t' + + def t_ppline_error(self, t): + msg = 'invalid #line directive' + self._error(msg, t) + + ## + ## Rules for the normal state + ## + t_ignore = ' \t' + + # Newlines + def t_NEWLINE(self, t): + r'\n+' + t.lexer.lineno += t.value.count("\n") + + # Operators + t_PLUS = r'\+' + t_MINUS = r'-' + t_TIMES = r'\*' + t_DIVIDE = r'/' + t_MOD = r'%' + t_OR = r'\|' + t_AND = r'&' + t_NOT = r'~' + t_XOR = r'\^' + t_LSHIFT = r'<<' + t_RSHIFT = r'>>' + t_LOR = r'\|\|' + t_LAND = r'&&' + t_LNOT = r'!' + t_LT = r'<' + t_GT = r'>' + t_LE = r'<=' + t_GE = r'>=' + t_EQ = r'==' + t_NE = r'!=' + + # Assignment operators + t_EQUALS = r'=' + t_TIMESEQUAL = r'\*=' + t_DIVEQUAL = r'/=' + t_MODEQUAL = r'%=' + t_PLUSEQUAL = r'\+=' + t_MINUSEQUAL = r'-=' + t_LSHIFTEQUAL = r'<<=' + t_RSHIFTEQUAL = r'>>=' + t_ANDEQUAL = r'&=' + t_OREQUAL = r'\|=' + t_XOREQUAL = r'^=' + + # Increment/decrement + t_PLUSPLUS = r'\+\+' + t_MINUSMINUS = r'--' + + # -> + t_ARROW = r'->' + + # ? + t_CONDOP = r'\?' + + # Delimeters + t_LPAREN = r'\(' + t_RPAREN = r'\)' + t_LBRACKET = r'\[' + t_RBRACKET = r'\]' + t_LBRACE = r'\{' + t_RBRACE = r'\}' + t_COMMA = r',' + t_PERIOD = r'\.' + t_SEMI = r';' + t_COLON = r':' + t_ELLIPSIS = r'\.\.\.' + + t_STRING_LITERAL = string_literal + + # The following floating and integer constants are defined as + # functions to impose a strict order (otherwise, decimal + # is placed before the others because its regex is longer, + # and this is bad) + # + @TOKEN(floating_constant) + def t_FLOAT_CONST(self, t): + return t + + @TOKEN(hex_constant) + def t_INT_CONST_HEX(self, t): + return t + + @TOKEN(bad_octal_constant) + def t_BAD_CONST_OCT(self, t): + msg = "Invalid octal constant" + self._error(msg, t) + + @TOKEN(octal_constant) + def t_INT_CONST_OCT(self, t): + return t + + @TOKEN(decimal_constant) + def t_INT_CONST_DEC(self, t): + return t + + # Must come before bad_char_const, to prevent it from + # catching valid char constants as invalid + # + @TOKEN(char_const) + def t_CHAR_CONST(self, t): + return t + + @TOKEN(wchar_const) + def t_WCHAR_CONST(self, t): + return t + + @TOKEN(unmatched_quote) + def t_UNMATCHED_QUOTE(self, t): + msg = "Unmatched '" + self._error(msg, t) + + @TOKEN(bad_char_const) + def t_BAD_CHAR_CONST(self, t): + msg = "Invalid char constant %s" % t.value + self._error(msg, t) + + @TOKEN(wstring_literal) + def t_WSTRING_LITERAL(self, t): + return t + + # unmatched string literals are caught by the preprocessor + + @TOKEN(bad_string_literal) + def t_BAD_STRING_LITERAL(self, t): + msg = "String contains invalid escape code" + self._error(msg, t) + + @TOKEN(identifier) + def t_ID(self, t): + t.type = self.keyword_map.get(t.value, "ID") + + if t.type == 'ID' and self.type_lookup_func(t.value): + t.type = "TYPEID" + + return t + + def t_error(self, t): + msg = 'Illegal character %s' % repr(t.value[0]) + self._error(msg, t) + + +if __name__ == "__main__": + filename = '../zp.c' + text = open(filename).read() + + #~ text = '"'+r"""ka \p ka"""+'"' + text = r""" + 546 + #line 66 "kwas\df.h" + id 4 + # 5 + dsf + """ + + def errfoo(msg, a, b): + print msg + sys.exit() + + def typelookup(namd): + return False + + clex = CLexer(errfoo, typelookup) + clex.build() + clex.input(text) + + while 1: + tok = clex.token() + if not tok: break + + #~ print type(tok) + print "-", tok.value, tok.type, tok.lineno, clex.filename, tok.lexpos + + diff --git a/plugins/pycparser/pycparser/c_parser.py b/plugins/pycparser/pycparser/c_parser.py new file mode 100644 index 0000000..6c03660 --- /dev/null +++ b/plugins/pycparser/pycparser/c_parser.py @@ -0,0 +1,1259 @@ +#----------------------------------------------------------------- +# pycparser: cparse.py +# +# CParser class: Parser and AST builder for the C language +# +# Copyright (C) 2008, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- + +import re +import sys +from types import StringType + +import ply.yacc + +import c_ast +from c_lexer import CLexer +from plyparser import PLYParser, Coord, ParseError + + +class CParser(PLYParser): + def __init__( + self, + lex_optimize=True, + lextab='pycparser.lextab', + yacc_optimize=True, + yacctab='pycparser.yacctab', + yacc_debug=False): + """ Create a new CParser. + + Some arguments for controlling the debug/optimization + level of the parser are provided. The defaults are + tuned for release/performance mode. + The simple rules for using them are: + *) When tweaking CParser/CLexer, set these to False + *) When releasing a stable parser, set to True + + lex_optimize: + Set to False when you're modifying the lexer. + Otherwise, changes in the lexer won't be used, if + some lextab.py file exists. + When releasing with a stable lexer, set to True + to save the re-generation of the lexer table on + each run. + + lextab: + Points to the lex table that's used for optimized + mode. Only if you're modifying the lexer and want + some tests to avoid re-generating the table, make + this point to a local lex table file (that's been + earlier generated with lex_optimize=True) + + yacc_optimize: + Set to False when you're modifying the parser. + Otherwise, changes in the parser won't be used, if + some parsetab.py file exists. + When releasing with a stable parser, set to True + to save the re-generation of the parser table on + each run. + + yacctab: + Points to the yacc table that's used for optimized + mode. Only if you're modifying the parser, make + this point to a local yacc table file + + yacc_debug: + Generate a parser.out file that explains how yacc + built the parsing table from the grammar. + """ + self.clex = CLexer( + error_func=self._lex_error_func, + type_lookup_func=self._lex_type_lookup_func) + + self.clex.build( + optimize=lex_optimize, + lextab=lextab) + self.tokens = self.clex.tokens + + rules_with_opt = [ + 'abstract_declarator', + 'constant_expression', + 'declaration_list', + 'declaration_specifiers', + 'expression', + 'identifier_list', + 'init_declarator_list', + 'parameter_type_list', + 'specifier_qualifier_list', + 'statement_list', + 'type_qualifier_list', + ] + + for rule in rules_with_opt: + self._create_opt_rule(rule) + + self.cparser = ply.yacc.yacc( + module=self, + start='translation_unit', + debug=yacc_debug, + optimize=yacc_optimize, + tabmodule=yacctab) + + # A table of identifiers defined as typedef types during + # parsing. + # + self.typedef_table = set([]) + + def parse(self, text, filename='', debuglevel=0): + """ Parses C code and returns an AST. + + text: + A string containing the C source code + + filename: + Name of the file being parsed (for meaningful + error messages) + + debuglevel: + Debug level to yacc + """ + self.clex.filename = filename + self.clex.reset_lineno() + self.typedef_table = set([]) + return self.cparser.parse(text, lexer=self.clex, debug=debuglevel) + + ######################-- PRIVATE --###################### + + def _lex_error_func(self, msg, line, column): + self._parse_error(msg, self._coord(line, column)) + + def _lex_type_lookup_func(self, name): + """ Looks up types that were previously defined with + typedef. + Passed to the lexer for recognizing identifiers that + are types. + """ + return name in self.typedef_table + + def _add_typedef_type(self, name): + """ Adds names that were defined as new types with + typedef. + """ + self.typedef_table.add(name) + + # To understand what's going on here, read sections A.8.5 and + # A.8.6 of K&R2 very carefully. + # + # A C type consists of a basic type declaration, with a list + # of modifiers. For example: + # + # int *c[5]; + # + # The basic declaration here is 'int x', and the pointer and + # the array are the modifiers. + # + # Basic declarations are represented by TypeDecl (from module + # c_ast) and the modifiers are FuncDecl, PtrDecl and + # ArrayDecl. + # + # The standard states that whenever a new modifier is parsed, + # it should be added to the end of the list of modifiers. For + # example: + # + # K&R2 A.8.6.2: Array Declarators + # + # In a declaration T D where D has the form + # D1 [constant-expression-opt] + # and the type of the identifier in the declaration T D1 is + # "type-modifier T", the type of the + # identifier of D is "type-modifier array of T" + # + # This is what this method does. The declarator it receives + # can be a list of declarators ending with TypeDecl. It + # tacks the modifier to the end of this list, just before + # the TypeDecl. + # + # Additionally, the modifier may be a list itself. This is + # useful for pointers, that can come as a chain from the rule + # p_pointer. In this case, the whole modifier list is spliced + # into the new location. + # + def _type_modify_decl(self, decl, modifier): + """ Tacks a type modifier on a declarator, and returns + the modified declarator. + + Note: the declarator and modifier may be modified + """ + #~ print '****' + #~ decl.show(offset=3) + #~ modifier.show(offset=3) + #~ print '****' + + modifier_head = modifier + modifier_tail = modifier + + # The modifier may be a nested list. Reach its tail. + # + while modifier_tail.type: + modifier_tail = modifier_tail.type + + # If the decl is a basic type, just tack the modifier onto + # it + # + if isinstance(decl, c_ast.TypeDecl): + modifier_tail.type = decl + return modifier + else: + # Otherwise, the decl is a list of modifiers. Reach + # its tail and splice the modifier onto the tail, + # pointing to the underlying basic type. + # + decl_tail = decl + + while not isinstance(decl_tail.type, c_ast.TypeDecl): + decl_tail = decl_tail.type + + modifier_tail.type = decl_tail.type + decl_tail.type = modifier_head + return decl + + # Due to the order in which declarators are constructed, + # they have to be fixed in order to look like a normal AST. + # + # When a declaration arrives from syntax construction, it has + # these problems: + # * The innermost TypeDecl has no type (because the basic + # type is only known at the uppermost declaration level) + # * The declaration has no variable name, since that is saved + # in the innermost TypeDecl + # * The typename of the declaration is a list of type + # specifiers, and not a node. Here, basic identifier types + # should be separated from more complex types like enums + # and structs. + # + # This method fixes these problem. + # + def _fix_decl_name_type(self, decl, typename): + """ Fixes a declaration. Modifies decl. + """ + # Reach the underlying basic type + # + type = decl + while not isinstance(type, c_ast.TypeDecl): + type = type.type + + decl.name = type.declname + type.quals = decl.quals + + # The typename is a list of types. If any type in this + # list isn't a simple string type, it must be the only + # type in the list (it's illegal to declare "int enum .." + # If all the types are basic, they're collected in the + # IdentifierType holder. + # + for tn in typename: + if not isinstance(tn, StringType): + if len(typename) > 1: + self._parse_error( + "Invalid multiple types specified", tn.coord) + else: + type.type = tn + return decl + + type.type = c_ast.IdentifierType(typename) + return decl + + def _add_declaration_specifier(self, declspec, newspec, kind): + """ Declaration specifiers are represented by a dictionary + with 3 entries: + * qual: a list of type qualifiers + * storage: a list of storage type qualifiers + * type: a list of type specifiers + + This method is given a declaration specifier, and a + new specifier of a given kind. + Returns the declaration specifier, with the new + specifier incorporated. + """ + spec = declspec or dict(qual=[], storage=[], type=[]) + spec[kind].append(newspec) + return spec + + def _build_function_definition(self, decl, spec, param_decls, body): + """ Builds a function definition. + """ + declaration = c_ast.Decl( + name=None, + quals=spec['qual'], + storage=spec['storage'], + type=decl, + init=None, + bitsize=None, + coord=decl.coord) + + typename = spec['type'] + declaration = self._fix_decl_name_type(declaration, typename) + return c_ast.FuncDef( + decl=declaration, + param_decls=param_decls, + body=body, + coord=decl.coord) + + def _select_struct_union_class(self, token): + """ Given a token (either STRUCT or UNION), selects the + appropriate AST class. + """ + if token == 'struct': + return c_ast.Struct + else: + return c_ast.Union + + ## + ## Precedence and associativity of operators + ## + precedence = ( + ('left', 'LOR'), + ('left', 'LAND'), + ('left', 'OR'), + ('left', 'XOR'), + ('left', 'AND'), + ('left', 'EQ', 'NE'), + ('left', 'GT', 'GE', 'LT', 'LE'), + ('left', 'RSHIFT', 'LSHIFT'), + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE', 'MOD') + ) + + ## + ## Grammar productions + ## Implementation of the BNF defined in K&R2 A.13 + ## + def p_translation_unit_1(self, p): + """ translation_unit : external_declaration + """ + # Note: external_declaration is already a list + # + p[0] = c_ast.FileAST(p[1]) + + def p_translation_unit_2(self, p): + """ translation_unit : translation_unit external_declaration + """ + p[1].ext.extend(p[2]) + p[0] = p[1] + + # Declarations always come as lists (because they can be + # several in one line), so we wrap the function definition + # into a list as well, to make the return value of + # external_declaration homogenous. + # + def p_external_declaration_1(self, p): + """ external_declaration : function_definition + """ + p[0] = [p[1]] + + def p_external_declaration_2(self, p): + """ external_declaration : declaration + """ + p[0] = p[1] + + def p_external_declaration_3(self, p): + """ external_declaration : pp_directive + """ + p[0] = p[1] + + def p_pp_directive(self, p): + """ pp_directive : PPHASH + """ + self._parse_error('Directives not supported yet', + self._coord(p.lineno(1))) + + # In function definitions, the declarator can be followed by + # a declaration list, for old "K&R style" function definitios. + # + def p_function_definition_1(self, p): + """ function_definition : declarator declaration_list_opt compound_statement + """ + # no declaration specifiers + spec = dict(qual=[], storage=[], type=[]) + + p[0] = self._build_function_definition( + decl=p[1], + spec=spec, + param_decls=p[2], + body=p[3]) + + def p_function_definition_2(self, p): + """ function_definition : declaration_specifiers declarator declaration_list_opt compound_statement + """ + spec = p[1] + + p[0] = self._build_function_definition( + decl=p[2], + spec=spec, + param_decls=p[3], + body=p[4]) + + def p_statement(self, p): + """ statement : labeled_statement + | expression_statement + | compound_statement + | selection_statement + | iteration_statement + | jump_statement + """ + p[0] = p[1] + + # In C, declarations can come several in a line: + # int x, *px, romulo = 5; + # + # However, for the AST, we will split them to separate Decl + # nodes. + # + # This rule splits its declarations and always returns a list + # of Decl nodes, even if it's one element long. + # + def p_decl_body(self, p): + """ decl_body : declaration_specifiers init_declarator_list_opt + """ + spec = p[1] + is_typedef = 'typedef' in spec['storage'] + decls = [] + + # p[2] (init_declarator_list_opt) is either a list or None + # + if p[2] is None: + # Then it's a declaration of a struct / enum tag, + # without an actual declarator. + # + type = spec['type'] + if len(type) > 1: + coord = '?' + for t in type: + if hasattr(t, 'coord'): + coord = t.coord + break + + self._parse_error('Multiple type specifiers with a type tag', coord) + + decl = c_ast.Decl( + name=None, + quals=spec['qual'], + storage=spec['storage'], + type=type[0], + init=None, + bitsize=None, + coord=type[0].coord) + decls = [decl] + else: + for decl, init in p[2] or []: + if is_typedef: + decl = c_ast.Typedef( + name=None, + quals=spec['qual'], + storage=spec['storage'], + type=decl, + coord=decl.coord) + else: + decl = c_ast.Decl( + name=None, + quals=spec['qual'], + storage=spec['storage'], + type=decl, + init=init, + bitsize=None, + coord=decl.coord) + + typename = spec['type'] + fixed_decl = self._fix_decl_name_type(decl, typename) + + # Add the type name defined by typedef to a + # symbol table (for usage in the lexer) + # + if is_typedef: + self._add_typedef_type(fixed_decl.name) + + decls.append(fixed_decl) + + p[0] = decls + + # The declaration has been split to a decl_body sub-rule and + # SEMI, because having them in a single rule created a problem + # for defining typedefs. + # + # If a typedef line was directly followed by a line using the + # type defined with the typedef, the type would not be + # recognized. This is because to reduce the declaration rule, + # the parser's lookahead asked for the token after SEMI, which + # was the type from the next line, and the lexer had no chance + # to see the updated type symbol table. + # + # Splitting solves this problem, because after seeing SEMI, + # the parser reduces decl_body, which actually adds the new + # type into the table to be seen by the lexer before the next + # line is reached. + # + def p_declaration(self, p): + """ declaration : decl_body SEMI + """ + p[0] = p[1] + + # Since each declaration is a list of declarations, this + # rule will combine all the declarations and return a single + # list + # + def p_declaration_list(self, p): + """ declaration_list : declaration + | declaration_list declaration + """ + p[0] = p[1] if len(p) == 2 else p[1] + p[2] + + def p_declaration_specifiers_1(self, p): + """ declaration_specifiers : type_qualifier declaration_specifiers_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'qual') + + def p_declaration_specifiers_2(self, p): + """ declaration_specifiers : type_specifier declaration_specifiers_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'type') + + def p_declaration_specifiers_3(self, p): + """ declaration_specifiers : storage_class_specifier declaration_specifiers_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'storage') + + def p_storage_class_specifier(self, p): + """ storage_class_specifier : AUTO + | REGISTER + | STATIC + | EXTERN + | TYPEDEF + """ + p[0] = p[1] + + def p_type_specifier_1(self, p): + """ type_specifier : VOID + | CHAR + | SHORT + | INT + | LONG + | FLOAT + | DOUBLE + | SIGNED + | UNSIGNED + | typedef_name + | enum_specifier + | struct_or_union_specifier + """ + p[0] = p[1] + + def p_type_qualifier(self, p): + """ type_qualifier : CONST + | VOLATILE + """ + p[0] = p[1] + + def p_init_declarator_list(self, p): + """ init_declarator_list : init_declarator + | init_declarator_list COMMA init_declarator + """ + p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]] + + # Returns a (declarator, intializer) pair + # If there's no initializer, returns (declarator, None) + # + def p_init_declarator(self, p): + """ init_declarator : declarator + | declarator EQUALS initializer + """ + p[0] = (p[1], p[3] if len(p) > 2 else None) + + def p_specifier_qualifier_list_1(self, p): + """ specifier_qualifier_list : type_qualifier specifier_qualifier_list_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'qual') + + def p_specifier_qualifier_list_2(self, p): + """ specifier_qualifier_list : type_specifier specifier_qualifier_list_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'type') + + # TYPEID is allowed here (and in other struct/enum related tag names), because + # struct/enum tags reside in their own namespace and can be named the same as types + # + def p_struct_or_union_specifier_1(self, p): + """ struct_or_union_specifier : struct_or_union ID + | struct_or_union TYPEID + """ + klass = self._select_struct_union_class(p[1]) + p[0] = klass( + name=p[2], + decls=None, + coord=self._coord(p.lineno(2))) + + def p_struct_or_union_specifier_2(self, p): + """ struct_or_union_specifier : struct_or_union LBRACE struct_declaration_list RBRACE + """ + klass = self._select_struct_union_class(p[1]) + p[0] = klass( + name=None, + decls=p[3], + coord=self._coord(p.lineno(2))) + + def p_struct_or_union_specifier_3(self, p): + """ struct_or_union_specifier : struct_or_union ID LBRACE struct_declaration_list RBRACE + | struct_or_union TYPEID LBRACE struct_declaration_list RBRACE + """ + klass = self._select_struct_union_class(p[1]) + p[0] = klass( + name=p[2], + decls=p[4], + coord=self._coord(p.lineno(2))) + + def p_struct_or_union(self, p): + """ struct_or_union : STRUCT + | UNION + """ + p[0] = p[1] + + # Combine all declarations into a single list + # + def p_struct_declaration_list(self, p): + """ struct_declaration_list : struct_declaration + | struct_declaration_list struct_declaration + """ + p[0] = p[1] if len(p) == 2 else p[1] + p[2] + + def p_struct_declaration_1(self, p): + """ struct_declaration : specifier_qualifier_list struct_declarator_list SEMI + """ + spec = p[1] + decls = [] + + for struct_decl in p[2]: + decl = c_ast.Decl( + name=None, + quals=spec['qual'], + storage=spec['storage'], + type=struct_decl['decl'], + init=None, + bitsize=struct_decl['bitsize'], + coord=struct_decl['decl'].coord) + + typename = spec['type'] + decls.append(self._fix_decl_name_type(decl, typename)) + + p[0] = decls + + def p_struct_declarator_list(self, p): + """ struct_declarator_list : struct_declarator + | struct_declarator_list COMMA struct_declarator + """ + p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]] + + # struct_declarator passes up a dict with the keys: decl (for + # the underlying declarator) and bitsize (for the bitsize) + # + def p_struct_declarator_1(self, p): + """ struct_declarator : declarator + """ + p[0] = {'decl': p[1], 'bitsize': None} + + def p_struct_declarator_2(self, p): + """ struct_declarator : declarator COLON constant_expression + | COLON constant_expression + """ + if len(p) > 3: + p[0] = {'decl': p[1], 'bitsize': p[3]} + else: + p[0] = {'decl': None, 'bitsize': p[2]} + + def p_enum_specifier_1(self, p): + """ enum_specifier : ENUM ID + | ENUM TYPEID + """ + p[0] = c_ast.Enum(p[2], None, self._coord(p.lineno(1))) + + def p_enum_specifier_2(self, p): + """ enum_specifier : ENUM LBRACE enumerator_list RBRACE + """ + p[0] = c_ast.Enum(None, p[3], self._coord(p.lineno(1))) + + def p_enum_specifier_3(self, p): + """ enum_specifier : ENUM ID LBRACE enumerator_list RBRACE + | ENUM TYPEID LBRACE enumerator_list RBRACE + """ + p[0] = c_ast.Enum(p[2], p[4], self._coord(p.lineno(1))) + + def p_enumerator_list(self, p): + """ enumerator_list : enumerator + | enumerator_list COMMA + | enumerator_list COMMA enumerator + """ + if len(p) == 2: + p[0] = c_ast.EnumeratorList([p[1]], p[1].coord) + elif len(p) == 3: + p[0] = p[1] + else: + p[1].enumerators.append(p[3]) + p[0] = p[1] + + def p_enumerator(self, p): + """ enumerator : ID + | ID EQUALS constant_expression + """ + if len(p) == 2: + p[0] = c_ast.Enumerator( + p[1], None, + self._coord(p.lineno(1))) + else: + p[0] = c_ast.Enumerator( + p[1], p[3], + self._coord(p.lineno(1))) + + def p_declarator_1(self, p): + """ declarator : direct_declarator + """ + p[0] = p[1] + + def p_declarator_2(self, p): + """ declarator : pointer direct_declarator + """ + p[0] = self._type_modify_decl(p[2], p[1]) + + def p_direct_declarator_1(self, p): + """ direct_declarator : ID + """ + p[0] = c_ast.TypeDecl( + declname=p[1], + type=None, + quals=None, + coord=self._coord(p.lineno(1))) + + def p_direct_declarator_2(self, p): + """ direct_declarator : LPAREN declarator RPAREN + """ + p[0] = p[2] + + def p_direct_declarator_3(self, p): + """ direct_declarator : direct_declarator LBRACKET constant_expression_opt RBRACKET + """ + arr = c_ast.ArrayDecl( + type=None, + dim=p[3], + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=arr) + + def p_direct_declarator_4(self, p): + """ direct_declarator : direct_declarator LPAREN parameter_type_list RPAREN + | direct_declarator LPAREN identifier_list_opt RPAREN + """ + func = c_ast.FuncDecl( + args=p[3], + type=None, + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=func) + + def p_pointer(self, p): + """ pointer : TIMES type_qualifier_list_opt + | TIMES type_qualifier_list_opt pointer + """ + coord = self._coord(p.lineno(1)) + + p[0] = c_ast.PtrDecl( + quals=p[2] or [], + type=p[3] if len(p) > 3 else None, + coord=coord) + + def p_type_qualifier_list(self, p): + """ type_qualifier_list : type_qualifier + | type_qualifier_list type_qualifier + """ + p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]] + + def p_parameter_type_list(self, p): + """ parameter_type_list : parameter_list + | parameter_list COMMA ELLIPSIS + """ + if len(p) > 2: + p[1].params.append(c_ast.EllipsisParam()) + + p[0] = p[1] + + def p_parameter_list(self, p): + """ parameter_list : parameter_declaration + | parameter_list COMMA parameter_declaration + """ + if len(p) == 2: # single parameter + p[0] = c_ast.ParamList([p[1]], p[1].coord) + else: + p[1].params.append(p[3]) + p[0] = p[1] + + def p_parameter_declaration_1(self, p): + """ parameter_declaration : declaration_specifiers declarator + """ + spec = p[1] + decl = p[2] + + decl = c_ast.Decl( + name=None, + quals=spec['qual'], + storage=spec['storage'], + type=decl, + init=None, + bitsize=None, + coord=decl.coord) + + typename = spec['type'] or ['int'] + p[0] = self._fix_decl_name_type(decl, typename) + + def p_parameter_declaration_2(self, p): + """ parameter_declaration : declaration_specifiers abstract_declarator_opt + """ + spec = p[1] + decl = c_ast.Typename( + quals=spec['qual'], + type=p[2] or c_ast.TypeDecl(None, None, None)) + + typename = spec['type'] or ['int'] + + p[0] = self._fix_decl_name_type(decl, typename) + + def p_identifier_list(self, p): + """ identifier_list : identifier + | identifier_list COMMA identifier + """ + if len(p) == 2: # single parameter + p[0] = c_ast.ParamList([p[1]], p[1].coord) + else: + p[1].params.append(p[3]) + p[0] = p[1] + + def p_initializer_1(self, p): + """ initializer : assignment_expression + """ + p[0] = p[1] + + def p_initializer_2(self, p): + """ initializer : LBRACE initializer_list RBRACE + | LBRACE initializer_list COMMA RBRACE + """ + p[0] = p[2] + + def p_initializer_list(self, p): + """ initializer_list : initializer + | initializer_list COMMA initializer + """ + if len(p) == 2: # single initializer + p[0] = c_ast.ExprList([p[1]], p[1].coord) + else: + p[1].exprs.append(p[3]) + p[0] = p[1] + + def p_type_name(self, p): + """ type_name : specifier_qualifier_list abstract_declarator_opt + """ + #~ print '==========' + #~ print p[1] + #~ print p[2] + #~ print p[2].children() + #~ print '==========' + + typename = c_ast.Typename( + quals=p[1]['qual'], + type=p[2] or c_ast.TypeDecl(None, None, None)) + + p[0] = self._fix_decl_name_type(typename, p[1]['type']) + + def p_abstract_declarator_1(self, p): + """ abstract_declarator : pointer + """ + dummytype = c_ast.TypeDecl(None, None, None) + p[0] = self._type_modify_decl( + decl=dummytype, + modifier=p[1]) + + def p_abstract_declarator_2(self, p): + """ abstract_declarator : pointer direct_abstract_declarator + """ + p[0] = self._type_modify_decl(p[2], p[1]) + + def p_abstract_declarator_3(self, p): + """ abstract_declarator : direct_abstract_declarator + """ + p[0] = p[1] + + # Creating and using direct_abstract_declarator_opt here + # instead of listing both direct_abstract_declarator and the + # lack of it in the beginning of _1 and _2 caused two + # shift/reduce errors. + # + def p_direct_abstract_declarator_1(self, p): + """ direct_abstract_declarator : LPAREN abstract_declarator RPAREN """ + p[0] = p[2] + + def p_direct_abstract_declarator_2(self, p): + """ direct_abstract_declarator : direct_abstract_declarator LBRACKET constant_expression_opt RBRACKET + """ + arr = c_ast.ArrayDecl( + type=None, + dim=p[3], + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=arr) + + def p_direct_abstract_declarator_3(self, p): + """ direct_abstract_declarator : LBRACKET constant_expression_opt RBRACKET + """ + p[0] = c_ast.ArrayDecl( + type=c_ast.TypeDecl(None, None, None), + dim=p[2], + coord=self._coord(p.lineno(1))) + + def p_direct_abstract_declarator_4(self, p): + """ direct_abstract_declarator : direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN + """ + func = c_ast.FuncDecl( + args=p[3], + type=None, + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=func) + + def p_direct_abstract_declarator_5(self, p): + """ direct_abstract_declarator : LPAREN parameter_type_list_opt RPAREN + """ + p[0] = c_ast.FuncDecl( + args=p[2], + type=c_ast.TypeDecl(None, None, None), + coord=p[1].coord) + + def p_compound_statement_1(self, p): + """ compound_statement : LBRACE statement_list_opt RBRACE """ + p[0] = c_ast.Compound( + decls=None, + stmts=p[2], + coord=self._coord(p.lineno(1))) + + def p_compound_statement_2(self, p): + """ compound_statement : LBRACE declaration_list RBRACE """ + p[0] = c_ast.Compound( + decls=p[2], + stmts=None, + coord=self._coord(p.lineno(1))) + + def p_compound_statement_3(self, p): + """ compound_statement : LBRACE declaration_list statement_list RBRACE """ + #~ print '((((((' + #~ print p[2] + #~ print p[3] + #~ print '((((((' + p[0] = c_ast.Compound( + decls=p[2], + stmts=p[3], + coord=self._coord(p.lineno(1))) + + # Note: this doesn't create an AST node, but a list of AST + # nodes that will be used as the statement list of a compound + # + def p_statement_list(self, p): + """ statement_list : statement + | statement_list statement + """ + if len(p) == 2: # single expr + p[0] = [p[1]] if p[1] else [] + else: + p[0] = p[1] + ([p[2]] if p[2] else []) + + def p_labeled_statement_1(self, p): + """ labeled_statement : ID COLON statement """ + p[0] = c_ast.Label(p[1], p[3], self._coord(p.lineno(1))) + + def p_labeled_statement_2(self, p): + """ labeled_statement : CASE constant_expression COLON statement """ + p[0] = c_ast.Case(p[2], p[4], self._coord(p.lineno(1))) + + def p_labeled_statement_3(self, p): + """ labeled_statement : DEFAULT COLON statement """ + p[0] = c_ast.Default(p[3], self._coord(p.lineno(1))) + + def p_selection_statement_1(self, p): + """ selection_statement : IF LPAREN expression RPAREN statement """ + p[0] = c_ast.If(p[3], p[5], None, self._coord(p.lineno(1))) + + def p_selection_statement_2(self, p): + """ selection_statement : IF LPAREN expression RPAREN statement ELSE statement """ + p[0] = c_ast.If(p[3], p[5], p[7], self._coord(p.lineno(1))) + + def p_selection_statement_3(self, p): + """ selection_statement : SWITCH LPAREN expression RPAREN statement """ + p[0] = c_ast.Switch(p[3], p[5], self._coord(p.lineno(1))) + + def p_iteration_statement_1(self, p): + """ iteration_statement : WHILE LPAREN expression RPAREN statement """ + p[0] = c_ast.While(p[3], p[5], self._coord(p.lineno(1))) + + def p_iteration_statement_2(self, p): + """ iteration_statement : DO statement WHILE LPAREN expression RPAREN """ + p[0] = c_ast.DoWhile(p[5], p[2], self._coord(p.lineno(1))) + + def p_iteration_statement_3(self, p): + """ iteration_statement : FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN statement """ + p[0] = c_ast.For(p[3], p[5], p[7], p[9], self._coord(p.lineno(1))) + + def p_jump_statement_1(self, p): + """ jump_statement : GOTO ID SEMI """ + p[0] = c_ast.Goto(p[2], self._coord(p.lineno(1))) + + def p_jump_statement_2(self, p): + """ jump_statement : BREAK SEMI """ + p[0] = c_ast.Break(self._coord(p.lineno(1))) + + def p_jump_statement_3(self, p): + """ jump_statement : CONTINUE SEMI """ + p[0] = c_ast.Continue(self._coord(p.lineno(1))) + + def p_jump_statement_4(self, p): + """ jump_statement : RETURN expression SEMI + | RETURN SEMI + """ + p[0] = c_ast.Return(p[2] if len(p) == 4 else None, self._coord(p.lineno(1))) + + def p_expression_statement(self, p): + """ expression_statement : expression_opt SEMI """ + p[0] = p[1] + + def p_expression(self, p): + """ expression : assignment_expression + | expression COMMA assignment_expression + """ + if len(p) == 2: + p[0] = p[1] + else: + if not isinstance(p[1], c_ast.ExprList): + p[1] = c_ast.ExprList([p[1]], p[1].coord) + + p[1].exprs.append(p[3]) + p[0] = p[1] + + def p_typedef_name(self, p): + """ typedef_name : TYPEID """ + p[0] = p[1] + + def p_assignment_expression(self, p): + """ assignment_expression : conditional_expression + | unary_expression assignment_operator assignment_expression + """ + if len(p) == 2: + p[0] = p[1] + else: + p[0] = c_ast.Assignment(p[2], p[1], p[3], p[1].coord) + + # K&R2 defines these as many separate rules, to encode + # precedence and associativity. Why work hard ? I'll just use + # the built in precedence/associativity specification feature + # of PLY. (see precedence declaration above) + # + def p_assignment_operator(self, p): + """ assignment_operator : EQUALS + | XOREQUAL + | TIMESEQUAL + | DIVEQUAL + | MODEQUAL + | PLUSEQUAL + | MINUSEQUAL + | LSHIFTEQUAL + | RSHIFTEQUAL + | ANDEQUAL + | OREQUAL + """ + p[0] = p[1] + + def p_constant_expression(self, p): + """ constant_expression : conditional_expression """ + p[0] = p[1] + + def p_conditional_expression(self, p): + """ conditional_expression : binary_expression + | binary_expression CONDOP expression COLON conditional_expression + """ + if len(p) == 2: + p[0] = p[1] + else: + p[0] = c_ast.TernaryOp(p[1], p[3], p[5], p[1].coord) + + def p_binary_expression(self, p): + """ binary_expression : cast_expression + | binary_expression TIMES binary_expression + | binary_expression DIVIDE binary_expression + | binary_expression MOD binary_expression + | binary_expression PLUS binary_expression + | binary_expression MINUS binary_expression + | binary_expression RSHIFT binary_expression + | binary_expression LSHIFT binary_expression + | binary_expression LT binary_expression + | binary_expression LE binary_expression + | binary_expression GE binary_expression + | binary_expression GT binary_expression + | binary_expression EQ binary_expression + | binary_expression NE binary_expression + | binary_expression AND binary_expression + | binary_expression OR binary_expression + | binary_expression XOR binary_expression + | binary_expression LAND binary_expression + | binary_expression LOR binary_expression + """ + if len(p) == 2: + p[0] = p[1] + else: + p[0] = c_ast.BinaryOp(p[2], p[1], p[3], p[1].coord) + + def p_cast_expression_1(self, p): + """ cast_expression : unary_expression """ + p[0] = p[1] + + def p_cast_expression_2(self, p): + """ cast_expression : LPAREN type_name RPAREN cast_expression """ + p[0] = c_ast.Cast(p[2], p[4], p[2].coord) + + def p_unary_expression_1(self, p): + """ unary_expression : postfix_expression """ + p[0] = p[1] + + def p_unary_expression_2(self, p): + """ unary_expression : PLUSPLUS unary_expression + | MINUSMINUS unary_expression + | unary_operator cast_expression + """ + p[0] = c_ast.UnaryOp(p[1], p[2], p[2].coord) + + def p_unary_expression_3(self, p): + """ unary_expression : SIZEOF unary_expression + | SIZEOF LPAREN type_name RPAREN + """ + p[0] = c_ast.UnaryOp( + p[1], + p[2] if len(p) == 3 else p[3], + self._coord(p.lineno(1))) + + def p_unary_operator(self, p): + """ unary_operator : AND + | TIMES + | PLUS + | MINUS + | NOT + | LNOT + """ + p[0] = p[1] + + def p_postfix_exptession_1(self, p): + """ postfix_expression : primary_expression """ + p[0] = p[1] + + def p_postfix_exptession_2(self, p): + """ postfix_expression : postfix_expression LBRACKET expression RBRACKET """ + p[0] = c_ast.ArrayRef(p[1], p[3], p[1].coord) + + def p_postfix_exptession_3(self, p): + """ postfix_expression : postfix_expression LPAREN argument_expression_list RPAREN + | postfix_expression LPAREN RPAREN + """ + p[0] = c_ast.FuncCall(p[1], p[3] if len(p) == 5 else None) + + def p_postfix_expression_4(self, p): + """ postfix_expression : postfix_expression PERIOD identifier + | postfix_expression ARROW identifier + """ + p[0] = c_ast.StructRef(p[1], p[2], p[3], p[1].coord) + + def p_postfix_expression_5(self, p): + """ postfix_expression : postfix_expression PLUSPLUS + | postfix_expression MINUSMINUS + """ + p[0] = c_ast.UnaryOp('p' + p[2], p[1], p[1].coord) + + def p_primary_expression_1(self, p): + """ primary_expression : identifier """ + p[0] = p[1] + + def p_primary_expression_2(self, p): + """ primary_expression : constant """ + p[0] = p[1] + + def p_primary_expression_3(self, p): + """ primary_expression : STRING_LITERAL + | WSTRING_LITERAL + """ + p[0] = c_ast.Constant( + 'string', p[1], self._coord(p.lineno(1))) + + def p_primary_expression_4(self, p): + """ primary_expression : LPAREN expression RPAREN """ + p[0] = p[2] + + def p_argument_expression_list(self, p): + """ argument_expression_list : assignment_expression + | argument_expression_list COMMA assignment_expression + """ + if len(p) == 2: # single expr + p[0] = c_ast.ExprList([p[1]], p[1].coord) + else: + p[1].exprs.append(p[3]) + p[0] = p[1] + + def p_identifier(self, p): + """ identifier : ID """ + p[0] = c_ast.ID(p[1], self._coord(p.lineno(1))) + + def p_constant_1(self, p): + """ constant : INT_CONST_DEC + | INT_CONST_OCT + | INT_CONST_HEX + """ + p[0] = c_ast.Constant( + 'int', p[1], self._coord(p.lineno(1))) + + def p_constant_2(self, p): + """ constant : FLOAT_CONST """ + p[0] = c_ast.Constant( + 'float', p[1], self._coord(p.lineno(1))) + + def p_constant_3(self, p): + """ constant : CHAR_CONST + | WCHAR_CONST + """ + p[0] = c_ast.Constant( + 'char', p[1], self._coord(p.lineno(1))) + + def p_empty(self, p): + 'empty : ' + p[0] = None + + def p_error(self, p): + if p: + self._parse_error( + 'before: %s' % p.value, + self._coord(p.lineno)) + else: + self._parse_error('At end of input', '') + + +if __name__ == "__main__": + import pprint + import time + + t1 = time.time() + parser = CParser(lex_optimize=True, yacc_debug=True, yacc_optimize=False) + print time.time() - t1 + + buf = ''' + int (*k)(int); + ''' + + # set debuglevel to 2 for debugging + t = parser.parse(buf, 'x.c', debuglevel=0) + t.show(showcoord=True) diff --git a/plugins/pycparser/pycparser/plyparser.py b/plugins/pycparser/pycparser/plyparser.py new file mode 100644 index 0000000..8e9e573 --- /dev/null +++ b/plugins/pycparser/pycparser/plyparser.py @@ -0,0 +1,67 @@ +#----------------------------------------------------------------- +# plyparser.py +# +# PLYParser class and other utilites for simplifying programming +# parsers with PLY +# +# Copyright (C) 2008-2009, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- + + +class Coord(object): + """ Coordinates of a syntactic element. Consists of: + - File name + - Line number + - (optional) column number, for the Lexer + """ + def __init__(self, file, line, column=None): + self.file = file + self.line = line + self.column = column + + def __str__(self): + str = "%s:%s" % (self.file, self.line) + if self.column: str += ":%s" % self.column + return str + + +class ParseError(Exception): pass + + +class PLYParser(object): + def _create_opt_rule(self, rulename): + """ Given a rule name, creates an optional ply.yacc rule + for it. The name of the optional rule is + _opt + """ + optname = rulename + '_opt' + + def optrule(self, p): + p[0] = p[1] + + optrule.__doc__ = '%s : empty\n| %s' % (optname, rulename) + optrule.__name__ = 'p_%s' % optname + setattr(self.__class__, optrule.__name__, optrule) + + def _coord(self, lineno, column=None): + return Coord( + file=self.clex.filename, + line=lineno, + column=column) + + def _parse_error(self, msg, coord): + raise ParseError("%s: %s" % (coord, msg)) + + +if __name__ == '__main__': + pp = PLYParser() + pp._create_opt_rule('java') + + ar = [4, 6] + pp.p_java_opt(ar) + + print ar + print pp.p_java_opt.__doc__ + + print dir(pp) diff --git a/plugins/pycparser/yacctab.py b/plugins/pycparser/yacctab.py new file mode 100644 index 0000000..544f84c --- /dev/null +++ b/plugins/pycparser/yacctab.py @@ -0,0 +1,250 @@ + +# yacctab.py +# This file is automatically generated. Do not edit. +_tabversion = '3.2' + +_lr_method = 'LALR' + +_lr_signature = "\n\x9d\xda\xf6\xeb\xf5\x97'\n\xff\xf7b(G7V" + +_lr_action_items = {'VOID':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[6,6,-51,-61,-60,-49,-46,-47,-27,-23,6,-45,-57,-53,-58,-44,6,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,6,-56,-54,-59,-62,6,-70,6,-69,-95,-24,6,-85,-84,6,-38,-39,6,-97,6,6,6,-76,6,6,6,6,-29,-40,6,-77,-71,6,6,-98,-100,-99,6,6,-86,-30,6,-73,-78,-72,6,6,-88,-87,-127,-128,-129,]),'LBRACKET':([1,2,3,5,6,8,9,12,14,15,16,17,19,21,22,23,25,28,31,33,34,36,37,38,39,40,42,43,44,46,48,49,50,54,56,57,58,59,60,67,73,76,78,83,84,85,86,87,90,95,97,101,102,106,107,111,116,125,126,136,137,138,139,140,149,153,160,183,184,185,186,191,192,197,229,231,236,238,239,242,258,259,260,288,292,295,320,321,327,328,329,347,348,],[-221,-51,-61,-60,-49,-46,-47,-221,-45,-57,-53,-58,-44,-48,-149,52,-221,-96,-50,-52,-55,-221,-56,-54,-59,-62,-43,-7,-8,-70,-69,-42,52,-85,-84,-22,-101,-103,-21,-41,-97,-221,-221,-219,-210,-220,-218,-208,151,-217,-199,-214,-209,-216,-215,-207,189,-104,-102,-71,-17,-68,-18,-67,-205,-206,189,-98,-100,-99,189,286,189,-86,-214,-73,-72,-204,-203,-202,189,189,-211,286,-88,-87,-200,-201,-126,-122,-124,-123,-125,]),'WCHAR_CONST':([52,66,70,81,88,89,91,92,94,96,98,100,103,110,128,131,133,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,232,244,245,246,247,248,249,250,251,252,253,254,255,256,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[85,-38,-39,-198,85,-196,-195,85,85,-194,85,85,-193,-197,85,85,-40,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,-32,-35,-31,85,85,-33,85,85,-130,-36,85,-34,85,-155,-158,-156,-152,-153,-157,-159,85,-161,-162,-154,-160,85,85,85,-127,-146,85,-128,-145,85,-143,-131,85,85,85,-142,85,85,85,85,85,-141,-129,-144,-134,85,-132,85,85,-133,85,85,85,-138,-137,-135,85,-139,85,-136,85,-140,]),'FLOAT_CONST':([52,66,70,81,88,89,91,92,94,96,98,100,103,110,128,131,133,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,232,244,245,246,247,248,249,250,251,252,253,254,255,256,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[86,-38,-39,-198,86,-196,-195,86,86,-194,86,86,-193,-197,86,86,-40,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,-32,-35,-31,86,86,-33,86,86,-130,-36,86,-34,86,-155,-158,-156,-152,-153,-157,-159,86,-161,-162,-154,-160,86,86,86,-127,-146,86,-128,-145,86,-143,-131,86,86,86,-142,86,86,86,86,86,-141,-129,-144,-134,86,-132,86,86,-133,86,86,86,-138,-137,-135,86,-139,86,-136,86,-140,]),'MINUS':([52,66,70,81,82,83,84,85,86,87,88,89,90,91,92,94,95,96,97,98,99,100,101,102,103,104,106,107,110,111,128,131,133,143,146,147,149,151,152,153,154,155,156,157,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,229,232,238,239,242,244,245,246,247,248,249,250,251,252,253,254,255,256,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,319,320,321,322,324,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[89,-38,-39,-198,-185,-219,-210,-220,-218,-208,89,-196,-187,-195,89,89,-217,-194,-199,89,-166,89,-214,-209,-193,167,-216,-215,-197,-207,89,89,-40,89,89,-191,-205,89,89,-206,-190,89,-188,-185,-189,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,-32,-35,-31,89,89,-33,89,89,-130,-36,89,-34,-214,89,-204,-203,-202,-155,-158,-156,-152,-153,-157,-159,89,-161,-162,-154,-160,89,-211,89,167,167,167,-171,167,167,167,-170,167,167,-168,-167,167,167,167,167,167,-169,89,-127,-146,89,-128,-145,89,-143,-131,89,89,89,-142,89,89,-192,-200,-201,89,-186,89,89,-141,-129,-144,-134,89,-132,89,89,-133,89,89,89,-138,-137,-135,89,-139,89,-136,89,-140,]),'RPAREN':([1,2,3,5,6,8,9,12,14,15,16,17,19,21,22,23,25,28,31,33,34,36,37,38,39,40,42,43,44,45,46,48,49,50,53,54,56,57,58,59,60,67,73,76,78,82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,112,113,114,115,116,117,118,119,125,126,136,137,138,139,140,147,149,152,153,154,156,157,158,159,160,161,162,163,183,184,185,186,187,188,190,191,192,193,197,218,231,236,237,238,239,241,242,243,257,258,259,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,281,282,283,284,287,288,289,290,291,292,295,302,319,320,321,323,324,325,327,328,329,331,339,341,344,345,346,347,348,360,362,365,],[-221,-51,-61,-60,-49,-46,-47,-221,-45,-57,-53,-58,-44,-48,-149,-94,-221,-96,-50,-52,-55,-221,-56,-54,-59,-62,-43,-7,-8,73,-70,-69,-42,-95,-221,-85,-84,-22,-101,-103,-21,-41,-97,-221,-221,-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,-164,-216,-215,-207,184,-11,185,-107,-221,-12,-105,-111,-104,-102,-71,-17,-68,-18,-67,-191,-205,242,-206,-190,-188,-185,256,-147,-221,-150,260,-189,-98,-100,-99,-221,-110,-2,-109,-121,-119,-1,-86,-10,-73,-72,319,-204,-203,-212,-202,321,-118,-221,-119,-211,-172,-184,-173,-171,-175,-179,-174,-170,-177,-182,-168,-167,-176,-183,-178,-180,-181,-169,-15,-16,327,328,-221,-120,-112,-106,-108,-88,-87,-9,-192,-200,-201,-151,-186,-148,-126,-122,-124,348,352,354,356,-213,-165,-123,-125,363,-221,367,]),'LONG':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[16,16,-51,-61,-60,-49,-46,-47,-27,-23,16,-45,-57,-53,-58,-44,16,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,16,-56,-54,-59,-62,16,-70,16,-69,-95,-24,16,-85,-84,16,-38,-39,16,-97,16,16,16,-76,16,16,16,16,-29,-40,16,-77,-71,16,16,-98,-100,-99,16,16,-86,-30,16,-73,-78,-72,16,16,-88,-87,-127,-128,-129,]),'PLUS':([52,66,70,81,82,83,84,85,86,87,88,89,90,91,92,94,95,96,97,98,99,100,101,102,103,104,106,107,110,111,128,131,133,143,146,147,149,151,152,153,154,155,156,157,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,229,232,238,239,242,244,245,246,247,248,249,250,251,252,253,254,255,256,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,319,320,321,322,324,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[91,-38,-39,-198,-185,-219,-210,-220,-218,-208,91,-196,-187,-195,91,91,-217,-194,-199,91,-166,91,-214,-209,-193,171,-216,-215,-197,-207,91,91,-40,91,91,-191,-205,91,91,-206,-190,91,-188,-185,-189,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,-32,-35,-31,91,91,-33,91,91,-130,-36,91,-34,-214,91,-204,-203,-202,-155,-158,-156,-152,-153,-157,-159,91,-161,-162,-154,-160,91,-211,91,171,171,171,-171,171,171,171,-170,171,171,-168,-167,171,171,171,171,171,-169,91,-127,-146,91,-128,-145,91,-143,-131,91,91,91,-142,91,91,-192,-200,-201,91,-186,91,91,-141,-129,-144,-134,91,-132,91,91,-133,91,91,91,-138,-137,-135,91,-139,91,-136,91,-140,]),'ELLIPSIS':([195,],[290,]),'GT':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,172,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,172,-173,-171,-175,172,-174,-170,-177,172,-168,-167,-176,172,172,172,172,-169,-192,-200,-201,-186,]),'RBRACE':([66,70,75,77,82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,109,111,121,122,123,131,133,134,135,145,147,149,153,154,156,157,161,163,196,198,200,203,206,207,209,211,212,214,217,223,224,226,228,235,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,293,294,296,297,299,300,301,303,304,307,308,313,319,320,321,323,324,332,333,334,335,336,338,343,346,349,350,353,358,359,361,363,366,368,],[-38,-39,136,-76,-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,-164,-216,-215,-163,-207,-89,197,-92,-221,-40,231,-77,236,-191,-205,-206,-190,-188,-185,-150,-189,292,-90,295,-113,-32,-35,299,-31,303,-33,-20,-130,-36,-19,-34,-78,-204,-203,-202,-211,-172,-184,-173,-171,-175,-179,-174,-170,-177,-182,-168,-167,-176,-183,-178,-180,-181,-169,-91,-93,-116,333,-127,-146,335,-128,-145,-143,-131,-142,-192,-200,-201,-151,-186,350,-114,-141,-129,-144,-134,-132,-165,-117,-115,-133,-138,-137,-135,-139,-136,-140,]),'ENUM':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[24,24,-51,-61,-60,-49,-46,-47,-27,-23,24,-45,-57,-53,-58,-44,24,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,24,-56,-54,-59,-62,24,-70,24,-69,-95,-24,24,-85,-84,24,-38,-39,24,-97,24,24,24,-76,24,24,24,24,-29,-40,24,-77,-71,24,24,-98,-100,-99,24,24,-86,-30,24,-73,-78,-72,24,24,-88,-87,-127,-128,-129,]),'PERIOD':([83,84,85,86,87,90,95,97,101,102,106,107,111,149,153,229,238,239,242,260,320,321,],[-219,-210,-220,-218,-208,150,-217,-199,-214,-209,-216,-215,-207,-205,-206,-214,-204,-203,-202,-211,-200,-201,]),'GE':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,176,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,176,-173,-171,-175,176,-174,-170,-177,176,-168,-167,-176,176,176,176,176,-169,-192,-200,-201,-186,]),'INT_CONST_DEC':([52,66,70,81,88,89,91,92,94,96,98,100,103,110,128,131,133,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,232,244,245,246,247,248,249,250,251,252,253,254,255,256,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[107,-38,-39,-198,107,-196,-195,107,107,-194,107,107,-193,-197,107,107,-40,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,-32,-35,-31,107,107,-33,107,107,-130,-36,107,-34,107,-155,-158,-156,-152,-153,-157,-159,107,-161,-162,-154,-160,107,107,107,-127,-146,107,-128,-145,107,-143,-131,107,107,107,-142,107,107,107,107,107,-141,-129,-144,-134,107,-132,107,107,-133,107,107,107,-138,-137,-135,107,-139,107,-136,107,-140,]),'ARROW':([83,84,85,86,87,90,95,97,101,102,106,107,111,149,153,229,238,239,242,260,320,321,],[-219,-210,-220,-218,-208,148,-217,-199,-214,-209,-216,-215,-207,-205,-206,-214,-204,-203,-202,-211,-200,-201,]),'DOUBLE':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[34,34,-51,-61,-60,-49,-46,-47,-27,-23,34,-45,-57,-53,-58,-44,34,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,34,-56,-54,-59,-62,34,-70,34,-69,-95,-24,34,-85,-84,34,-38,-39,34,-97,34,34,34,-76,34,34,34,34,-29,-40,34,-77,-71,34,34,-98,-100,-99,34,34,-86,-30,34,-73,-78,-72,34,34,-88,-87,-127,-128,-129,]),'MINUSEQUAL':([82,83,84,85,86,87,90,95,97,101,102,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-214,-209,-216,-215,-207,-191,-205,-206,-190,-188,245,-189,-214,-204,-203,-202,-211,-192,-200,-201,-186,]),'INT_CONST_OCT':([52,66,70,81,88,89,91,92,94,96,98,100,103,110,128,131,133,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,232,244,245,246,247,248,249,250,251,252,253,254,255,256,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[106,-38,-39,-198,106,-196,-195,106,106,-194,106,106,-193,-197,106,106,-40,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,-32,-35,-31,106,106,-33,106,106,-130,-36,106,-34,106,-155,-158,-156,-152,-153,-157,-159,106,-161,-162,-154,-160,106,106,106,-127,-146,106,-128,-145,106,-143,-131,106,106,106,-142,106,106,106,106,106,-141,-129,-144,-134,106,-132,106,106,-133,106,106,106,-138,-137,-135,106,-139,106,-136,106,-140,]),'TIMESEQUAL':([82,83,84,85,86,87,90,95,97,101,102,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-214,-209,-216,-215,-207,-191,-205,-206,-190,-188,254,-189,-214,-204,-203,-202,-211,-192,-200,-201,-186,]),'OR':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,181,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,181,-173,-171,-175,-179,-174,-170,-177,-182,-168,-167,-176,181,-178,-180,-181,-169,-192,-200,-201,-186,]),'SHORT':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[2,2,-51,-61,-60,-49,-46,-47,-27,-23,2,-45,-57,-53,-58,-44,2,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,2,-56,-54,-59,-62,2,-70,2,-69,-95,-24,2,-85,-84,2,-38,-39,2,-97,2,2,2,-76,2,2,2,2,-29,-40,2,-77,-71,2,2,-98,-100,-99,2,2,-86,-30,2,-73,-78,-72,2,2,-88,-87,-127,-128,-129,]),'RETURN':([66,70,131,133,206,207,211,212,214,217,223,224,227,228,299,300,301,303,304,307,308,309,313,315,334,335,336,338,340,343,352,353,354,356,358,359,361,363,364,366,367,368,],[-38,-39,213,-40,-32,-35,-31,213,-33,213,-130,-36,213,-34,-127,-146,213,-128,-145,-143,-131,213,-142,213,-141,-129,-144,-134,213,-132,213,-133,213,213,-138,-137,-135,-139,213,-136,213,-140,]),'RSHIFTEQUAL':([82,83,84,85,86,87,90,95,97,101,102,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-214,-209,-216,-215,-207,-191,-205,-206,-190,-188,255,-189,-214,-204,-203,-202,-211,-192,-200,-201,-186,]),'STATIC':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,48,50,51,53,54,56,64,66,70,72,73,131,132,133,136,183,184,185,186,195,197,205,212,231,236,258,287,292,295,299,303,335,],[8,8,-51,-61,-60,-49,-46,-47,-27,-23,8,-45,-57,-53,-58,-44,8,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,8,-56,-54,-59,-62,8,-70,-69,-95,-24,8,-85,-84,8,-38,-39,8,-97,8,-29,-40,-71,-98,-100,-99,8,8,-86,-30,8,-73,-72,8,8,-88,-87,-127,-128,-129,]),'SIZEOF':([52,66,70,81,88,89,91,92,94,96,98,100,103,110,128,131,133,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,232,244,245,246,247,248,249,250,251,252,253,254,255,256,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[88,-38,-39,-198,88,-196,-195,88,88,-194,88,88,-193,-197,88,88,-40,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,-32,-35,-31,88,88,-33,88,88,-130,-36,88,-34,88,-155,-158,-156,-152,-153,-157,-159,88,-161,-162,-154,-160,88,88,88,-127,-146,88,-128,-145,88,-143,-131,88,88,88,-142,88,88,88,88,88,-141,-129,-144,-134,88,-132,88,88,-133,88,88,88,-138,-137,-135,88,-139,88,-136,88,-140,]),'UNSIGNED':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[15,15,-51,-61,-60,-49,-46,-47,-27,-23,15,-45,-57,-53,-58,-44,15,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,15,-56,-54,-59,-62,15,-70,15,-69,-95,-24,15,-85,-84,15,-38,-39,15,-97,15,15,15,-76,15,15,15,15,-29,-40,15,-77,-71,15,15,-98,-100,-99,15,15,-86,-30,15,-73,-78,-72,15,15,-88,-87,-127,-128,-129,]),'UNION':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[18,18,-51,-61,-60,-49,-46,-47,-27,-23,18,-45,-57,-53,-58,-44,18,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,18,-56,-54,-59,-62,18,-70,18,-69,-95,-24,18,-85,-84,18,-38,-39,18,-97,18,18,18,-76,18,18,18,18,-29,-40,18,-77,-71,18,18,-98,-100,-99,18,18,-86,-30,18,-73,-78,-72,18,18,-88,-87,-127,-128,-129,]),'COLON':([2,3,5,6,15,16,17,22,23,28,31,33,34,37,38,39,40,46,48,50,54,56,73,76,78,79,82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,109,111,136,137,138,139,140,142,147,149,153,154,156,157,159,161,163,183,184,185,197,219,229,231,234,236,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,292,295,311,319,320,321,323,324,325,346,],[-51,-61,-60,-49,-57,-53,-58,-149,-94,-96,-50,-52,-55,-56,-54,-59,-62,-70,-69,-95,-85,-84,-97,-221,-221,143,-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,-164,-216,-215,-163,-207,-71,-17,-68,-18,-67,232,-191,-205,-206,-190,-188,-185,-147,-150,-189,-98,-100,-99,-86,309,315,-73,143,-72,-204,-203,-202,-211,-172,-184,-173,-171,-175,-179,-174,-170,-177,-182,-168,-167,-176,-183,-178,-180,326,-181,-169,-88,-87,340,-192,-200,-201,-151,-186,-148,-165,]),'$end':([10,11,20,27,30,32,51,66,132,205,299,303,335,],[-27,-23,0,-26,-25,-28,-24,-38,-29,-30,-127,-128,-129,]),'WSTRING_LITERAL':([52,66,70,81,88,89,91,92,94,96,98,100,103,110,128,131,133,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,232,244,245,246,247,248,249,250,251,252,253,254,255,256,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[84,-38,-39,-198,84,-196,-195,84,84,-194,84,84,-193,-197,84,84,-40,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,-32,-35,-31,84,84,-33,84,84,-130,-36,84,-34,84,-155,-158,-156,-152,-153,-157,-159,84,-161,-162,-154,-160,84,84,84,-127,-146,84,-128,-145,84,-143,-131,84,84,84,-142,84,84,84,84,84,-141,-129,-144,-134,84,-132,84,84,-133,84,84,84,-138,-137,-135,84,-139,84,-136,84,-140,]),'DIVIDE':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,174,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,174,174,174,174,174,174,174,174,174,174,-168,-167,174,174,174,174,174,-169,-192,-200,-201,-186,]),'FOR':([66,70,131,133,206,207,211,212,214,217,223,224,227,228,299,300,301,303,304,307,308,309,313,315,334,335,336,338,340,343,352,353,354,356,358,359,361,363,364,366,367,368,],[-38,-39,215,-40,-32,-35,-31,215,-33,215,-130,-36,215,-34,-127,-146,215,-128,-145,-143,-131,215,-142,215,-141,-129,-144,-134,215,-132,215,-133,215,215,-138,-137,-135,-139,215,-136,215,-140,]),'PLUSPLUS':([52,66,70,81,83,84,85,86,87,88,89,90,91,92,94,95,96,97,98,100,101,102,103,106,107,110,111,128,131,133,143,146,149,151,152,153,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,229,232,238,239,242,244,245,246,247,248,249,250,251,252,253,254,255,256,260,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,320,321,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[94,-38,-39,-198,-219,-210,-220,-218,-208,94,-196,149,-195,94,94,-217,-194,-199,94,94,-214,-209,-193,-216,-215,-197,-207,94,94,-40,94,94,-205,94,94,-206,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,-32,-35,-31,94,94,-33,94,94,-130,-36,94,-34,-214,94,-204,-203,-202,-155,-158,-156,-152,-153,-157,-159,94,-161,-162,-154,-160,94,-211,94,94,-127,-146,94,-128,-145,94,-143,-131,94,94,94,-142,94,94,-200,-201,94,94,94,-141,-129,-144,-134,94,-132,94,94,-133,94,94,94,-138,-137,-135,94,-139,94,-136,94,-140,]),'EQUALS':([23,28,50,64,73,82,83,84,85,86,87,90,95,97,101,102,106,107,111,123,130,147,149,153,154,156,157,163,183,184,185,229,238,239,242,260,319,320,321,324,],[-94,-96,-95,128,-97,-185,-219,-210,-220,-218,-208,-187,-217,-199,-214,-209,-216,-215,-207,199,128,-191,-205,-206,-190,-188,247,-189,-98,-100,-99,-214,-204,-203,-202,-211,-192,-200,-201,-186,]),'ELSE':([206,207,211,214,224,228,299,300,303,304,307,313,334,335,336,338,343,353,358,359,361,363,366,368,],[-32,-35,-31,-33,-36,-34,-127,-146,-128,-145,-143,-142,-141,-129,-144,-134,-132,-133,-138,-137,364,-139,-136,-140,]),'EQ':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,178,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,178,-173,-171,-175,-179,-174,-170,-177,178,-168,-167,-176,178,-178,178,178,-169,-192,-200,-201,-186,]),'AND':([52,66,70,81,82,83,84,85,86,87,88,89,90,91,92,94,95,96,97,98,99,100,101,102,103,104,106,107,110,111,128,131,133,143,146,147,149,151,152,153,154,155,156,157,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,229,232,238,239,242,244,245,246,247,248,249,250,251,252,253,254,255,256,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,319,320,321,322,324,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[103,-38,-39,-198,-185,-219,-210,-220,-218,-208,103,-196,-187,-195,103,103,-217,-194,-199,103,-166,103,-214,-209,-193,179,-216,-215,-197,-207,103,103,-40,103,103,-191,-205,103,103,-206,-190,103,-188,-185,-189,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,-32,-35,-31,103,103,-33,103,103,-130,-36,103,-34,-214,103,-204,-203,-202,-155,-158,-156,-152,-153,-157,-159,103,-161,-162,-154,-160,103,-211,103,-172,179,-173,-171,-175,-179,-174,-170,-177,179,-168,-167,-176,179,-178,-180,179,-169,103,-127,-146,103,-128,-145,103,-143,-131,103,103,103,-142,103,103,-192,-200,-201,103,-186,103,103,-141,-129,-144,-134,103,-132,103,103,-133,103,103,103,-138,-137,-135,103,-139,103,-136,103,-140,]),'TYPEID':([0,1,2,3,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,21,22,23,24,27,28,29,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[22,22,-51,-61,-60,-49,46,-46,-47,-27,-23,22,-45,-57,-53,-58,-75,-44,22,-48,-149,-94,54,-26,-96,-74,-25,-50,-28,-52,-55,22,-56,-54,-59,-62,22,-70,22,-69,-95,-24,22,-85,-84,22,-38,-39,22,-97,22,22,22,-76,22,22,22,22,-29,-40,22,-77,-71,22,22,-98,-100,-99,22,22,-86,-30,22,-73,-78,-72,22,22,-88,-87,-127,-128,-129,]),'LBRACE':([7,18,23,24,28,29,41,46,48,50,54,56,64,66,68,70,71,72,73,128,129,131,133,183,184,185,204,206,207,211,212,214,217,223,224,227,228,299,300,301,303,304,307,308,309,313,315,332,334,335,336,338,340,343,352,353,354,356,358,359,361,363,364,366,367,368,],[47,-75,-94,55,-96,-74,-221,74,80,-95,120,124,-221,-38,-5,-39,131,-6,-97,204,131,131,-40,-98,-100,-99,204,-32,-35,-31,131,-33,131,-130,-36,131,-34,-127,-146,131,-128,-145,-143,-131,131,-142,131,204,-141,-129,-144,-134,131,-132,131,-133,131,131,-138,-137,-135,-139,131,-136,131,-140,]),'PPHASH':([0,10,11,20,27,30,32,51,66,132,205,299,303,335,],[32,-27,-23,32,-26,-25,-28,-24,-38,-29,-30,-127,-128,-129,]),'INT':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[33,33,-51,-61,-60,-49,-46,-47,-27,-23,33,-45,-57,-53,-58,-44,33,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,33,-56,-54,-59,-62,33,-70,33,-69,-95,-24,33,-85,-84,33,-38,-39,33,-97,33,33,33,-76,33,33,33,33,-29,-40,33,-77,-71,33,33,-98,-100,-99,33,33,-86,-30,33,-73,-78,-72,33,33,-88,-87,-127,-128,-129,]),'SIGNED':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[37,37,-51,-61,-60,-49,-46,-47,-27,-23,37,-45,-57,-53,-58,-44,37,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,37,-56,-54,-59,-62,37,-70,37,-69,-95,-24,37,-85,-84,37,-38,-39,37,-97,37,37,37,-76,37,37,37,37,-29,-40,37,-77,-71,37,37,-98,-100,-99,37,37,-86,-30,37,-73,-78,-72,37,37,-88,-87,-127,-128,-129,]),'CONTINUE':([66,70,131,133,206,207,211,212,214,217,223,224,227,228,299,300,301,303,304,307,308,309,313,315,334,335,336,338,340,343,352,353,354,356,358,359,361,363,364,366,367,368,],[-38,-39,216,-40,-32,-35,-31,216,-33,216,-130,-36,216,-34,-127,-146,216,-128,-145,-143,-131,216,-142,216,-141,-129,-144,-134,216,-132,216,-133,216,216,-138,-137,-135,-139,216,-136,216,-140,]),'NOT':([52,66,70,81,88,89,91,92,94,96,98,100,103,110,128,131,133,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,232,244,245,246,247,248,249,250,251,252,253,254,255,256,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[110,-38,-39,-198,110,-196,-195,110,110,-194,110,110,-193,-197,110,110,-40,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,-32,-35,-31,110,110,-33,110,110,-130,-36,110,-34,110,-155,-158,-156,-152,-153,-157,-159,110,-161,-162,-154,-160,110,110,110,-127,-146,110,-128,-145,110,-143,-131,110,110,110,-142,110,110,110,110,110,-141,-129,-144,-134,110,-132,110,110,-133,110,110,110,-138,-137,-135,110,-139,110,-136,110,-140,]),'OREQUAL':([82,83,84,85,86,87,90,95,97,101,102,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-214,-209,-216,-215,-207,-191,-205,-206,-190,-188,253,-189,-214,-204,-203,-202,-211,-192,-200,-201,-186,]),'MOD':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,182,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,182,182,182,182,182,182,182,182,182,182,-168,-167,182,182,182,182,182,-169,-192,-200,-201,-186,]),'RSHIFT':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,164,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,164,-173,-171,164,164,164,-170,164,164,-168,-167,164,164,164,164,164,-169,-192,-200,-201,-186,]),'DEFAULT':([66,70,131,133,206,207,211,212,214,217,223,224,227,228,299,300,301,303,304,307,308,309,313,315,334,335,336,338,340,343,352,353,354,356,358,359,361,363,364,366,367,368,],[-38,-39,219,-40,-32,-35,-31,219,-33,219,-130,-36,219,-34,-127,-146,219,-128,-145,-143,-131,219,-142,219,-141,-129,-144,-134,219,-132,219,-133,219,219,-138,-137,-135,-139,219,-136,219,-140,]),'CHAR':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[31,31,-51,-61,-60,-49,-46,-47,-27,-23,31,-45,-57,-53,-58,-44,31,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,31,-56,-54,-59,-62,31,-70,31,-69,-95,-24,31,-85,-84,31,-38,-39,31,-97,31,31,31,-76,31,31,31,31,-29,-40,31,-77,-71,31,31,-98,-100,-99,31,31,-86,-30,31,-73,-78,-72,31,31,-88,-87,-127,-128,-129,]),'WHILE':([66,70,131,133,206,207,211,212,214,217,223,224,227,228,299,300,301,303,304,307,308,309,313,314,315,334,335,336,338,340,343,352,353,354,356,358,359,361,363,364,366,367,368,],[-38,-39,220,-40,-32,-35,-31,220,-33,220,-130,-36,220,-34,-127,-146,220,-128,-145,-143,-131,220,-142,342,220,-141,-129,-144,-134,220,-132,220,-133,220,220,-138,-137,-135,-139,220,-136,220,-140,]),'DIVEQUAL':([82,83,84,85,86,87,90,95,97,101,102,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-214,-209,-216,-215,-207,-191,-205,-206,-190,-188,244,-189,-214,-204,-203,-202,-211,-192,-200,-201,-186,]),'EXTERN':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,48,50,51,53,54,56,64,66,70,72,73,131,132,133,136,183,184,185,186,195,197,205,212,231,236,258,287,292,295,299,303,335,],[9,9,-51,-61,-60,-49,-46,-47,-27,-23,9,-45,-57,-53,-58,-44,9,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,9,-56,-54,-59,-62,9,-70,-69,-95,-24,9,-85,-84,9,-38,-39,9,-97,9,-29,-40,-71,-98,-100,-99,9,9,-86,-30,9,-73,-72,9,9,-88,-87,-127,-128,-129,]),'CASE':([66,70,131,133,206,207,211,212,214,217,223,224,227,228,299,300,301,303,304,307,308,309,313,315,334,335,336,338,340,343,352,353,354,356,358,359,361,363,364,366,367,368,],[-38,-39,221,-40,-32,-35,-31,221,-33,221,-130,-36,221,-34,-127,-146,221,-128,-145,-143,-131,221,-142,221,-141,-129,-144,-134,221,-132,221,-133,221,221,-138,-137,-135,-139,221,-136,221,-140,]),'LAND':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,177,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,177,-173,-171,-175,-179,-174,-170,-177,-182,-168,-167,-176,-183,-178,-180,-181,-169,-192,-200,-201,-186,]),'REGISTER':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,48,50,51,53,54,56,64,66,70,72,73,131,132,133,136,183,184,185,186,195,197,205,212,231,236,258,287,292,295,299,303,335,],[14,14,-51,-61,-60,-49,-46,-47,-27,-23,14,-45,-57,-53,-58,-44,14,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,14,-56,-54,-59,-62,14,-70,-69,-95,-24,14,-85,-84,14,-38,-39,14,-97,14,-29,-40,-71,-98,-100,-99,14,14,-86,-30,14,-73,-72,14,14,-88,-87,-127,-128,-129,]),'MODEQUAL':([82,83,84,85,86,87,90,95,97,101,102,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-214,-209,-216,-215,-207,-191,-205,-206,-190,-188,246,-189,-214,-204,-203,-202,-211,-192,-200,-201,-186,]),'NE':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,169,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,169,-173,-171,-175,-179,-174,-170,-177,169,-168,-167,-176,169,-178,169,169,-169,-192,-200,-201,-186,]),'SWITCH':([66,70,131,133,206,207,211,212,214,217,223,224,227,228,299,300,301,303,304,307,308,309,313,315,334,335,336,338,340,343,352,353,354,356,358,359,361,363,364,366,367,368,],[-38,-39,222,-40,-32,-35,-31,222,-33,222,-130,-36,222,-34,-127,-146,222,-128,-145,-143,-131,222,-142,222,-141,-129,-144,-134,222,-132,222,-133,222,222,-138,-137,-135,-139,222,-136,222,-140,]),'INT_CONST_HEX':([52,66,70,81,88,89,91,92,94,96,98,100,103,110,128,131,133,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,232,244,245,246,247,248,249,250,251,252,253,254,255,256,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[95,-38,-39,-198,95,-196,-195,95,95,-194,95,95,-193,-197,95,95,-40,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,-32,-35,-31,95,95,-33,95,95,-130,-36,95,-34,95,-155,-158,-156,-152,-153,-157,-159,95,-161,-162,-154,-160,95,95,95,-127,-146,95,-128,-145,95,-143,-131,95,95,95,-142,95,95,95,95,95,-141,-129,-144,-134,95,-132,95,95,-133,95,95,95,-138,-137,-135,95,-139,95,-136,95,-140,]),'PLUSEQUAL':([82,83,84,85,86,87,90,95,97,101,102,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-214,-209,-216,-215,-207,-191,-205,-206,-190,-188,249,-189,-214,-204,-203,-202,-211,-192,-200,-201,-186,]),'STRUCT':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[29,29,-51,-61,-60,-49,-46,-47,-27,-23,29,-45,-57,-53,-58,-44,29,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,29,-56,-54,-59,-62,29,-70,29,-69,-95,-24,29,-85,-84,29,-38,-39,29,-97,29,29,29,-76,29,29,29,29,-29,-40,29,-77,-71,29,29,-98,-100,-99,29,29,-86,-30,29,-73,-78,-72,29,29,-88,-87,-127,-128,-129,]),'CONDOP':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,180,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,-184,-173,-171,-175,-179,-174,-170,-177,-182,-168,-167,-176,-183,-178,-180,-181,-169,-192,-200,-201,-186,]),'BREAK':([66,70,131,133,206,207,211,212,214,217,223,224,227,228,299,300,301,303,304,307,308,309,313,315,334,335,336,338,340,343,352,353,354,356,358,359,361,363,364,366,367,368,],[-38,-39,225,-40,-32,-35,-31,225,-33,225,-130,-36,225,-34,-127,-146,225,-128,-145,-143,-131,225,-142,225,-141,-129,-144,-134,225,-132,225,-133,225,225,-138,-137,-135,-139,225,-136,225,-140,]),'VOLATILE':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,25,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,57,59,64,66,70,72,73,74,75,76,77,78,80,98,125,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[40,40,-51,-61,-60,-49,-46,-47,-27,-23,40,-45,-57,-53,-58,-44,40,-48,-149,-94,40,-26,-96,-25,-50,-28,-52,-55,40,-56,-54,-59,-62,40,-70,40,-69,-95,-24,40,-85,-84,40,-103,40,-38,-39,40,-97,40,40,40,-76,40,40,40,-104,40,-29,-40,40,-77,-71,40,40,-98,-100,-99,40,40,-86,-30,40,-73,-78,-72,40,40,-88,-87,-127,-128,-129,]),'ANDEQUAL':([82,83,84,85,86,87,90,95,97,101,102,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-214,-209,-216,-215,-207,-191,-205,-206,-190,-188,252,-189,-214,-204,-203,-202,-211,-192,-200,-201,-186,]),'DO':([66,70,131,133,206,207,211,212,214,217,223,224,227,228,299,300,301,303,304,307,308,309,313,315,334,335,336,338,340,343,352,353,354,356,358,359,361,363,364,366,367,368,],[-38,-39,227,-40,-32,-35,-31,227,-33,227,-130,-36,227,-34,-127,-146,227,-128,-145,-143,-131,227,-142,227,-141,-129,-144,-134,227,-132,227,-133,227,227,-138,-137,-135,-139,227,-136,227,-140,]),'LNOT':([52,66,70,81,88,89,91,92,94,96,98,100,103,110,128,131,133,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,232,244,245,246,247,248,249,250,251,252,253,254,255,256,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[81,-38,-39,-198,81,-196,-195,81,81,-194,81,81,-193,-197,81,81,-40,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,-32,-35,-31,81,81,-33,81,81,-130,-36,81,-34,81,-155,-158,-156,-152,-153,-157,-159,81,-161,-162,-154,-160,81,81,81,-127,-146,81,-128,-145,81,-143,-131,81,81,81,-142,81,81,81,81,81,-141,-129,-144,-134,81,-132,81,81,-133,81,81,81,-138,-137,-135,81,-139,81,-136,81,-140,]),'CONST':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,25,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,57,59,64,66,70,72,73,74,75,76,77,78,80,98,125,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[3,3,-51,-61,-60,-49,-46,-47,-27,-23,3,-45,-57,-53,-58,-44,3,-48,-149,-94,3,-26,-96,-25,-50,-28,-52,-55,3,-56,-54,-59,-62,3,-70,3,-69,-95,-24,3,-85,-84,3,-103,3,-38,-39,3,-97,3,3,3,-76,3,3,3,-104,3,-29,-40,3,-77,-71,3,3,-98,-100,-99,3,3,-86,-30,3,-73,-78,-72,3,3,-88,-87,-127,-128,-129,]),'LOR':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,165,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,-184,-173,-171,-175,-179,-174,-170,-177,-182,-168,-167,-176,-183,-178,-180,-181,-169,-192,-200,-201,-186,]),'CHAR_CONST':([52,66,70,81,88,89,91,92,94,96,98,100,103,110,128,131,133,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,232,244,245,246,247,248,249,250,251,252,253,254,255,256,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[83,-38,-39,-198,83,-196,-195,83,83,-194,83,83,-193,-197,83,83,-40,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,-32,-35,-31,83,83,-33,83,83,-130,-36,83,-34,83,-155,-158,-156,-152,-153,-157,-159,83,-161,-162,-154,-160,83,83,83,-127,-146,83,-128,-145,83,-143,-131,83,83,83,-142,83,83,83,83,83,-141,-129,-144,-134,83,-132,83,83,-133,83,83,83,-138,-137,-135,83,-139,83,-136,83,-140,]),'LSHIFT':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,166,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,166,-173,-171,166,166,166,-170,166,166,-168,-167,166,166,166,166,166,-169,-192,-200,-201,-186,]),'GOTO':([66,70,131,133,206,207,211,212,214,217,223,224,227,228,299,300,301,303,304,307,308,309,313,315,334,335,336,338,340,343,352,353,354,356,358,359,361,363,364,366,367,368,],[-38,-39,208,-40,-32,-35,-31,208,-33,208,-130,-36,208,-34,-127,-146,208,-128,-145,-143,-131,208,-142,208,-141,-129,-144,-134,208,-132,208,-133,208,208,-138,-137,-135,-139,208,-136,208,-140,]),'LE':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,168,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,168,-173,-171,-175,168,-174,-170,-177,168,-168,-167,-176,168,168,168,168,-169,-192,-200,-201,-186,]),'SEMI':([1,2,3,5,6,8,9,12,14,15,16,17,19,21,22,23,26,28,31,33,34,35,36,37,38,39,40,42,43,44,46,48,49,50,54,56,61,62,63,64,65,66,67,69,70,73,82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,109,111,130,131,133,136,141,142,144,147,149,153,154,156,157,159,161,163,183,184,185,197,201,202,203,206,207,210,211,212,213,214,216,217,218,223,224,225,226,227,228,229,231,233,236,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,292,295,298,299,300,301,302,303,304,305,306,307,308,309,313,315,317,318,319,320,321,323,324,325,333,334,335,336,337,338,340,343,346,350,351,352,353,354,356,357,358,359,361,363,364,366,367,368,],[-221,-51,-61,-60,-49,-46,-47,-221,-45,-57,-53,-58,-44,-48,-149,-94,-221,-96,-50,-52,-55,66,-221,-56,-54,-59,-62,-43,-7,-8,-70,-69,-42,-95,-85,-84,-14,-37,-13,-65,-63,-38,-41,-221,-39,-97,-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,-164,-216,-215,-163,-207,-65,-221,-40,-71,-79,-81,235,-191,-205,-206,-190,-188,-185,-147,-150,-189,-98,-100,-99,-86,-64,-66,-113,-32,-35,300,-31,-221,304,-33,307,-221,-10,-130,-36,313,-9,-221,-34,-214,-73,-83,-72,-204,-203,-202,-211,-172,-184,-173,-171,-175,-179,-174,-170,-177,-182,-168,-167,-176,-183,-178,-180,-181,-169,-88,-87,334,-127,-146,-221,-9,-128,-145,336,-221,-143,-131,-221,-142,-221,-82,-80,-192,-200,-201,-151,-186,-148,-114,-141,-129,-144,351,-134,-221,-132,-165,-115,-221,-221,-133,-221,-221,362,-138,-137,-135,-139,-221,-136,-221,-140,]),'LT':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,170,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,170,-173,-171,-175,170,-174,-170,-177,170,-168,-167,-176,170,170,170,170,-169,-192,-200,-201,-186,]),'COMMA':([1,2,3,5,6,8,9,12,14,15,16,17,19,21,22,23,25,28,31,33,34,36,37,38,39,40,42,43,44,46,48,49,50,54,56,57,58,59,60,61,64,65,67,73,82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,109,111,115,116,117,118,119,121,122,123,125,126,130,136,141,142,144,147,149,153,154,156,157,159,161,162,163,183,184,185,187,188,190,191,192,193,196,197,198,200,201,202,203,218,229,231,233,236,238,239,240,241,242,243,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,288,289,291,292,293,294,295,296,297,305,317,318,319,320,321,323,324,325,327,328,329,333,339,341,344,345,346,347,348,349,350,360,],[-221,-51,-61,-60,-49,-46,-47,-221,-45,-57,-53,-58,-44,-48,-149,-94,-221,-96,-50,-52,-55,-221,-56,-54,-59,-62,-43,-7,-8,-70,-69,-42,-95,-85,-84,-22,-101,-103,-21,127,-65,-63,-41,-97,-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,-164,-216,-215,-163,-207,-107,-221,194,195,-111,-89,198,-92,-104,-102,-65,-71,-79,-81,234,-191,-205,-206,-190,-188,-185,-147,-150,261,-189,-98,-100,-99,-110,-2,-109,-121,-119,-1,198,-86,-90,198,-64,-66,-113,261,-214,-73,-83,-72,-204,-203,261,-212,-202,322,-211,-172,-184,-173,-171,-175,-179,-174,-170,-177,-182,-168,-167,-176,-183,-178,-180,261,-181,-169,-120,-112,-108,-88,-91,-93,-87,-116,332,261,-82,-80,-192,-200,-201,-151,-186,-148,-126,-122,-124,-114,261,261,261,-213,-165,-123,-125,-117,-115,261,]),'TYPEDEF':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,48,50,51,53,54,56,64,66,70,72,73,131,132,133,136,183,184,185,186,195,197,205,212,231,236,258,287,292,295,299,303,335,],[21,21,-51,-61,-60,-49,-46,-47,-27,-23,21,-45,-57,-53,-58,-44,21,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,21,-56,-54,-59,-62,21,-70,-69,-95,-24,21,-85,-84,21,-38,-39,21,-97,21,-29,-40,-71,-98,-100,-99,21,21,-86,-30,21,-73,-72,21,21,-88,-87,-127,-128,-129,]),'XOR':([82,83,84,85,86,87,90,95,97,99,101,102,104,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-166,-214,-209,173,-216,-215,-207,-191,-205,-206,-190,-188,-185,-189,-214,-204,-203,-202,-211,-172,173,-173,-171,-175,-179,-174,-170,-177,-182,-168,-167,-176,173,-178,-180,173,-169,-192,-200,-201,-186,]),'AUTO':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,48,50,51,53,54,56,64,66,70,72,73,131,132,133,136,183,184,185,186,195,197,205,212,231,236,258,287,292,295,299,303,335,],[19,19,-51,-61,-60,-49,-46,-47,-27,-23,19,-45,-57,-53,-58,-44,19,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,19,-56,-54,-59,-62,19,-70,-69,-95,-24,19,-85,-84,19,-38,-39,19,-97,19,-29,-40,-71,-98,-100,-99,19,19,-86,-30,19,-73,-72,19,19,-88,-87,-127,-128,-129,]),'TIMES':([0,1,2,3,4,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,25,26,27,30,31,32,33,34,36,37,38,39,40,42,43,44,46,48,49,51,52,54,56,57,58,59,60,66,67,69,70,76,78,79,81,82,83,84,85,86,87,88,89,90,91,92,94,95,96,97,98,99,100,101,102,103,104,106,107,110,111,116,125,127,128,131,132,133,136,137,138,139,140,143,146,147,149,151,152,153,154,155,156,157,160,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,186,189,197,199,204,205,206,207,211,212,213,214,217,221,223,224,227,228,229,231,232,234,236,238,239,242,244,245,246,247,248,249,250,251,252,253,254,255,256,258,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,286,292,295,299,300,301,303,304,306,307,308,309,310,312,313,315,316,319,320,321,322,324,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[25,-221,-51,-61,25,-60,-49,-46,-47,-27,-23,-221,-45,-57,-53,-58,-44,25,-48,-149,-221,25,-26,-25,-50,-28,-52,-55,-221,-56,-54,-59,-62,-43,-7,-8,-70,-69,-42,-24,96,-85,-84,-22,25,-103,-21,-38,-41,25,-39,-221,-221,25,-198,-185,-219,-210,-220,-218,-208,96,-196,-187,-195,96,96,-217,-194,-199,96,-166,96,-214,-209,-193,175,-216,-215,-197,-207,25,-104,25,96,96,-29,-40,-71,-17,-68,-18,-67,96,96,-191,-205,96,96,-206,-190,96,-188,-185,25,-189,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,25,96,-86,96,96,-30,-32,-35,-31,96,96,-33,96,96,-130,-36,96,-34,-214,-73,96,25,-72,-204,-203,-202,-155,-158,-156,-152,-153,-157,-159,96,-161,-162,-154,-160,96,25,-211,96,175,175,175,175,175,175,175,175,175,175,-168,-167,175,175,175,175,175,-169,96,-88,-87,-127,-146,96,-128,-145,96,-143,-131,96,96,96,-142,96,96,-192,-200,-201,96,-186,96,96,-141,-129,-144,-134,96,-132,96,96,-133,96,96,96,-138,-137,-135,96,-139,96,-136,96,-140,]),'LPAREN':([0,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,25,26,27,28,30,31,32,33,34,36,37,38,39,40,42,43,44,46,48,49,50,51,52,54,56,57,58,59,60,66,67,69,70,73,76,78,79,81,83,84,85,86,87,88,89,90,91,92,94,95,96,97,98,100,101,102,103,106,107,110,111,116,125,126,127,128,131,132,133,136,137,138,139,140,143,146,149,151,152,153,155,160,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,189,191,192,197,199,204,205,206,207,211,212,213,214,215,217,220,221,222,223,224,227,228,229,230,231,232,234,236,238,239,242,244,245,246,247,248,249,250,251,252,253,254,255,256,258,259,260,261,286,288,292,295,299,300,301,303,304,306,307,308,309,310,312,313,315,316,320,321,322,326,327,328,329,332,334,335,336,338,340,342,343,347,348,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[4,-221,-51,-61,4,-60,-49,-46,-47,-27,-23,-221,4,-45,-57,-53,-58,-44,4,-48,-149,53,-221,4,-26,-96,-25,-50,-28,-52,-55,-221,-56,-54,-59,-62,-43,-7,-8,-70,-69,-42,53,-24,98,-85,-84,-22,-101,-103,-21,-38,-41,4,-39,-97,-221,-221,4,-198,-219,-210,-220,-218,-208,146,-196,152,-195,98,155,-217,-194,-199,98,155,-214,-209,-193,-216,-215,-197,-207,186,-104,-102,4,98,98,-29,-40,-71,-17,-68,-18,-67,98,98,-205,98,98,-206,98,258,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,-98,-100,-99,186,98,287,186,-86,98,98,-30,-32,-35,-31,98,98,-33,306,98,310,98,312,-130,-36,98,-34,-214,316,-73,98,4,-72,-204,-203,-202,-155,-158,-156,-152,-153,-157,-159,98,-161,-162,-154,-160,98,258,258,-211,98,98,287,-88,-87,-127,-146,98,-128,-145,98,-143,-131,98,98,98,-142,98,98,-200,-201,98,98,-126,-122,-124,98,-141,-129,-144,-134,98,355,-132,-123,-125,98,98,-133,98,98,98,-138,-137,-135,98,-139,98,-136,98,-140,]),'MINUSMINUS':([52,66,70,81,83,84,85,86,87,88,89,90,91,92,94,95,96,97,98,100,101,102,103,106,107,110,111,128,131,133,143,146,149,151,152,153,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,229,232,238,239,242,244,245,246,247,248,249,250,251,252,253,254,255,256,260,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,320,321,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[100,-38,-39,-198,-219,-210,-220,-218,-208,100,-196,153,-195,100,100,-217,-194,-199,100,100,-214,-209,-193,-216,-215,-197,-207,100,100,-40,100,100,-205,100,100,-206,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,-32,-35,-31,100,100,-33,100,100,-130,-36,100,-34,-214,100,-204,-203,-202,-155,-158,-156,-152,-153,-157,-159,100,-161,-162,-154,-160,100,-211,100,100,-127,-146,100,-128,-145,100,-143,-131,100,100,100,-142,100,100,-200,-201,100,100,100,-141,-129,-144,-134,100,-132,100,100,-133,100,100,100,-138,-137,-135,100,-139,100,-136,100,-140,]),'ID':([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,24,25,26,27,29,30,31,32,33,34,36,37,38,39,40,42,43,44,46,48,49,51,52,53,54,55,56,57,58,59,60,66,67,69,70,76,78,79,81,88,89,91,92,94,96,98,100,103,110,116,120,124,125,126,127,128,131,132,133,136,137,138,139,140,143,146,148,150,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,186,189,192,194,197,198,199,204,205,206,207,208,211,212,213,214,217,221,223,224,227,228,231,232,234,236,244,245,246,247,248,249,250,251,252,253,254,255,256,261,286,292,295,299,300,301,303,304,306,307,308,309,310,312,313,315,316,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[28,-221,-51,-61,28,-60,-49,48,-46,-47,-27,-23,-221,28,-45,-57,-53,-58,-75,-44,28,-48,-149,56,-221,28,-26,-74,-25,-50,-28,-52,-55,-221,-56,-54,-59,-62,-43,-7,-8,-70,-69,-42,-24,101,101,-85,123,-84,-22,-101,-103,-21,-38,-41,28,-39,-221,-221,28,-198,101,-196,-195,101,101,-194,101,101,-193,-197,28,123,123,-104,-102,28,101,229,-29,-40,-71,-17,-68,-18,-67,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,28,101,28,101,-86,123,101,101,-30,-32,-35,298,-31,229,101,-33,229,101,-130,-36,229,-34,-73,101,28,-72,-155,-158,-156,-152,-153,-157,-159,101,-161,-162,-154,-160,101,101,101,-88,-87,-127,-146,229,-128,-145,101,-143,-131,229,101,101,-142,229,101,101,101,101,-141,-129,-144,-134,229,-132,101,229,-133,229,101,229,-138,-137,-135,101,-139,229,-136,229,-140,]),'IF':([66,70,131,133,206,207,211,212,214,217,223,224,227,228,299,300,301,303,304,307,308,309,313,315,334,335,336,338,340,343,352,353,354,356,358,359,361,363,364,366,367,368,],[-38,-39,230,-40,-32,-35,-31,230,-33,230,-130,-36,230,-34,-127,-146,230,-128,-145,-143,-131,230,-142,230,-141,-129,-144,-134,230,-132,230,-133,230,230,-138,-137,-135,-139,230,-136,230,-140,]),'STRING_LITERAL':([52,66,70,81,88,89,91,92,94,96,98,100,103,110,128,131,133,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,206,207,211,212,213,214,217,221,223,224,227,228,232,244,245,246,247,248,249,250,251,252,253,254,255,256,261,286,299,300,301,303,304,306,307,308,309,310,312,313,315,316,322,326,332,334,335,336,338,340,343,351,352,353,354,355,356,358,359,361,362,363,364,366,367,368,],[102,-38,-39,-198,102,-196,-195,102,102,-194,102,102,-193,-197,102,102,-40,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,-32,-35,-31,102,102,-33,102,102,-130,-36,102,-34,102,-155,-158,-156,-152,-153,-157,-159,102,-161,-162,-154,-160,102,102,102,-127,-146,102,-128,-145,102,-143,-131,102,102,102,-142,102,102,102,102,102,-141,-129,-144,-134,102,-132,102,102,-133,102,102,102,-138,-137,-135,102,-139,102,-136,102,-140,]),'FLOAT':([0,1,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,27,28,30,31,32,33,34,36,37,38,39,40,41,46,47,48,50,51,53,54,56,64,66,70,72,73,74,75,76,77,78,80,98,131,132,133,134,135,136,145,146,183,184,185,186,195,197,205,212,231,235,236,258,287,292,295,299,303,335,],[38,38,-51,-61,-60,-49,-46,-47,-27,-23,38,-45,-57,-53,-58,-44,38,-48,-149,-94,-26,-96,-25,-50,-28,-52,-55,38,-56,-54,-59,-62,38,-70,38,-69,-95,-24,38,-85,-84,38,-38,-39,38,-97,38,38,38,-76,38,38,38,38,-29,-40,38,-77,-71,38,38,-98,-100,-99,38,38,-86,-30,38,-73,-78,-72,38,38,-88,-87,-127,-128,-129,]),'XOREQUAL':([82,83,84,85,86,87,90,95,97,101,102,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-214,-209,-216,-215,-207,-191,-205,-206,-190,-188,248,-189,-214,-204,-203,-202,-211,-192,-200,-201,-186,]),'LSHIFTEQUAL':([82,83,84,85,86,87,90,95,97,101,102,106,107,111,147,149,153,154,156,157,163,229,238,239,242,260,319,320,321,324,],[-185,-219,-210,-220,-218,-208,-187,-217,-199,-214,-209,-216,-215,-207,-191,-205,-206,-190,-188,250,-189,-214,-204,-203,-202,-211,-192,-200,-201,-186,]),'RBRACKET':([52,82,83,84,85,86,87,90,93,95,97,99,101,102,104,105,106,107,108,109,111,147,149,153,154,156,157,159,161,163,189,238,239,240,242,260,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,279,280,285,286,319,320,321,323,324,325,330,346,],[-221,-185,-219,-210,-220,-218,-208,-187,-3,-217,-199,-166,-214,-209,-164,183,-216,-215,-4,-163,-207,-191,-205,-206,-190,-188,-185,-147,-150,-189,-221,-204,-203,320,-202,-211,-172,-184,-173,-171,-175,-179,-174,-170,-177,-182,-168,-167,-176,-183,-178,-180,-181,-169,329,-221,-192,-200,-201,-151,-186,-148,347,-165,]),} + +_lr_action = { } +for _k, _v in _lr_action_items.items(): + for _x,_y in zip(_v[0],_v[1]): + if not _x in _lr_action: _lr_action[_x] = { } + _lr_action[_x][_k] = _y +del _lr_action_items + +_lr_goto_items = {'storage_class_specifier':([0,1,12,20,36,41,53,64,72,131,186,195,212,258,287,],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,]),'identifier_list_opt':([53,],[112,]),'selection_statement':([131,212,217,227,301,309,315,340,352,354,356,364,367,],[228,228,228,228,228,228,228,228,228,228,228,228,228,]),'constant':([52,88,92,94,98,100,128,131,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,212,213,217,221,227,232,251,256,261,286,301,306,309,310,312,315,316,322,326,332,340,351,352,354,355,356,362,364,367,],[87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,]),'unary_expression':([52,88,92,94,98,100,128,131,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,212,213,217,221,227,232,251,256,261,286,301,306,309,310,312,315,316,322,326,332,340,351,352,354,355,356,362,364,367,],[82,147,82,156,157,163,157,157,82,157,157,157,157,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,157,82,82,82,82,157,157,157,157,82,157,82,157,82,157,82,157,157,157,157,157,157,157,157,82,157,157,157,157,157,157,157,157,157,157,]),'conditional_expression':([52,98,128,131,143,146,151,152,155,180,189,199,204,212,213,217,221,227,232,251,261,286,301,306,309,310,312,315,316,322,326,332,340,351,352,354,355,356,362,364,367,],[109,161,161,161,109,161,161,161,161,161,109,109,161,161,161,161,109,161,109,161,161,109,161,161,161,161,161,161,161,161,346,161,161,161,161,161,161,161,161,161,161,]),'struct_or_union_specifier':([0,1,12,20,36,41,47,53,64,72,74,75,76,78,80,98,131,134,145,146,186,195,212,258,287,],[5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,]),'initializer':([128,204,332,],[202,296,349,]),'abstract_declarator_opt':([116,160,],[187,257,]),'iteration_statement':([131,212,217,227,301,309,315,340,352,354,356,364,367,],[207,207,207,207,207,207,207,207,207,207,207,207,207,]),'init_declarator_list':([26,69,],[61,61,]),'init_declarator_list_opt':([26,69,],[62,62,]),'struct_declaration_list':([47,74,80,],[75,134,145,]),'enumerator':([55,120,124,198,],[121,121,121,293,]),'pp_directive':([0,20,],[10,10,]),'abstract_declarator':([116,160,186,258,],[188,188,284,284,]),'declaration_specifiers_opt':([1,12,36,],[42,49,67,]),'external_declaration':([0,20,],[11,51,]),'type_specifier':([0,1,12,20,36,41,47,53,64,72,74,75,76,78,80,98,131,134,145,146,186,195,212,258,287,],[12,12,12,12,12,12,76,12,12,12,76,76,76,76,76,76,12,76,76,76,12,12,12,12,12,]),'compound_statement':([71,129,131,212,217,227,301,309,315,340,352,354,356,364,367,],[132,205,214,214,214,214,214,214,214,214,214,214,214,214,214,]),'pointer':([0,4,20,26,58,69,79,116,127,160,186,234,258,],[13,13,13,13,126,13,13,192,13,259,192,13,259,]),'type_name':([98,146,],[158,237,]),'postfix_expression':([52,88,92,94,98,100,128,131,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,212,213,217,221,227,232,251,256,261,286,301,306,309,310,312,315,316,322,326,332,340,351,352,354,355,356,362,364,367,],[90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,]),'parameter_type_list_opt':([186,258,287,],[283,283,331,]),'expression_statement':([131,212,217,227,301,309,315,340,352,354,356,364,367,],[206,206,206,206,206,206,206,206,206,206,206,206,206,]),'unary_operator':([52,88,92,94,98,100,128,131,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,212,213,217,221,227,232,251,256,261,286,301,306,309,310,312,315,316,322,326,332,340,351,352,354,355,356,362,364,367,],[92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,]),'cast_expression':([52,92,98,128,131,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,212,213,217,221,227,232,251,256,261,286,301,306,309,310,312,315,316,322,326,332,340,351,352,354,355,356,362,364,367,],[99,154,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,324,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,]),'initializer_list':([204,],[297,]),'struct_declarator_list':([79,],[144,]),'empty':([1,12,25,26,36,41,52,53,64,69,76,78,116,131,160,186,189,212,217,227,258,286,287,301,306,309,315,340,351,352,354,356,362,364,367,],[43,43,60,63,43,68,93,113,68,63,137,137,193,226,193,281,93,302,302,302,281,93,281,302,302,302,302,302,302,302,302,302,302,302,302,]),'assignment_operator':([157,],[251,]),'struct_or_union':([0,1,12,20,36,41,47,53,64,72,74,75,76,78,80,98,131,134,145,146,186,195,212,258,287,],[7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,]),'struct_declaration':([47,74,75,80,134,145,],[77,77,135,77,135,135,]),'assignment_expression':([98,128,131,146,151,152,155,180,204,212,213,217,227,251,261,301,306,309,310,312,315,316,322,332,340,351,352,354,355,356,362,364,367,],[159,203,159,159,159,241,159,159,203,159,159,159,159,323,325,159,159,159,159,159,159,159,345,203,159,159,159,159,159,159,159,159,159,]),'parameter_type_list':([53,186,258,287,],[114,282,282,282,]),'type_qualifier_list_opt':([25,],[58,]),'direct_declarator':([0,4,13,20,26,69,79,116,127,186,192,234,],[23,23,50,23,23,23,23,23,23,23,50,23,]),'type_qualifier_list':([25,],[57,]),'argument_expression_list':([152,],[243,]),'statement_list_opt':([131,],[209,]),'direct_abstract_declarator':([116,160,186,192,258,259,],[191,191,191,288,191,288,]),'specifier_qualifier_list_opt':([76,78,],[138,140,]),'constant_expression':([52,143,189,199,221,232,286,],[108,233,108,294,311,317,108,]),'expression_opt':([131,212,217,227,301,306,309,315,340,351,352,354,356,362,364,367,],[210,210,210,210,210,337,210,210,210,357,210,210,210,365,210,210,]),'primary_expression':([52,88,92,94,98,100,128,131,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,212,213,217,221,227,232,251,256,261,286,301,306,309,310,312,315,316,322,326,332,340,351,352,354,355,356,362,364,367,],[97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,]),'declaration_specifiers':([0,1,12,20,36,41,53,64,72,131,186,195,212,258,287,],[26,44,44,26,44,69,116,69,69,69,116,116,69,116,116,]),'declaration':([0,20,41,64,72,131,212,],[27,27,70,70,133,70,133,]),'declarator':([0,4,20,26,69,79,116,127,186,234,],[41,45,41,64,130,142,190,130,45,142,]),'typedef_name':([0,1,12,20,36,41,47,53,64,72,74,75,76,78,80,98,131,134,145,146,186,195,212,258,287,],[17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,]),'identifier_list':([53,],[117,]),'jump_statement':([131,212,217,227,301,309,315,340,352,354,356,364,367,],[224,224,224,224,224,224,224,224,224,224,224,224,224,]),'declaration_list_opt':([41,64,],[71,129,]),'struct_declarator':([79,234,],[141,318,]),'function_definition':([0,20,],[30,30,]),'binary_expression':([52,98,128,131,143,146,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,199,204,212,213,217,221,227,232,251,261,286,301,306,309,310,312,315,316,322,326,332,340,351,352,354,355,356,362,364,367,],[104,104,104,104,104,104,104,104,104,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,104,279,280,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,]),'parameter_list':([53,186,258,287,],[118,118,118,118,]),'enum_specifier':([0,1,12,20,36,41,47,53,64,72,74,75,76,78,80,98,131,134,145,146,186,195,212,258,287,],[39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,]),'decl_body':([0,20,41,64,72,131,212,],[35,35,35,35,35,35,35,]),'type_qualifier':([0,1,12,20,25,36,41,47,53,57,64,72,74,75,76,78,80,98,131,134,145,146,186,195,212,258,287,],[36,36,36,36,59,36,36,78,36,125,36,36,78,78,78,78,78,78,36,78,78,78,36,36,36,36,36,]),'constant_expression_opt':([52,189,286,],[105,285,330,]),'enumerator_list':([55,120,124,],[122,196,200,]),'labeled_statement':([131,212,217,227,301,309,315,340,352,354,356,364,367,],[211,211,211,211,211,211,211,211,211,211,211,211,211,]),'declaration_list':([41,64,131,],[72,72,212,]),'specifier_qualifier_list':([47,74,75,76,78,80,98,134,145,146,],[79,79,79,139,139,79,160,79,79,160,]),'statement':([131,212,217,227,301,309,315,340,352,354,356,364,367,],[223,223,308,314,308,338,343,353,358,359,361,366,368,]),'translation_unit':([0,],[20,]),'init_declarator':([26,69,127,],[65,65,201,]),'parameter_declaration':([53,186,195,258,287,],[115,115,291,115,115,]),'identifier':([52,53,88,92,94,98,100,128,131,143,146,148,150,151,152,155,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,189,194,199,204,212,213,217,221,227,232,251,256,261,286,301,306,309,310,312,315,316,322,326,332,340,351,352,354,355,356,362,364,367,],[111,119,111,111,111,111,111,111,111,111,111,238,239,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,289,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,]),'expression':([98,131,146,151,155,180,212,213,217,227,301,306,309,310,312,315,316,340,351,352,354,355,356,362,364,367,],[162,218,162,240,162,278,218,305,218,218,218,218,218,339,341,218,344,218,218,218,218,360,218,218,218,218,]),'statement_list':([131,212,],[217,301,]),} + +_lr_goto = { } +for _k, _v in _lr_goto_items.items(): + for _x,_y in zip(_v[0],_v[1]): + if not _x in _lr_goto: _lr_goto[_x] = { } + _lr_goto[_x][_k] = _y +del _lr_goto_items +_lr_productions = [ + ("S' -> translation_unit","S'",1,None,None,None), + ('abstract_declarator_opt -> empty','abstract_declarator_opt',1,'p_abstract_declarator_opt','/home/skybot/ext/parser/pycparser/plyparser.py',41), + ('abstract_declarator_opt -> abstract_declarator','abstract_declarator_opt',1,'p_abstract_declarator_opt','/home/skybot/ext/parser/pycparser/plyparser.py',42), + ('constant_expression_opt -> empty','constant_expression_opt',1,'p_constant_expression_opt','/home/skybot/ext/parser/pycparser/plyparser.py',41), + ('constant_expression_opt -> constant_expression','constant_expression_opt',1,'p_constant_expression_opt','/home/skybot/ext/parser/pycparser/plyparser.py',42), + ('declaration_list_opt -> empty','declaration_list_opt',1,'p_declaration_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',41), + ('declaration_list_opt -> declaration_list','declaration_list_opt',1,'p_declaration_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',42), + ('declaration_specifiers_opt -> empty','declaration_specifiers_opt',1,'p_declaration_specifiers_opt','/home/skybot/ext/parser/pycparser/plyparser.py',41), + ('declaration_specifiers_opt -> declaration_specifiers','declaration_specifiers_opt',1,'p_declaration_specifiers_opt','/home/skybot/ext/parser/pycparser/plyparser.py',42), + ('expression_opt -> empty','expression_opt',1,'p_expression_opt','/home/skybot/ext/parser/pycparser/plyparser.py',41), + ('expression_opt -> expression','expression_opt',1,'p_expression_opt','/home/skybot/ext/parser/pycparser/plyparser.py',42), + ('identifier_list_opt -> empty','identifier_list_opt',1,'p_identifier_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',41), + ('identifier_list_opt -> identifier_list','identifier_list_opt',1,'p_identifier_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',42), + ('init_declarator_list_opt -> empty','init_declarator_list_opt',1,'p_init_declarator_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',41), + ('init_declarator_list_opt -> init_declarator_list','init_declarator_list_opt',1,'p_init_declarator_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',42), + ('parameter_type_list_opt -> empty','parameter_type_list_opt',1,'p_parameter_type_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',41), + ('parameter_type_list_opt -> parameter_type_list','parameter_type_list_opt',1,'p_parameter_type_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',42), + ('specifier_qualifier_list_opt -> empty','specifier_qualifier_list_opt',1,'p_specifier_qualifier_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',41), + ('specifier_qualifier_list_opt -> specifier_qualifier_list','specifier_qualifier_list_opt',1,'p_specifier_qualifier_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',42), + ('statement_list_opt -> empty','statement_list_opt',1,'p_statement_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',41), + ('statement_list_opt -> statement_list','statement_list_opt',1,'p_statement_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',42), + ('type_qualifier_list_opt -> empty','type_qualifier_list_opt',1,'p_type_qualifier_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',41), + ('type_qualifier_list_opt -> type_qualifier_list','type_qualifier_list_opt',1,'p_type_qualifier_list_opt','/home/skybot/ext/parser/pycparser/plyparser.py',42), + ('translation_unit -> external_declaration','translation_unit',1,'p_translation_unit_1','/home/skybot/ext/parser/pycparser/c_parser.py',333), + ('translation_unit -> translation_unit external_declaration','translation_unit',2,'p_translation_unit_2','/home/skybot/ext/parser/pycparser/c_parser.py',340), + ('external_declaration -> function_definition','external_declaration',1,'p_external_declaration_1','/home/skybot/ext/parser/pycparser/c_parser.py',351), + ('external_declaration -> declaration','external_declaration',1,'p_external_declaration_2','/home/skybot/ext/parser/pycparser/c_parser.py',356), + ('external_declaration -> pp_directive','external_declaration',1,'p_external_declaration_3','/home/skybot/ext/parser/pycparser/c_parser.py',361), + ('pp_directive -> PPHASH','pp_directive',1,'p_pp_directive','/home/skybot/ext/parser/pycparser/c_parser.py',366), + ('function_definition -> declarator declaration_list_opt compound_statement','function_definition',3,'p_function_definition_1','/home/skybot/ext/parser/pycparser/c_parser.py',375), + ('function_definition -> declaration_specifiers declarator declaration_list_opt compound_statement','function_definition',4,'p_function_definition_2','/home/skybot/ext/parser/pycparser/c_parser.py',387), + ('statement -> labeled_statement','statement',1,'p_statement','/home/skybot/ext/parser/pycparser/c_parser.py',398), + ('statement -> expression_statement','statement',1,'p_statement','/home/skybot/ext/parser/pycparser/c_parser.py',399), + ('statement -> compound_statement','statement',1,'p_statement','/home/skybot/ext/parser/pycparser/c_parser.py',400), + ('statement -> selection_statement','statement',1,'p_statement','/home/skybot/ext/parser/pycparser/c_parser.py',401), + ('statement -> iteration_statement','statement',1,'p_statement','/home/skybot/ext/parser/pycparser/c_parser.py',402), + ('statement -> jump_statement','statement',1,'p_statement','/home/skybot/ext/parser/pycparser/c_parser.py',403), + ('decl_body -> declaration_specifiers init_declarator_list_opt','decl_body',2,'p_decl_body','/home/skybot/ext/parser/pycparser/c_parser.py',417), + ('declaration -> decl_body SEMI','declaration',2,'p_declaration','/home/skybot/ext/parser/pycparser/c_parser.py',497), + ('declaration_list -> declaration','declaration_list',1,'p_declaration_list','/home/skybot/ext/parser/pycparser/c_parser.py',506), + ('declaration_list -> declaration_list declaration','declaration_list',2,'p_declaration_list','/home/skybot/ext/parser/pycparser/c_parser.py',507), + ('declaration_specifiers -> type_qualifier declaration_specifiers_opt','declaration_specifiers',2,'p_declaration_specifiers_1','/home/skybot/ext/parser/pycparser/c_parser.py',512), + ('declaration_specifiers -> type_specifier declaration_specifiers_opt','declaration_specifiers',2,'p_declaration_specifiers_2','/home/skybot/ext/parser/pycparser/c_parser.py',517), + ('declaration_specifiers -> storage_class_specifier declaration_specifiers_opt','declaration_specifiers',2,'p_declaration_specifiers_3','/home/skybot/ext/parser/pycparser/c_parser.py',522), + ('storage_class_specifier -> AUTO','storage_class_specifier',1,'p_storage_class_specifier','/home/skybot/ext/parser/pycparser/c_parser.py',527), + ('storage_class_specifier -> REGISTER','storage_class_specifier',1,'p_storage_class_specifier','/home/skybot/ext/parser/pycparser/c_parser.py',528), + ('storage_class_specifier -> STATIC','storage_class_specifier',1,'p_storage_class_specifier','/home/skybot/ext/parser/pycparser/c_parser.py',529), + ('storage_class_specifier -> EXTERN','storage_class_specifier',1,'p_storage_class_specifier','/home/skybot/ext/parser/pycparser/c_parser.py',530), + ('storage_class_specifier -> TYPEDEF','storage_class_specifier',1,'p_storage_class_specifier','/home/skybot/ext/parser/pycparser/c_parser.py',531), + ('type_specifier -> VOID','type_specifier',1,'p_type_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',536), + ('type_specifier -> CHAR','type_specifier',1,'p_type_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',537), + ('type_specifier -> SHORT','type_specifier',1,'p_type_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',538), + ('type_specifier -> INT','type_specifier',1,'p_type_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',539), + ('type_specifier -> LONG','type_specifier',1,'p_type_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',540), + ('type_specifier -> FLOAT','type_specifier',1,'p_type_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',541), + ('type_specifier -> DOUBLE','type_specifier',1,'p_type_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',542), + ('type_specifier -> SIGNED','type_specifier',1,'p_type_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',543), + ('type_specifier -> UNSIGNED','type_specifier',1,'p_type_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',544), + ('type_specifier -> typedef_name','type_specifier',1,'p_type_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',545), + ('type_specifier -> enum_specifier','type_specifier',1,'p_type_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',546), + ('type_specifier -> struct_or_union_specifier','type_specifier',1,'p_type_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',547), + ('type_qualifier -> CONST','type_qualifier',1,'p_type_qualifier','/home/skybot/ext/parser/pycparser/c_parser.py',552), + ('type_qualifier -> VOLATILE','type_qualifier',1,'p_type_qualifier','/home/skybot/ext/parser/pycparser/c_parser.py',553), + ('init_declarator_list -> init_declarator','init_declarator_list',1,'p_init_declarator_list','/home/skybot/ext/parser/pycparser/c_parser.py',558), + ('init_declarator_list -> init_declarator_list COMMA init_declarator','init_declarator_list',3,'p_init_declarator_list','/home/skybot/ext/parser/pycparser/c_parser.py',559), + ('init_declarator -> declarator','init_declarator',1,'p_init_declarator','/home/skybot/ext/parser/pycparser/c_parser.py',567), + ('init_declarator -> declarator EQUALS initializer','init_declarator',3,'p_init_declarator','/home/skybot/ext/parser/pycparser/c_parser.py',568), + ('specifier_qualifier_list -> type_qualifier specifier_qualifier_list_opt','specifier_qualifier_list',2,'p_specifier_qualifier_list_1','/home/skybot/ext/parser/pycparser/c_parser.py',573), + ('specifier_qualifier_list -> type_specifier specifier_qualifier_list_opt','specifier_qualifier_list',2,'p_specifier_qualifier_list_2','/home/skybot/ext/parser/pycparser/c_parser.py',578), + ('struct_or_union_specifier -> struct_or_union ID','struct_or_union_specifier',2,'p_struct_or_union_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',586), + ('struct_or_union_specifier -> struct_or_union TYPEID','struct_or_union_specifier',2,'p_struct_or_union_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',587), + ('struct_or_union_specifier -> struct_or_union LBRACE struct_declaration_list RBRACE','struct_or_union_specifier',4,'p_struct_or_union_specifier_2','/home/skybot/ext/parser/pycparser/c_parser.py',596), + ('struct_or_union_specifier -> struct_or_union ID LBRACE struct_declaration_list RBRACE','struct_or_union_specifier',5,'p_struct_or_union_specifier_3','/home/skybot/ext/parser/pycparser/c_parser.py',605), + ('struct_or_union_specifier -> struct_or_union TYPEID LBRACE struct_declaration_list RBRACE','struct_or_union_specifier',5,'p_struct_or_union_specifier_3','/home/skybot/ext/parser/pycparser/c_parser.py',606), + ('struct_or_union -> STRUCT','struct_or_union',1,'p_struct_or_union','/home/skybot/ext/parser/pycparser/c_parser.py',615), + ('struct_or_union -> UNION','struct_or_union',1,'p_struct_or_union','/home/skybot/ext/parser/pycparser/c_parser.py',616), + ('struct_declaration_list -> struct_declaration','struct_declaration_list',1,'p_struct_declaration_list','/home/skybot/ext/parser/pycparser/c_parser.py',623), + ('struct_declaration_list -> struct_declaration_list struct_declaration','struct_declaration_list',2,'p_struct_declaration_list','/home/skybot/ext/parser/pycparser/c_parser.py',624), + ('struct_declaration -> specifier_qualifier_list struct_declarator_list SEMI','struct_declaration',3,'p_struct_declaration_1','/home/skybot/ext/parser/pycparser/c_parser.py',629), + ('struct_declarator_list -> struct_declarator','struct_declarator_list',1,'p_struct_declarator_list','/home/skybot/ext/parser/pycparser/c_parser.py',650), + ('struct_declarator_list -> struct_declarator_list COMMA struct_declarator','struct_declarator_list',3,'p_struct_declarator_list','/home/skybot/ext/parser/pycparser/c_parser.py',651), + ('struct_declarator -> declarator','struct_declarator',1,'p_struct_declarator_1','/home/skybot/ext/parser/pycparser/c_parser.py',659), + ('struct_declarator -> declarator COLON constant_expression','struct_declarator',3,'p_struct_declarator_2','/home/skybot/ext/parser/pycparser/c_parser.py',664), + ('struct_declarator -> COLON constant_expression','struct_declarator',2,'p_struct_declarator_2','/home/skybot/ext/parser/pycparser/c_parser.py',665), + ('enum_specifier -> ENUM ID','enum_specifier',2,'p_enum_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',673), + ('enum_specifier -> ENUM TYPEID','enum_specifier',2,'p_enum_specifier_1','/home/skybot/ext/parser/pycparser/c_parser.py',674), + ('enum_specifier -> ENUM LBRACE enumerator_list RBRACE','enum_specifier',4,'p_enum_specifier_2','/home/skybot/ext/parser/pycparser/c_parser.py',679), + ('enum_specifier -> ENUM ID LBRACE enumerator_list RBRACE','enum_specifier',5,'p_enum_specifier_3','/home/skybot/ext/parser/pycparser/c_parser.py',684), + ('enum_specifier -> ENUM TYPEID LBRACE enumerator_list RBRACE','enum_specifier',5,'p_enum_specifier_3','/home/skybot/ext/parser/pycparser/c_parser.py',685), + ('enumerator_list -> enumerator','enumerator_list',1,'p_enumerator_list','/home/skybot/ext/parser/pycparser/c_parser.py',690), + ('enumerator_list -> enumerator_list COMMA','enumerator_list',2,'p_enumerator_list','/home/skybot/ext/parser/pycparser/c_parser.py',691), + ('enumerator_list -> enumerator_list COMMA enumerator','enumerator_list',3,'p_enumerator_list','/home/skybot/ext/parser/pycparser/c_parser.py',692), + ('enumerator -> ID','enumerator',1,'p_enumerator','/home/skybot/ext/parser/pycparser/c_parser.py',703), + ('enumerator -> ID EQUALS constant_expression','enumerator',3,'p_enumerator','/home/skybot/ext/parser/pycparser/c_parser.py',704), + ('declarator -> direct_declarator','declarator',1,'p_declarator_1','/home/skybot/ext/parser/pycparser/c_parser.py',716), + ('declarator -> pointer direct_declarator','declarator',2,'p_declarator_2','/home/skybot/ext/parser/pycparser/c_parser.py',721), + ('direct_declarator -> ID','direct_declarator',1,'p_direct_declarator_1','/home/skybot/ext/parser/pycparser/c_parser.py',726), + ('direct_declarator -> LPAREN declarator RPAREN','direct_declarator',3,'p_direct_declarator_2','/home/skybot/ext/parser/pycparser/c_parser.py',735), + ('direct_declarator -> direct_declarator LBRACKET constant_expression_opt RBRACKET','direct_declarator',4,'p_direct_declarator_3','/home/skybot/ext/parser/pycparser/c_parser.py',740), + ('direct_declarator -> direct_declarator LPAREN parameter_type_list RPAREN','direct_declarator',4,'p_direct_declarator_4','/home/skybot/ext/parser/pycparser/c_parser.py',750), + ('direct_declarator -> direct_declarator LPAREN identifier_list_opt RPAREN','direct_declarator',4,'p_direct_declarator_4','/home/skybot/ext/parser/pycparser/c_parser.py',751), + ('pointer -> TIMES type_qualifier_list_opt','pointer',2,'p_pointer','/home/skybot/ext/parser/pycparser/c_parser.py',761), + ('pointer -> TIMES type_qualifier_list_opt pointer','pointer',3,'p_pointer','/home/skybot/ext/parser/pycparser/c_parser.py',762), + ('type_qualifier_list -> type_qualifier','type_qualifier_list',1,'p_type_qualifier_list','/home/skybot/ext/parser/pycparser/c_parser.py',772), + ('type_qualifier_list -> type_qualifier_list type_qualifier','type_qualifier_list',2,'p_type_qualifier_list','/home/skybot/ext/parser/pycparser/c_parser.py',773), + ('parameter_type_list -> parameter_list','parameter_type_list',1,'p_parameter_type_list','/home/skybot/ext/parser/pycparser/c_parser.py',778), + ('parameter_type_list -> parameter_list COMMA ELLIPSIS','parameter_type_list',3,'p_parameter_type_list','/home/skybot/ext/parser/pycparser/c_parser.py',779), + ('parameter_list -> parameter_declaration','parameter_list',1,'p_parameter_list','/home/skybot/ext/parser/pycparser/c_parser.py',787), + ('parameter_list -> parameter_list COMMA parameter_declaration','parameter_list',3,'p_parameter_list','/home/skybot/ext/parser/pycparser/c_parser.py',788), + ('parameter_declaration -> declaration_specifiers declarator','parameter_declaration',2,'p_parameter_declaration_1','/home/skybot/ext/parser/pycparser/c_parser.py',797), + ('parameter_declaration -> declaration_specifiers abstract_declarator_opt','parameter_declaration',2,'p_parameter_declaration_2','/home/skybot/ext/parser/pycparser/c_parser.py',815), + ('identifier_list -> identifier','identifier_list',1,'p_identifier_list','/home/skybot/ext/parser/pycparser/c_parser.py',827), + ('identifier_list -> identifier_list COMMA identifier','identifier_list',3,'p_identifier_list','/home/skybot/ext/parser/pycparser/c_parser.py',828), + ('initializer -> assignment_expression','initializer',1,'p_initializer_1','/home/skybot/ext/parser/pycparser/c_parser.py',837), + ('initializer -> LBRACE initializer_list RBRACE','initializer',3,'p_initializer_2','/home/skybot/ext/parser/pycparser/c_parser.py',842), + ('initializer -> LBRACE initializer_list COMMA RBRACE','initializer',4,'p_initializer_2','/home/skybot/ext/parser/pycparser/c_parser.py',843), + ('initializer_list -> initializer','initializer_list',1,'p_initializer_list','/home/skybot/ext/parser/pycparser/c_parser.py',848), + ('initializer_list -> initializer_list COMMA initializer','initializer_list',3,'p_initializer_list','/home/skybot/ext/parser/pycparser/c_parser.py',849), + ('type_name -> specifier_qualifier_list abstract_declarator_opt','type_name',2,'p_type_name','/home/skybot/ext/parser/pycparser/c_parser.py',858), + ('abstract_declarator -> pointer','abstract_declarator',1,'p_abstract_declarator_1','/home/skybot/ext/parser/pycparser/c_parser.py',873), + ('abstract_declarator -> pointer direct_abstract_declarator','abstract_declarator',2,'p_abstract_declarator_2','/home/skybot/ext/parser/pycparser/c_parser.py',881), + ('abstract_declarator -> direct_abstract_declarator','abstract_declarator',1,'p_abstract_declarator_3','/home/skybot/ext/parser/pycparser/c_parser.py',886), + ('direct_abstract_declarator -> LPAREN abstract_declarator RPAREN','direct_abstract_declarator',3,'p_direct_abstract_declarator_1','/home/skybot/ext/parser/pycparser/c_parser.py',896), + ('direct_abstract_declarator -> direct_abstract_declarator LBRACKET constant_expression_opt RBRACKET','direct_abstract_declarator',4,'p_direct_abstract_declarator_2','/home/skybot/ext/parser/pycparser/c_parser.py',900), + ('direct_abstract_declarator -> LBRACKET constant_expression_opt RBRACKET','direct_abstract_declarator',3,'p_direct_abstract_declarator_3','/home/skybot/ext/parser/pycparser/c_parser.py',910), + ('direct_abstract_declarator -> direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN','direct_abstract_declarator',4,'p_direct_abstract_declarator_4','/home/skybot/ext/parser/pycparser/c_parser.py',918), + ('direct_abstract_declarator -> LPAREN parameter_type_list_opt RPAREN','direct_abstract_declarator',3,'p_direct_abstract_declarator_5','/home/skybot/ext/parser/pycparser/c_parser.py',928), + ('compound_statement -> LBRACE statement_list_opt RBRACE','compound_statement',3,'p_compound_statement_1','/home/skybot/ext/parser/pycparser/c_parser.py',936), + ('compound_statement -> LBRACE declaration_list RBRACE','compound_statement',3,'p_compound_statement_2','/home/skybot/ext/parser/pycparser/c_parser.py',943), + ('compound_statement -> LBRACE declaration_list statement_list RBRACE','compound_statement',4,'p_compound_statement_3','/home/skybot/ext/parser/pycparser/c_parser.py',950), + ('statement_list -> statement','statement_list',1,'p_statement_list','/home/skybot/ext/parser/pycparser/c_parser.py',964), + ('statement_list -> statement_list statement','statement_list',2,'p_statement_list','/home/skybot/ext/parser/pycparser/c_parser.py',965), + ('labeled_statement -> ID COLON statement','labeled_statement',3,'p_labeled_statement_1','/home/skybot/ext/parser/pycparser/c_parser.py',973), + ('labeled_statement -> CASE constant_expression COLON statement','labeled_statement',4,'p_labeled_statement_2','/home/skybot/ext/parser/pycparser/c_parser.py',977), + ('labeled_statement -> DEFAULT COLON statement','labeled_statement',3,'p_labeled_statement_3','/home/skybot/ext/parser/pycparser/c_parser.py',981), + ('selection_statement -> IF LPAREN expression RPAREN statement','selection_statement',5,'p_selection_statement_1','/home/skybot/ext/parser/pycparser/c_parser.py',985), + ('selection_statement -> IF LPAREN expression RPAREN statement ELSE statement','selection_statement',7,'p_selection_statement_2','/home/skybot/ext/parser/pycparser/c_parser.py',989), + ('selection_statement -> SWITCH LPAREN expression RPAREN statement','selection_statement',5,'p_selection_statement_3','/home/skybot/ext/parser/pycparser/c_parser.py',993), + ('iteration_statement -> WHILE LPAREN expression RPAREN statement','iteration_statement',5,'p_iteration_statement_1','/home/skybot/ext/parser/pycparser/c_parser.py',997), + ('iteration_statement -> DO statement WHILE LPAREN expression RPAREN','iteration_statement',6,'p_iteration_statement_2','/home/skybot/ext/parser/pycparser/c_parser.py',1001), + ('iteration_statement -> FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN statement','iteration_statement',9,'p_iteration_statement_3','/home/skybot/ext/parser/pycparser/c_parser.py',1005), + ('jump_statement -> GOTO ID SEMI','jump_statement',3,'p_jump_statement_1','/home/skybot/ext/parser/pycparser/c_parser.py',1009), + ('jump_statement -> BREAK SEMI','jump_statement',2,'p_jump_statement_2','/home/skybot/ext/parser/pycparser/c_parser.py',1013), + ('jump_statement -> CONTINUE SEMI','jump_statement',2,'p_jump_statement_3','/home/skybot/ext/parser/pycparser/c_parser.py',1017), + ('jump_statement -> RETURN expression SEMI','jump_statement',3,'p_jump_statement_4','/home/skybot/ext/parser/pycparser/c_parser.py',1021), + ('jump_statement -> RETURN SEMI','jump_statement',2,'p_jump_statement_4','/home/skybot/ext/parser/pycparser/c_parser.py',1022), + ('expression_statement -> expression_opt SEMI','expression_statement',2,'p_expression_statement','/home/skybot/ext/parser/pycparser/c_parser.py',1027), + ('expression -> assignment_expression','expression',1,'p_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1031), + ('expression -> expression COMMA assignment_expression','expression',3,'p_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1032), + ('typedef_name -> TYPEID','typedef_name',1,'p_typedef_name','/home/skybot/ext/parser/pycparser/c_parser.py',1044), + ('assignment_expression -> conditional_expression','assignment_expression',1,'p_assignment_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1048), + ('assignment_expression -> unary_expression assignment_operator assignment_expression','assignment_expression',3,'p_assignment_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1049), + ('assignment_operator -> EQUALS','assignment_operator',1,'p_assignment_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1062), + ('assignment_operator -> XOREQUAL','assignment_operator',1,'p_assignment_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1063), + ('assignment_operator -> TIMESEQUAL','assignment_operator',1,'p_assignment_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1064), + ('assignment_operator -> DIVEQUAL','assignment_operator',1,'p_assignment_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1065), + ('assignment_operator -> MODEQUAL','assignment_operator',1,'p_assignment_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1066), + ('assignment_operator -> PLUSEQUAL','assignment_operator',1,'p_assignment_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1067), + ('assignment_operator -> MINUSEQUAL','assignment_operator',1,'p_assignment_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1068), + ('assignment_operator -> LSHIFTEQUAL','assignment_operator',1,'p_assignment_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1069), + ('assignment_operator -> RSHIFTEQUAL','assignment_operator',1,'p_assignment_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1070), + ('assignment_operator -> ANDEQUAL','assignment_operator',1,'p_assignment_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1071), + ('assignment_operator -> OREQUAL','assignment_operator',1,'p_assignment_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1072), + ('constant_expression -> conditional_expression','constant_expression',1,'p_constant_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1077), + ('conditional_expression -> binary_expression','conditional_expression',1,'p_conditional_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1081), + ('conditional_expression -> binary_expression CONDOP expression COLON conditional_expression','conditional_expression',5,'p_conditional_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1082), + ('binary_expression -> cast_expression','binary_expression',1,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1090), + ('binary_expression -> binary_expression TIMES binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1091), + ('binary_expression -> binary_expression DIVIDE binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1092), + ('binary_expression -> binary_expression MOD binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1093), + ('binary_expression -> binary_expression PLUS binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1094), + ('binary_expression -> binary_expression MINUS binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1095), + ('binary_expression -> binary_expression RSHIFT binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1096), + ('binary_expression -> binary_expression LSHIFT binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1097), + ('binary_expression -> binary_expression LT binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1098), + ('binary_expression -> binary_expression LE binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1099), + ('binary_expression -> binary_expression GE binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1100), + ('binary_expression -> binary_expression GT binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1101), + ('binary_expression -> binary_expression EQ binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1102), + ('binary_expression -> binary_expression NE binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1103), + ('binary_expression -> binary_expression AND binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1104), + ('binary_expression -> binary_expression OR binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1105), + ('binary_expression -> binary_expression XOR binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1106), + ('binary_expression -> binary_expression LAND binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1107), + ('binary_expression -> binary_expression LOR binary_expression','binary_expression',3,'p_binary_expression','/home/skybot/ext/parser/pycparser/c_parser.py',1108), + ('cast_expression -> unary_expression','cast_expression',1,'p_cast_expression_1','/home/skybot/ext/parser/pycparser/c_parser.py',1116), + ('cast_expression -> LPAREN type_name RPAREN cast_expression','cast_expression',4,'p_cast_expression_2','/home/skybot/ext/parser/pycparser/c_parser.py',1120), + ('unary_expression -> postfix_expression','unary_expression',1,'p_unary_expression_1','/home/skybot/ext/parser/pycparser/c_parser.py',1124), + ('unary_expression -> PLUSPLUS unary_expression','unary_expression',2,'p_unary_expression_2','/home/skybot/ext/parser/pycparser/c_parser.py',1128), + ('unary_expression -> MINUSMINUS unary_expression','unary_expression',2,'p_unary_expression_2','/home/skybot/ext/parser/pycparser/c_parser.py',1129), + ('unary_expression -> unary_operator cast_expression','unary_expression',2,'p_unary_expression_2','/home/skybot/ext/parser/pycparser/c_parser.py',1130), + ('unary_expression -> SIZEOF unary_expression','unary_expression',2,'p_unary_expression_3','/home/skybot/ext/parser/pycparser/c_parser.py',1135), + ('unary_expression -> SIZEOF LPAREN type_name RPAREN','unary_expression',4,'p_unary_expression_3','/home/skybot/ext/parser/pycparser/c_parser.py',1136), + ('unary_operator -> AND','unary_operator',1,'p_unary_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1144), + ('unary_operator -> TIMES','unary_operator',1,'p_unary_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1145), + ('unary_operator -> PLUS','unary_operator',1,'p_unary_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1146), + ('unary_operator -> MINUS','unary_operator',1,'p_unary_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1147), + ('unary_operator -> NOT','unary_operator',1,'p_unary_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1148), + ('unary_operator -> LNOT','unary_operator',1,'p_unary_operator','/home/skybot/ext/parser/pycparser/c_parser.py',1149), + ('postfix_expression -> primary_expression','postfix_expression',1,'p_postfix_exptession_1','/home/skybot/ext/parser/pycparser/c_parser.py',1154), + ('postfix_expression -> postfix_expression LBRACKET expression RBRACKET','postfix_expression',4,'p_postfix_exptession_2','/home/skybot/ext/parser/pycparser/c_parser.py',1158), + ('postfix_expression -> postfix_expression LPAREN argument_expression_list RPAREN','postfix_expression',4,'p_postfix_exptession_3','/home/skybot/ext/parser/pycparser/c_parser.py',1162), + ('postfix_expression -> postfix_expression LPAREN RPAREN','postfix_expression',3,'p_postfix_exptession_3','/home/skybot/ext/parser/pycparser/c_parser.py',1163), + ('postfix_expression -> postfix_expression PERIOD identifier','postfix_expression',3,'p_postfix_expression_4','/home/skybot/ext/parser/pycparser/c_parser.py',1168), + ('postfix_expression -> postfix_expression ARROW identifier','postfix_expression',3,'p_postfix_expression_4','/home/skybot/ext/parser/pycparser/c_parser.py',1169), + ('postfix_expression -> postfix_expression PLUSPLUS','postfix_expression',2,'p_postfix_expression_5','/home/skybot/ext/parser/pycparser/c_parser.py',1174), + ('postfix_expression -> postfix_expression MINUSMINUS','postfix_expression',2,'p_postfix_expression_5','/home/skybot/ext/parser/pycparser/c_parser.py',1175), + ('primary_expression -> identifier','primary_expression',1,'p_primary_expression_1','/home/skybot/ext/parser/pycparser/c_parser.py',1180), + ('primary_expression -> constant','primary_expression',1,'p_primary_expression_2','/home/skybot/ext/parser/pycparser/c_parser.py',1184), + ('primary_expression -> STRING_LITERAL','primary_expression',1,'p_primary_expression_3','/home/skybot/ext/parser/pycparser/c_parser.py',1188), + ('primary_expression -> WSTRING_LITERAL','primary_expression',1,'p_primary_expression_3','/home/skybot/ext/parser/pycparser/c_parser.py',1189), + ('primary_expression -> LPAREN expression RPAREN','primary_expression',3,'p_primary_expression_4','/home/skybot/ext/parser/pycparser/c_parser.py',1195), + ('argument_expression_list -> assignment_expression','argument_expression_list',1,'p_argument_expression_list','/home/skybot/ext/parser/pycparser/c_parser.py',1199), + ('argument_expression_list -> argument_expression_list COMMA assignment_expression','argument_expression_list',3,'p_argument_expression_list','/home/skybot/ext/parser/pycparser/c_parser.py',1200), + ('identifier -> ID','identifier',1,'p_identifier','/home/skybot/ext/parser/pycparser/c_parser.py',1209), + ('constant -> INT_CONST_DEC','constant',1,'p_constant_1','/home/skybot/ext/parser/pycparser/c_parser.py',1213), + ('constant -> INT_CONST_OCT','constant',1,'p_constant_1','/home/skybot/ext/parser/pycparser/c_parser.py',1214), + ('constant -> INT_CONST_HEX','constant',1,'p_constant_1','/home/skybot/ext/parser/pycparser/c_parser.py',1215), + ('constant -> FLOAT_CONST','constant',1,'p_constant_2','/home/skybot/ext/parser/pycparser/c_parser.py',1221), + ('constant -> CHAR_CONST','constant',1,'p_constant_3','/home/skybot/ext/parser/pycparser/c_parser.py',1226), + ('constant -> WCHAR_CONST','constant',1,'p_constant_3','/home/skybot/ext/parser/pycparser/c_parser.py',1227), + ('empty -> ','empty',0,'p_empty','/home/skybot/ext/parser/pycparser/c_parser.py',1233), +]