| # Regular expression patterns for C syntax. | |
| # | |
| # None of these patterns has any capturing. However, a number of them | |
| # have capturing markers compatible with utils.set_capture_groups(). | |
| import textwrap | |
| def _ind(text, level=1, edges='both'): | |
| indent = ' ' * level | |
| text = textwrap.indent(text, indent) | |
| if edges == 'pre' or edges == 'both': | |
| text = '\n' + indent + text.lstrip() | |
| if edges == 'post' or edges == 'both': | |
| text = text.rstrip() + '\n' + ' ' * (level - 1) | |
| return text | |
| ####################################### | |
| # general | |
| HEX = r'(?: [0-9a-zA-Z] )' | |
| STRING_LITERAL = textwrap.dedent(rf''' | |
| (?: | |
| # character literal | |
| (?: | |
| ['] [^'] ['] | |
| | | |
| ['] \\ . ['] | |
| | | |
| ['] \\x{HEX}{HEX} ['] | |
| | | |
| ['] \\0\d\d ['] | |
| | | |
| (?: | |
| ['] \\o[01]\d\d ['] | |
| | | |
| ['] \\o2[0-4]\d ['] | |
| | | |
| ['] \\o25[0-5] ['] | |
| ) | |
| ) | |
| | | |
| # string literal | |
| (?: | |
| ["] (?: [^"\\]* \\ . )* [^"\\]* ["] | |
| ) | |
| # end string literal | |
| ) | |
| ''') | |
| _KEYWORD = textwrap.dedent(r''' | |
| (?: | |
| \b | |
| (?: | |
| auto | | |
| extern | | |
| register | | |
| static | | |
| _Thread_local | | |
| typedef | | |
| const | | |
| volatile | | |
| signed | | |
| unsigned | | |
| char | | |
| short | | |
| int | | |
| long | | |
| float | | |
| double | | |
| _Complex | | |
| void | | |
| struct | | |
| union | | |
| enum | | |
| goto | | |
| return | | |
| sizeof | | |
| break | | |
| continue | | |
| if | | |
| else | | |
| for | | |
| do | | |
| while | | |
| switch | | |
| case | | |
| default | | |
| entry | |
| ) | |
| \b | |
| ) | |
| ''') | |
| KEYWORD = rf''' | |
| # keyword | |
| {_KEYWORD} | |
| # end keyword | |
| ''' | |
| _KEYWORD = ''.join(_KEYWORD.split()) | |
| IDENTIFIER = r'(?: [a-zA-Z_][a-zA-Z0-9_]* )' | |
| # We use a negative lookahead to filter out keywords. | |
| STRICT_IDENTIFIER = rf'(?: (?! {_KEYWORD} ) \b {IDENTIFIER} \b )' | |
| ANON_IDENTIFIER = rf'(?: (?! {_KEYWORD} ) \b {IDENTIFIER} (?: - \d+ )? \b )' | |
| ####################################### | |
| # types | |
| SIMPLE_TYPE = textwrap.dedent(rf''' | |
| # simple type | |
| (?: | |
| \b | |
| (?: | |
| void | |
| | | |
| (?: signed | unsigned ) # implies int | |
| | | |
| (?: | |
| (?: (?: float | double | long\s+double ) \s+ )? | |
| _Complex | |
| ) | |
| | | |
| (?: | |
| _Complex | |
| (?: \s+ (?: float | double | long\s+double ) )? | |
| ) | |
| | | |
| (?: | |
| (?: (?: signed | unsigned ) \s+ )? | |
| (?: (?: long | short ) \s+ )? | |
| (?: char | short | int | long | float | double ) | |
| ) | |
| ) | |
| \b | |
| ) | |
| # end simple type | |
| ''') | |
| COMPOUND_TYPE_KIND = r'(?: \b (?: struct | union | enum ) \b )' | |
| ####################################### | |
| # variable declarations | |
| _STORAGE = 'auto register static extern _Thread_local'.split() | |
| STORAGE_CLASS = rf'(?: \b (?: {" | ".join(_STORAGE)} ) \b )' | |
| TYPE_QUALIFIER = r'(?: \b (?: const | volatile ) \b )' | |
| PTR_QUALIFIER = rf'(?: [*] (?: \s* {TYPE_QUALIFIER} )? )' | |
| TYPE_SPEC = textwrap.dedent(rf''' | |
| # type spec | |
| (?: | |
| {_ind(SIMPLE_TYPE, 2)} | |
| | | |
| (?: | |
| [_]*typeof[_]* | |
| \s* [(] | |
| (?: \s* [*&] )* | |
| \s* {STRICT_IDENTIFIER} | |
| \s* [)] | |
| ) | |
| | | |
| # reference to a compound type | |
| (?: | |
| {COMPOUND_TYPE_KIND} | |
| (?: \s* {ANON_IDENTIFIER} )? | |
| ) | |
| | | |
| # reference to a typedef | |
| {STRICT_IDENTIFIER} | |
| ) | |
| # end type spec | |
| ''') | |
| DECLARATOR = textwrap.dedent(rf''' | |
| # declarator (possibly abstract) | |
| (?: | |
| (?: {PTR_QUALIFIER} \s* )* | |
| (?: | |
| (?: | |
| (?: # <IDENTIFIER> | |
| {STRICT_IDENTIFIER} | |
| ) | |
| # Inside the brackets is actually a "constant expression". | |
| (?: \s* \[ (?: \s* [^\]]+ \s* )? [\]] )* # arrays | |
| ) | |
| | | |
| (?: | |
| [(] \s* | |
| (?: # <WRAPPED_IDENTIFIER> | |
| {STRICT_IDENTIFIER} | |
| ) | |
| # Inside the brackets is actually a "constant expression". | |
| (?: \s* \[ (?: \s* [^\]]+ \s* )? [\]] )* # arrays | |
| \s* [)] | |
| ) | |
| | | |
| # func ptr | |
| (?: | |
| [(] (?: \s* {PTR_QUALIFIER} )? \s* | |
| (?: # <FUNC_IDENTIFIER> | |
| {STRICT_IDENTIFIER} | |
| ) | |
| # Inside the brackets is actually a "constant expression". | |
| (?: \s* \[ (?: \s* [^\]]+ \s* )? [\]] )* # arrays | |
| \s* [)] | |
| # We allow for a single level of paren nesting in parameters. | |
| \s* [(] (?: [^()]* [(] [^)]* [)] )* [^)]* [)] | |
| ) | |
| ) | |
| ) | |
| # end declarator | |
| ''') | |
| VAR_DECL = textwrap.dedent(rf''' | |
| # var decl (and typedef and func return type) | |
| (?: | |
| (?: | |
| (?: # <STORAGE> | |
| {STORAGE_CLASS} | |
| ) | |
| \s* | |
| )? | |
| (?: | |
| (?: # <TYPE_QUAL> | |
| {TYPE_QUALIFIER} | |
| ) | |
| \s* | |
| )? | |
| (?: | |
| (?: # <TYPE_SPEC> | |
| {_ind(TYPE_SPEC, 4)} | |
| ) | |
| ) | |
| \s* | |
| (?: | |
| (?: # <DECLARATOR> | |
| {_ind(DECLARATOR, 4)} | |
| ) | |
| ) | |
| ) | |
| # end var decl | |
| ''') | |
| INITIALIZER = textwrap.dedent(rf''' | |
| # initializer | |
| (?: | |
| (?: | |
| [(] | |
| # no nested parens (e.g. func ptr) | |
| [^)]* | |
| [)] | |
| \s* | |
| )? | |
| (?: | |
| # a string literal | |
| (?: | |
| (?: {_ind(STRING_LITERAL, 4)} \s* )* | |
| {_ind(STRING_LITERAL, 4)} | |
| ) | |
| | | |
| # a simple initializer | |
| (?: | |
| (?: | |
| [^'",;{{]* | |
| {_ind(STRING_LITERAL, 4)} | |
| )* | |
| [^'",;{{]* | |
| ) | |
| | | |
| # a struct/array literal | |
| (?: | |
| # We only expect compound initializers with | |
| # single-variable declarations. | |
| {{ | |
| (?: | |
| [^'";]*? | |
| {_ind(STRING_LITERAL, 5)} | |
| )* | |
| [^'";]*? | |
| }} | |
| (?= \s* ; ) # Note this lookahead. | |
| ) | |
| ) | |
| ) | |
| # end initializer | |
| ''') | |
| ####################################### | |
| # compound type declarations | |
| STRUCT_MEMBER_DECL = textwrap.dedent(rf''' | |
| (?: | |
| # inline compound type decl | |
| (?: | |
| (?: # <COMPOUND_TYPE_KIND> | |
| {COMPOUND_TYPE_KIND} | |
| ) | |
| (?: | |
| \s+ | |
| (?: # <COMPOUND_TYPE_NAME> | |
| {STRICT_IDENTIFIER} | |
| ) | |
| )? | |
| \s* {{ | |
| ) | |
| | | |
| (?: | |
| # typed member | |
| (?: | |
| # Technically it doesn't have to have a type... | |
| (?: # <SPECIFIER_QUALIFIER> | |
| (?: {TYPE_QUALIFIER} \s* )? | |
| {_ind(TYPE_SPEC, 5)} | |
| ) | |
| (?: | |
| # If it doesn't have a declarator then it will have | |
| # a size and vice versa. | |
| \s* | |
| (?: # <DECLARATOR> | |
| {_ind(DECLARATOR, 6)} | |
| ) | |
| )? | |
| ) | |
| # sized member | |
| (?: | |
| \s* [:] \s* | |
| (?: # <SIZE> | |
| # This is actually a "constant expression". | |
| \d+ | |
| | | |
| [^'",}}]+ | |
| ) | |
| )? | |
| \s* | |
| (?: # <ENDING> | |
| [,;] | |
| ) | |
| ) | |
| | | |
| (?: | |
| \s* | |
| (?: # <CLOSE> | |
| }} | |
| ) | |
| ) | |
| ) | |
| ''') | |
| ENUM_MEMBER_DECL = textwrap.dedent(rf''' | |
| (?: | |
| (?: | |
| \s* | |
| (?: # <CLOSE> | |
| }} | |
| ) | |
| ) | |
| | | |
| (?: | |
| \s* | |
| (?: # <NAME> | |
| {IDENTIFIER} | |
| ) | |
| (?: | |
| \s* = \s* | |
| (?: # <INIT> | |
| # This is actually a "constant expression". | |
| {_ind(STRING_LITERAL, 4)} | |
| | | |
| [^'",}}]+ | |
| ) | |
| )? | |
| \s* | |
| (?: # <ENDING> | |
| , | }} | |
| ) | |
| ) | |
| ) | |
| ''') | |
| ####################################### | |
| # statements | |
| SIMPLE_STMT_BODY = textwrap.dedent(rf''' | |
| # simple statement body | |
| (?: | |
| (?: | |
| [^'"{{}};]* | |
| {_ind(STRING_LITERAL, 3)} | |
| )* | |
| [^'"{{}};]* | |
| #(?= [;{{] ) # Note this lookahead. | |
| ) | |
| # end simple statement body | |
| ''') | |
| SIMPLE_STMT = textwrap.dedent(rf''' | |
| # simple statement | |
| (?: | |
| (?: # <SIMPLE_STMT> | |
| # stmt-inline "initializer" | |
| (?: | |
| return \b | |
| (?: | |
| \s* | |
| {_ind(INITIALIZER, 5)} | |
| )? | |
| ) | |
| | | |
| # variable assignment | |
| (?: | |
| (?: [*] \s* )? | |
| (?: | |
| {STRICT_IDENTIFIER} \s* | |
| (?: . | -> ) \s* | |
| )* | |
| {STRICT_IDENTIFIER} | |
| (?: \s* \[ \s* \d+ \s* \] )? | |
| \s* = \s* | |
| {_ind(INITIALIZER, 4)} | |
| ) | |
| | | |
| # catchall return statement | |
| (?: | |
| return \b | |
| (?: | |
| (?: | |
| [^'";]* | |
| {_ind(STRING_LITERAL, 6)} | |
| )* | |
| \s* [^'";]* | |
| )? | |
| ) | |
| | | |
| # simple statement | |
| (?: | |
| {_ind(SIMPLE_STMT_BODY, 4)} | |
| ) | |
| ) | |
| \s* | |
| (?: # <SIMPLE_ENDING> | |
| ; | |
| ) | |
| ) | |
| # end simple statement | |
| ''') | |
| COMPOUND_STMT = textwrap.dedent(rf''' | |
| # compound statement | |
| (?: | |
| \b | |
| (?: | |
| (?: | |
| (?: # <COMPOUND_BARE> | |
| else | do | |
| ) | |
| \b | |
| ) | |
| | | |
| (?: | |
| (?: # <COMPOUND_LABELED> | |
| (?: | |
| case \b | |
| (?: | |
| [^'":]* | |
| {_ind(STRING_LITERAL, 7)} | |
| )* | |
| \s* [^'":]* | |
| ) | |
| | | |
| default | |
| | | |
| {STRICT_IDENTIFIER} | |
| ) | |
| \s* [:] | |
| ) | |
| | | |
| (?: | |
| (?: # <COMPOUND_PAREN> | |
| for | while | if | switch | |
| ) | |
| \s* (?= [(] ) # Note this lookahead. | |
| ) | |
| ) | |
| \s* | |
| ) | |
| # end compound statement | |
| ''') | |
| ####################################### | |
| # function bodies | |
| LOCAL = textwrap.dedent(rf''' | |
| (?: | |
| # an empty statement | |
| (?: # <EMPTY> | |
| ; | |
| ) | |
| | | |
| # inline type decl | |
| (?: | |
| (?: | |
| (?: # <INLINE_LEADING> | |
| [^;{{}}]+? | |
| ) | |
| \s* | |
| )? | |
| (?: # <INLINE_PRE> | |
| (?: {STORAGE_CLASS} \s* )? | |
| (?: {TYPE_QUALIFIER} \s* )? | |
| )? # </INLINE_PRE> | |
| (?: # <INLINE_KIND> | |
| {COMPOUND_TYPE_KIND} | |
| ) | |
| (?: | |
| \s+ | |
| (?: # <INLINE_NAME> | |
| {STRICT_IDENTIFIER} | |
| ) | |
| )? | |
| \s* {{ | |
| ) | |
| | | |
| # var decl | |
| (?: | |
| (?: # <STORAGE> | |
| {STORAGE_CLASS} | |
| )? # </STORAGE> | |
| (?: | |
| \s* | |
| (?: # <VAR_DECL> | |
| {_ind(VAR_DECL, 5)} | |
| ) | |
| ) | |
| (?: | |
| (?: | |
| # initializer | |
| # We expect only basic initializers. | |
| \s* = \s* | |
| (?: # <VAR_INIT> | |
| {_ind(INITIALIZER, 6)} | |
| ) | |
| )? | |
| (?: | |
| \s* | |
| (?: # <VAR_ENDING> | |
| [,;] | |
| ) | |
| ) | |
| ) | |
| ) | |
| | | |
| {_ind(COMPOUND_STMT, 2)} | |
| | | |
| # start-of-block | |
| (?: | |
| (?: # <BLOCK_LEADING> | |
| (?: | |
| [^'"{{}};]* | |
| {_ind(STRING_LITERAL, 5)} | |
| )* | |
| [^'"{{}};]* | |
| # Presumably we will not see "== {{". | |
| [^\s='"{{}});] | |
| \s* | |
| )? # </BLOCK_LEADING> | |
| (?: # <BLOCK_OPEN> | |
| {{ | |
| ) | |
| ) | |
| | | |
| {_ind(SIMPLE_STMT, 2)} | |
| | | |
| # end-of-block | |
| (?: # <BLOCK_CLOSE> | |
| }} | |
| ) | |
| ) | |
| ''') | |
| LOCAL_STATICS = textwrap.dedent(rf''' | |
| (?: | |
| # inline type decl | |
| (?: | |
| (?: | |
| (?: # <INLINE_LEADING> | |
| [^;{{}}]+? | |
| ) | |
| \s* | |
| )? | |
| (?: # <INLINE_PRE> | |
| (?: {STORAGE_CLASS} \s* )? | |
| (?: {TYPE_QUALIFIER} \s* )? | |
| )? | |
| (?: # <INLINE_KIND> | |
| {COMPOUND_TYPE_KIND} | |
| ) | |
| (?: | |
| \s+ | |
| (?: # <INLINE_NAME> | |
| {STRICT_IDENTIFIER} | |
| ) | |
| )? | |
| \s* {{ | |
| ) | |
| | | |
| # var decl | |
| (?: | |
| # We only look for static variables. | |
| (?: # <STATIC_DECL> | |
| static \b | |
| (?: \s* {TYPE_QUALIFIER} )? | |
| \s* {_ind(TYPE_SPEC, 4)} | |
| \s* {_ind(DECLARATOR, 4)} | |
| ) | |
| \s* | |
| (?: | |
| (?: # <STATIC_INIT> | |
| = \s* | |
| {_ind(INITIALIZER, 4)} | |
| \s* | |
| [,;{{] | |
| ) | |
| | | |
| (?: # <STATIC_ENDING> | |
| [,;] | |
| ) | |
| ) | |
| ) | |
| | | |
| # everything else | |
| (?: | |
| (?: # <DELIM_LEADING> | |
| (?: | |
| [^'"{{}};]* | |
| {_ind(STRING_LITERAL, 4)} | |
| )* | |
| \s* [^'"{{}};]* | |
| ) | |
| (?: | |
| (?: # <BLOCK_OPEN> | |
| {{ | |
| ) | |
| | | |
| (?: # <BLOCK_CLOSE> | |
| }} | |
| ) | |
| | | |
| (?: # <STMT_END> | |
| ; | |
| ) | |
| ) | |
| ) | |
| ) | |
| ''') | |
| ####################################### | |
| # global declarations | |
| GLOBAL = textwrap.dedent(rf''' | |
| (?: | |
| # an empty statement | |
| (?: # <EMPTY> | |
| ; | |
| ) | |
| | | |
| # compound type decl (maybe inline) | |
| (?: | |
| (?: | |
| (?: # <COMPOUND_LEADING> | |
| [^;{{}}]+? | |
| ) | |
| \s* | |
| )? | |
| (?: # <COMPOUND_KIND> | |
| {COMPOUND_TYPE_KIND} | |
| ) | |
| (?: | |
| \s+ | |
| (?: # <COMPOUND_NAME> | |
| {STRICT_IDENTIFIER} | |
| ) | |
| )? | |
| \s* {{ | |
| ) | |
| | | |
| # bogus inline decl artifact | |
| # This simplifies resolving the relative syntactic ambiguity of | |
| # inline structs. | |
| (?: | |
| (?: # <FORWARD_KIND> | |
| {COMPOUND_TYPE_KIND} | |
| ) | |
| \s* | |
| (?: # <FORWARD_NAME> | |
| {ANON_IDENTIFIER} | |
| ) | |
| (?: # <MAYBE_INLINE_ACTUAL> | |
| [^=,;({{[*\]]* | |
| [=,;({{] | |
| ) | |
| ) | |
| | | |
| # typedef | |
| (?: | |
| \b typedef \b \s* | |
| (?: # <TYPEDEF_DECL> | |
| {_ind(VAR_DECL, 4)} | |
| ) | |
| (?: | |
| # We expect no inline type definitions in the parameters. | |
| \s* [(] \s* | |
| (?: # <TYPEDEF_FUNC_PARAMS> | |
| [^{{;]* | |
| ) | |
| \s* [)] | |
| )? | |
| \s* ; | |
| ) | |
| | | |
| # func decl/definition & var decls | |
| # XXX dedicated pattern for funcs (more restricted)? | |
| (?: | |
| (?: | |
| (?: # <VAR_STORAGE> | |
| {STORAGE_CLASS} | |
| ) | |
| \s* | |
| )? | |
| (?: | |
| (?: # <FUNC_INLINE> | |
| \b inline \b | |
| ) | |
| \s* | |
| )? | |
| (?: # <VAR_DECL> | |
| {_ind(VAR_DECL, 4)} | |
| ) | |
| (?: | |
| # func decl / definition | |
| (?: | |
| (?: | |
| # We expect no inline type definitions in the parameters. | |
| \s* [(] \s* | |
| (?: # <FUNC_PARAMS> | |
| [^{{;]* | |
| ) | |
| \s* [)] \s* | |
| (?: # <FUNC_DELIM> | |
| [{{;] | |
| ) | |
| ) | |
| | | |
| (?: | |
| # This is some old-school syntax! | |
| \s* [(] \s* | |
| # We throw away the bare names: | |
| {STRICT_IDENTIFIER} | |
| (?: \s* , \s* {STRICT_IDENTIFIER} )* | |
| \s* [)] \s* | |
| # We keep the trailing param declarations: | |
| (?: # <FUNC_LEGACY_PARAMS> | |
| # There's at least one! | |
| (?: {TYPE_QUALIFIER} \s* )? | |
| {_ind(TYPE_SPEC, 7)} | |
| \s* | |
| {_ind(DECLARATOR, 7)} | |
| \s* ; | |
| (?: | |
| \s* | |
| (?: {TYPE_QUALIFIER} \s* )? | |
| {_ind(TYPE_SPEC, 8)} | |
| \s* | |
| {_ind(DECLARATOR, 8)} | |
| \s* ; | |
| )* | |
| ) | |
| \s* {{ | |
| ) | |
| ) | |
| | | |
| # var / typedef | |
| (?: | |
| (?: | |
| # initializer | |
| # We expect only basic initializers. | |
| \s* = \s* | |
| (?: # <VAR_INIT> | |
| {_ind(INITIALIZER, 6)} | |
| ) | |
| )? | |
| \s* | |
| (?: # <VAR_ENDING> | |
| [,;] | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ''') |