bitsquid avatar bitsquid committed 35370da

Better #include line parser -- handle C++ comments and spaces between
'#' and 'include'.

Comments (0)

Files changed (1)

header_hero/Parser/Parser.cs

             }
         };
 
+        enum States { Start, Hash, Include, AngleBracket, Quote }
+        enum ParseResult { Ok, Error }
+
+        static ParseResult ParseLine(string line, Result result)
+        {
+            int i = 0;
+            int path_start = 0;
+            States state = States.Start;
+
+            while (true) {
+                if (i >= line.Length)
+                    return ParseResult.Error;
+
+                char c = line[i];
+                ++i;
+               
+                if (c == ' ' || c == '\t') {
+                
+                } else if (state == States.Start) {
+                    if (c == '#')
+                        state = States.Hash;
+                    else if (c == '/') {
+                        if (i >= line.Length)
+                            return ParseResult.Error;
+                        if (line[i] == '/')
+                            return ParseResult.Ok; // Matched C++ style comment
+                    } else
+                        return ParseResult.Error;
+                } else if (state == States.Hash) {
+                    --i;
+                    if (line.IndexOf("include", i) == i) {
+                        i += 7;
+                        state = States.Include;
+                    } else
+                        return ParseResult.Ok; // Matched preprocessor other than #include
+                } else if (state == States.Include) {
+                    if (c == '<') {
+                        path_start = i;
+                        state = States.AngleBracket;
+                    } else if (c == '"') {
+                        path_start = i;
+                         state = States.Quote;
+                    } else
+                        return ParseResult.Error;
+                } else if (state == States.AngleBracket) {
+                    if (c == '>') {
+                        result.SystemIncludes.Add(line.Substring(path_start, i-path_start-1));
+                        return ParseResult.Ok;
+                    }
+                } else if (state == States.Quote) {
+                    if (c == '"') {
+                        result.LocalIncludes.Add(line.Substring(path_start, i-path_start-1));
+                        return ParseResult.Ok;
+                    }
+                }
+            }
+        }
+
         /// <summary>
         /// Simple parser... only looks for #include lines. Does not take #defines or comments into account.
         /// </summary>
             res.Lines = lines.Count();
             foreach (string line in lines)
             {
-                if (line.Contains("#include"))
+                if (line.Contains('#') && line.Contains("include"))
                 {
-                    int i = line.IndexOf('#');
-                    int lt = line.IndexOf('<', i);
-                    int qt = line.IndexOf('"', i);
-
-                    if (lt < 0 && qt < 0 || lt > 0 && qt > 0)
-                    {
+                    ParseResult r = ParseLine(line, res);
+                    if (r == ParseResult.Error)
                         errors.Add("Could not parse line: " + line + " in file: " + fi.FullName);
-                        continue;
-                    }
-
-                    if (qt<0) {
-                        int gt = line.IndexOf('>', lt+1);
-                        res.SystemIncludes.Add(line.Substring(lt+1,gt-lt-1));
-                    } else {
-                        int qt2 = line.IndexOf('"', qt+1);
-                        res.LocalIncludes.Add(line.Substring(qt+1,qt2-qt-1));
-                    }
                 }
             }
             return res;
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.