7
7
8
8
class CIdentList (Task ):
9
9
10
+ def __print_failure (self , name ):
11
+ print ("Error: " + name + ": unmatched curly braces when scanning for "
12
+ "C identifier lists" )
13
+
10
14
def should_process_file (self , config_file , name ):
11
15
return config_file .is_c_file (name ) or config_file .is_cpp_file (name )
12
16
@@ -31,12 +35,16 @@ def run_pipeline(self, config_file, name, lines):
31
35
#
32
36
# "def\\s+\w+" matches preprocessor directives "#ifdef" and "#ifndef" so
33
37
# their contents aren't used as a return type.
38
+ preproc_str = "#else|#endif|"
34
39
comment_str = "/\*|\*/|//|" + linesep + "|"
40
+ string_str = r"\\\\|\\\"|\"|"
41
+ char_str = r"\\'|'|"
35
42
extern_str = "(?P<ext_decl>extern \" C(\+\+)?\" )\s+(?P<ext_brace>\{)?|"
36
43
braces_str = "\{|\}|;|def\s+\w+|\w+\s+\w+\s*(?P<paren>\(\))"
37
44
postfix_str = "(?=\s*(;|\{))"
38
45
token_regex = regex .compile (
39
- comment_str + extern_str + braces_str + postfix_str )
46
+ preproc_str + comment_str + string_str + char_str + extern_str +
47
+ braces_str + postfix_str )
40
48
41
49
EXTRA_POP_OFFSET = 2
42
50
@@ -48,70 +56,115 @@ def run_pipeline(self, config_file, name, lines):
48
56
# is_c + pop offset == 3: C++ lang restore that needs extra brace pop
49
57
extern_brace_indices = [is_c ]
50
58
59
+ in_preproc_else = False
51
60
in_multicomment = False
52
- in_comment = False
61
+ in_singlecomment = False
62
+ in_string = False
63
+ in_char = False
53
64
for match in token_regex .finditer (lines ):
54
65
token = match .group ()
55
66
67
+ # Skip #else to #endif in case they have braces in them. This
68
+ # assumes preprocessor directives are only used for conditional
69
+ # compilation for different platforms and have the same amount of
70
+ # braces in both branches. Nested preprocessor directives are also
71
+ # not handled.
72
+ if token == "#else" :
73
+ in_preproc_else = True
74
+ elif token == "#endif" :
75
+ in_preproc_else = False
76
+ if in_preproc_else :
77
+ continue
78
+
56
79
if token == "/*" :
57
- in_multicomment = True
80
+ if not in_singlecomment and not in_string and not in_char :
81
+ in_multicomment = True
58
82
elif token == "*/" :
59
- in_multicomment = False
60
- in_comment = False
83
+ if not in_singlecomment and not in_string and not in_char :
84
+ in_multicomment = False
61
85
elif token == "//" :
62
- print ( "into comment" )
63
- in_comment = True
86
+ if not in_multicomment and not in_string and not in_char :
87
+ in_singlecomment = True
64
88
elif token == linesep :
65
- print ("out of comment" )
66
- in_comment = False
67
- elif not in_multicomment and not in_comment :
68
- if token == "{" :
89
+ if not in_multicomment :
90
+ in_singlecomment = False
91
+ elif in_multicomment or in_singlecomment :
92
+ # Tokens processed after this branch are ignored if they are in
93
+ # comments
94
+ continue
95
+ elif token == "\\ \" " :
96
+ continue
97
+ elif token == "\" " :
98
+ if not in_char :
99
+ in_string = not in_string
100
+ elif token == "\\ '" :
101
+ continue
102
+ elif token == "'" :
103
+ if not in_string :
104
+ in_char = not in_char
105
+ elif in_string or in_char :
106
+ # Tokens processed after this branch are ignored if they are in
107
+ # double or single quotes
108
+ continue
109
+ elif token == "{" :
110
+ extern_brace_indices .append (is_c )
111
+ elif token == "}" :
112
+ is_c = extern_brace_indices .pop ()
113
+
114
+ if len (extern_brace_indices ) == 0 :
115
+ self .__print_failure (name )
116
+ return (lines , False , False )
117
+
118
+ # If the next stack frame is from an extern without braces, pop
119
+ # it.
120
+ if extern_brace_indices [- 1 ] >= EXTRA_POP_OFFSET :
121
+ is_c = extern_brace_indices [- 1 ] - EXTRA_POP_OFFSET
122
+ extern_brace_indices .pop ()
123
+ elif token == ";" :
124
+ if len (extern_brace_indices ) == 0 :
125
+ self .__print_failure (name )
126
+ return (lines , False , False )
127
+
128
+ # If the next stack frame is from an extern without braces, pop
129
+ # it.
130
+ if extern_brace_indices [- 1 ] >= EXTRA_POP_OFFSET :
131
+ is_c = extern_brace_indices [- 1 ] - EXTRA_POP_OFFSET
132
+ extern_brace_indices .pop ()
133
+ elif token .startswith ("extern" ):
134
+ # Back up language setting first
135
+ if match .group ("ext_brace" ):
69
136
extern_brace_indices .append (is_c )
70
- elif token == "}" :
71
- is_c = extern_brace_indices .pop ()
72
-
73
- # If the next stack frame is from an extern without braces,
74
- # pop it.
75
- if extern_brace_indices [- 1 ] >= EXTRA_POP_OFFSET :
76
- is_c = extern_brace_indices [- 1 ] - EXTRA_POP_OFFSET
77
- extern_brace_indices .pop ()
78
- elif token == ";" :
79
- # If the next stack frame is from an extern without braces,
80
- # pop it.
81
- if extern_brace_indices [- 1 ] >= EXTRA_POP_OFFSET :
82
- is_c = extern_brace_indices [- 1 ] - EXTRA_POP_OFFSET
83
- extern_brace_indices .pop ()
84
- elif token .startswith ("extern" ):
85
- # Back up language setting first
86
- if match .group ("ext_brace" ):
87
- extern_brace_indices .append (is_c )
88
- else :
89
- # Handling an extern without braces changing the
90
- # language type is done by treating it as a pseudo-brace
91
- # that gets popped as well when the next "}" or ";" is
92
- # encountered. The "extra pop" offset is used as a flag
93
- # on the top stack value that is checked whenever a pop
94
- # is performed.
95
- extern_brace_indices .append (is_c + EXTRA_POP_OFFSET )
96
-
97
- # Change language based on extern declaration
98
- if match .group ("ext_decl" ) == "extern \" C\" " :
99
- is_c = True
100
- else :
101
- is_c = False
102
- elif match .group (
103
- "paren" ) and "return " not in match .group () and is_c :
104
- # Replaces () with (void)
105
- output += lines [pos :match .span ("paren" )[0 ]] + "(void)"
106
- pos = match .span ("paren" )[0 ] + len ("()" )
107
-
108
- file_changed = True
137
+ else :
138
+ # Handling an extern without braces changing the language
139
+ # type is done by treating it as a pseudo-brace that gets
140
+ # popped as well when the next "}" or ";" is encountered.
141
+ # The "extra pop" offset is used as a flag on the top stack
142
+ # value that is checked whenever a pop is performed.
143
+ extern_brace_indices .append (is_c + EXTRA_POP_OFFSET )
144
+
145
+ # Change language based on extern declaration
146
+ if match .group ("ext_decl" ) == "extern \" C\" " :
147
+ is_c = True
148
+ else :
149
+ is_c = False
150
+ elif match .group (
151
+ "paren" ) and "return " not in match .group () and is_c :
152
+ # Replaces () with (void)
153
+ output += lines [pos :match .span ("paren" )[0 ]] + "(void)"
154
+ pos = match .span ("paren" )[0 ] + len ("()" )
155
+
156
+ file_changed = True
109
157
110
158
# Write rest of file if it wasn't all processed
111
159
if pos < len (lines ):
112
160
output += lines [pos :]
113
161
162
+ # Invariant: extern_brace_indices has one entry
163
+ success = len (extern_brace_indices ) == 1
164
+ if not success :
165
+ self .__print_failure (name )
166
+
114
167
if file_changed :
115
- return (output , file_changed , True )
168
+ return (output , file_changed , success )
116
169
else :
117
- return (lines , file_changed , True )
170
+ return (lines , file_changed , success )
0 commit comments