\r
void define (string def)\r
{\r
- if (RootContext.AllDefines.Contains (def))\r
+ if (!RootContext.AllDefines.Contains (def)){\r
+ RootContext.AllDefines [def] = true;\r
+ }\r
+ if (defines.Contains (def))\r
return;\r
- RootContext.AllDefines [def] = true;\r
+ defines [def] = true;\r
}\r
\r
public Tokenizer (System.IO.Stream input, string fname, ArrayList defs)\r
if (Char.IsDigit (e))\r
c = (int) e - (int) '0';\r
else\r
- c = (int) e - (int) 'A';\r
+ c = (int) e - (int) 'A' + 10;\r
total = (total * 16) + c;\r
if (count == -1){\r
int p = peekChar ();\r
return;\r
}\r
\r
+ char[] whitespace = { ' ', '\t' };\r
+ if (arg.IndexOfAny (whitespace) != -1){\r
+ Report.Error(1025, Location, "Single-line comment or end-of-line expected");\r
+ return;\r
+ }\r
+\r
+ foreach (char c in arg){\r
+ if (!Char.IsLetter (c) && (c != '_')){\r
+ Report.Error(1001, Location, "Identifier expected");\r
+ return;\r
+ }\r
+ }\r
+\r
if (is_define){\r
if (defines == null)\r
defines = new Hashtable ();\r
return false;\r
}\r
\r
- if (Char.IsLetter (c) || c == '_'){\r
+ if (is_identifier_start_character(c)){\r
int j = 1;\r
\r
while (j < len){\r
c = s [j];\r
\r
- if (Char.IsLetter (c) || Char.IsDigit (c) || c == '_'){\r
+ if (is_identifier_part_character(c)){\r
j++;\r
continue;\r
}\r
\r
get_cmd_arg (out cmd, out arg);\r
\r
+ // Eat any trailing whitespaces and single-line comments\r
+ if (arg.IndexOf ("//") != -1)\r
+ arg = arg.Substring (0, arg.IndexOf ("//"));\r
+ arg = arg.TrimEnd (' ', '\t');\r
+\r
//\r
// The first group of pre-processing instructions is always processed\r
//\r
\r
Report.Error (1024, Location, "Preprocessor directive expected (got: " + cmd + ")");\r
return true;\r
+\r
+ }\r
+\r
+ private int consume_string(bool quoted) \r
+ {\r
+ int c;\r
+ string_builder.Length = 0;\r
+ \r
+ while ((c = getChar ()) != -1){\r
+ if (c == '"'){\r
+ if (quoted && peekChar () == '"'){\r
+ string_builder.Append ((char) c);\r
+ getChar ();\r
+ continue;\r
+ } else {\r
+ val = string_builder.ToString ();\r
+ return Token.LITERAL_STRING;\r
+ }\r
+ }\r
+\r
+ if (c == '\n' && !quoted) {\r
+ Report.Error(1010, Location, "Newline in constant");\r
+ }\r
+\r
+ if (!quoted){\r
+ c = escape (c);\r
+ if (c == -1)\r
+ return Token.ERROR;\r
+ }\r
+ string_builder.Append ((char) c);\r
+ }\r
+\r
+ Report.Error (1039, Location, "Unterminated string literal");\r
+ return Token.EOF;\r
+ }\r
+\r
+ private int consume_identifier(int c, bool quoted) \r
+ {\r
+ id_builder.Length = 0;\r
+\r
+ id_builder.Append ((char) c);\r
+ \r
+ while ((c = peekChar ()) != -1) {\r
+ if (is_identifier_part_character ((char) c)){\r
+ id_builder.Append ((char)getChar ());\r
+ col++;\r
+ } else \r
+ break;\r
+ }\r
+ \r
+ string ids = id_builder.ToString ();\r
+\r
+ if (!is_keyword (ids) || quoted) {\r
+ val = ids;\r
+ if (ids.Length > 512){\r
+ Report.Error (\r
+ 645, Location,\r
+ "Identifier too long (limit is 512 chars)");\r
+ }\r
+ return Token.IDENTIFIER;\r
+ }\r
+\r
+ // true, false and null are in the hash anyway.\r
+ return GetKeyword (ids);\r
}\r
\r
public int xtoken ()\r
{\r
int t;\r
- bool allow_keyword_as_ident = false;\r
bool doread = false;\r
int c;\r
\r
val = null;\r
// optimization: eliminate col and implement #directive semantic correctly.\r
for (;(c = getChar ()) != -1; col++) {\r
- if (Char.IsLetter ((char)c) || c == '_'){\r
- string ids;\r
-\r
- id_builder.Length = 0;\r
+ if (is_identifier_start_character((char)c)){\r
tokens_seen = true;\r
- id_builder.Append ((char) c);\r
- \r
- while ((c = peekChar ()) != -1) {\r
- if (is_identifier_part_character ((char) c)){\r
- id_builder.Append ((char)getChar ());\r
- col++;\r
- } else \r
- break;\r
- }\r
- \r
- ids = id_builder.ToString ();\r
-\r
- if (!is_keyword (ids) || allow_keyword_as_ident) {\r
- val = ids;\r
- if (ids.Length > 512){\r
- Report.Error (\r
- 645, Location,\r
- "Identifier too long (limit is 512 chars)");\r
- }\r
- allow_keyword_as_ident = false;\r
- return Token.IDENTIFIER;\r
- }\r
-\r
- // true, false and null are in the hash anyway.\r
- return GetKeyword (ids);\r
-\r
+ return consume_identifier(c, false);\r
}\r
\r
if (c == '.'){\r
any_token_seen |= tokens_seen;\r
tokens_seen = false;\r
if (c == -1)\r
- Report.Error (1027, Location, "#endif expected");\r
+ Report.Error (1027, Location, "#endif/#endregion expected");\r
continue;\r
}\r
\r
return t;\r
}\r
\r
- if (c == '"'){\r
- string_builder.Length = 0;\r
- \r
- tokens_seen = true;\r
- \r
- while ((c = getChar ()) != -1){\r
- if (c == '"'){\r
- if (allow_keyword_as_ident && peekChar () == '"'){\r
- string_builder.Append ((char) c);\r
- getChar ();\r
- continue;\r
- } \r
- allow_keyword_as_ident = false;\r
- val = string_builder.ToString ();\r
- return Token.LITERAL_STRING;\r
- }\r
-\r
- if (!allow_keyword_as_ident){\r
- c = escape (c);\r
- if (c == -1)\r
- return Token.ERROR;\r
- }\r
- string_builder.Append ((char) c);\r
- }\r
+ if (c == '"') {\r
+ return consume_string(false);\r
}\r
\r
if (c == '\''){\r
continue;\r
}\r
\r
- if (c == '@'){\r
- tokens_seen = true;\r
- allow_keyword_as_ident = true;\r
- continue;\r
+ if (c == '@') {\r
+ c = getChar();\r
+ if (c == '"') {\r
+ tokens_seen = true;\r
+ return consume_string(true);\r
+ } else if (is_identifier_start_character((char) c)){\r
+ return consume_identifier(c, true);\r
+ } else {\r
+ Report.Error(1033, Location, "'@' must be followed by string constant or identifier");\r
+ }\r
}\r
\r
error_details = ((char)c).ToString ();\r
return Token.ERROR;\r
}\r
\r
- if (ifstack != null && ifstack.Count > 1)\r
- Report.Error (1027, Location, "#endif expected");\r
+ if (ifstack != null && ifstack.Count >= 1)\r
+ Report.Error (1027, Location, "#endif/#endregion expected");\r
+\r
return Token.EOF;\r
}\r
}\r