bool handle_remove_add = false;\r
bool handle_assembly = false;\r
bool handle_constraints = false;\r
+ bool handle_typeof = false;\r
\r
//\r
// Whether tokens have been seen on this line\r
handle_constraints = value;\r
}\r
}\r
+\r
+ public bool TypeOfParsing {\r
+ get {\r
+ return handle_typeof;\r
+ }\r
+\r
+ set {\r
+ handle_typeof = value;\r
+ }\r
+ }\r
\r
//\r
// Class variables\r
const int max_id_size = 512;\r
static char [] id_builder = new char [max_id_size];\r
\r
+ static CharArrayHashtable [] identifiers = new CharArrayHashtable [max_id_size + 1];\r
+\r
const int max_number_size = 128;\r
static char [] number_builder = new char [max_number_size];\r
static int number_pos;\r
{\r
keywords = new CharArrayHashtable [64];\r
\r
+ AddKeyword ("__arglist", Token.ARGLIST);\r
AddKeyword ("abstract", Token.ABSTRACT);\r
AddKeyword ("as", Token.AS);\r
AddKeyword ("add", Token.ADD);\r
AddKeyword ("volatile", Token.VOLATILE);\r
AddKeyword ("where", Token.WHERE);\r
AddKeyword ("while", Token.WHILE);\r
-\r
- if (RootContext.V2){\r
- AddKeyword ("__yield", Token.YIELD);\r
- AddKeyword ("yield", Token.YIELD);\r
- }\r
+ AddKeyword ("partial", Token.PARTIAL);\r
}\r
\r
//\r
return -1;\r
if (handle_constraints == false && res == Token.WHERE)\r
return -1;\r
+\r
return res;\r
\r
}\r
Mono.CSharp.Location.Push (file);\r
}\r
\r
- bool is_identifier_start_character (char c)\r
+ public static void Cleanup () {\r
+ identifiers = null;\r
+ }\r
+\r
+ static bool is_identifier_start_character (char c)\r
{\r
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || Char.IsLetter (c);\r
}\r
\r
- bool is_identifier_part_character (char c)\r
+ static bool is_identifier_part_character (char c)\r
{\r
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || Char.IsLetter (c);\r
}\r
+ \r
+ public static bool IsValidIdentifier (string s)\r
+ {\r
+ if (s == null || s.Length == 0)\r
+ return false;\r
+ \r
+ if (!is_identifier_start_character (s [0]))\r
+ return false;\r
+ \r
+ for (int i = 1; i < s.Length; i ++)\r
+ if (! is_identifier_part_character (s [i]))\r
+ return false;\r
+ \r
+ return true;\r
+ }\r
+\r
+ bool parse_generic_dimension (out int dimension)\r
+ {\r
+ dimension = 1;\r
+\r
+ again:\r
+ int the_token = token ();\r
+ if (the_token == Token.OP_GENERICS_GT)\r
+ return true;\r
+ else if (the_token == Token.COMMA) {\r
+ dimension++;\r
+ goto again;\r
+ }\r
+\r
+ return false;\r
+ }\r
\r
bool parse_less_than ()\r
{\r
\r
if (the_token == Token.OP_GENERICS_GT)\r
return true;\r
- else if (the_token == Token.COMMA)\r
+ else if ((the_token == Token.COMMA) || (the_token == Token.DOT))\r
goto start;\r
else if (the_token == Token.OP_GENERICS_LT) {\r
if (!parse_less_than ())\r
return false;\r
goto again;\r
+ } else if (the_token == Token.OPEN_BRACKET) {\r
+ rank_specifiers:\r
+ the_token = token ();\r
+ if (the_token == Token.CLOSE_BRACKET)\r
+ goto again;\r
+ else if (the_token == Token.COMMA)\r
+ goto rank_specifiers;\r
+ return false;\r
}\r
\r
return false;\r
if (parsing_generic_less_than++ > 0)\r
return Token.OP_GENERICS_LT;\r
\r
- // Save current position and parse next token.\r
int old = reader.Position;\r
+ if (handle_typeof) {\r
+ int dimension;\r
+ if (parse_generic_dimension (out dimension)) {\r
+ val = dimension;\r
+ return Token.GENERIC_DIMENSION;\r
+ }\r
+ reader.Position = old;\r
+ putback_char = -1;\r
+ }\r
+\r
+ // Save current position and parse next token.\r
+ old = reader.Position;\r
bool is_generic_lt = parse_less_than ();\r
reader.Position = old;\r
putback_char = -1;\r
return Token.CARRET;\r
}\r
\r
-#if FIXME\r
- if (c == '>'){\r
- if (deambiguate_greater_than == 0)\r
- return Token.OP_GT;\r
-\r
- --deambiguate_greater_than;\r
-\r
- // Save current position and parse next token.\r
- int old = reader.Position;\r
- int new_token = token ();\r
- reader.Position = old;\r
- putback_char = -1;\r
-\r
- switch (new_token) {\r
- case Token.OPEN_PARENS:\r
- case Token.CLOSE_PARENS:\r
- case Token.CLOSE_BRACKET:\r
- case Token.OP_GT:\r
- case Token.COLON:\r
- case Token.SEMICOLON:\r
- case Token.COMMA:\r
- case Token.DOT:\r
- case Token.INTERR:\r
- return Token.OP_GENERICS_GT;\r
-\r
- default:\r
- return Token.OP_GT;\r
- }\r
- }\r
-#endif\r
-\r
return Token.ERROR;\r
}\r
\r
break;\r
\r
case 'l':\r
- if (!is_unsigned){\r
+ if (!is_unsigned && (RootContext.WarningLevel >= 4)){\r
//\r
// if we have not seen anything in between\r
// report this error\r
//\r
- Report.Warning (\r
- 78, Location,\r
- "the 'l' suffix is easily confused with digit `1'," +\r
- " use 'L' for clarity");\r
+ Report.Warning (78, Location, "The 'l' suffix is easily confused with the digit '1' (use 'L' for clarity)");\r
}\r
goto case 'L';\r
\r
val = 0ul;\r
return Token.LITERAL_INTEGER;\r
}\r
+ catch (FormatException) {\r
+ Report.Error (1013, Location, "Invalid number");\r
+ val = 0ul;\r
+ return Token.LITERAL_INTEGER;\r
+ }\r
}\r
\r
int adjust_real (int t)\r
case Token.TYPEOF:\r
case Token.UNCHECKED:\r
case Token.UNSAFE:\r
+\r
+ //\r
+ // These can be part of a member access\r
+ //\r
+ case Token.INT:\r
+ case Token.UINT:\r
+ case Token.SHORT:\r
+ case Token.USHORT:\r
+ case Token.LONG:\r
+ case Token.ULONG:\r
+ case Token.DOUBLE:\r
+ case Token.FLOAT:\r
+ case Token.CHAR:\r
return true;\r
\r
default:\r
public int token ()\r
{\r
current_token = xtoken ();\r
- return current_token;\r
+\r
+ if (current_token != Token.DEFAULT)\r
+ return current_token;\r
+\r
+ int c = consume_whitespace ();\r
+ if (c == -1)\r
+ current_token = Token.ERROR;\r
+ else if (c == '(')\r
+ current_token = Token.DEFAULT_OPEN_PARENS;\r
+ else\r
+ putback (c);\r
+\r
+ return current_token;\r
}\r
\r
static StringBuilder static_cmd_arg = new System.Text.StringBuilder ();\r
tokens_seen = false;\r
arg = "";\r
static_cmd_arg.Length = 0;\r
+\r
+ // skip over white space\r
+ while ((c = getChar ()) != -1 && (c != '\n') && ((c == '\r') || (c == ' ') || (c == '\t')))\r
+ ;\r
\r
- while ((c = getChar ()) != -1 && (c != '\n') && (c != ' ') && (c != '\t') && (c != '\r')){\r
- static_cmd_arg.Append ((char) c);\r
+ while ((c != -1) && (c != '\n') && (c != ' ') && (c != '\t') && (c != '\r')){\r
+ if (is_identifier_part_character ((char) c)){\r
+ static_cmd_arg.Append ((char) c);\r
+ c = getChar ();\r
+ } else {\r
+ putback (c);\r
+ break;\r
+ }\r
}\r
\r
cmd = static_cmd_arg.ToString ();\r
ref_name = file_name;\r
Location.Push (ref_name);\r
return true;\r
+ } else if (arg == "hidden"){\r
+ //\r
+ // We ignore #line hidden\r
+ //\r
+ return true;\r
}\r
\r
try {\r
\r
string name = arg.Substring (pos). Trim (quotes);\r
ref_name = Location.LookupFile (name);\r
+ file_name.HasLineDirective = true;\r
+ ref_name.HasLineDirective = true;\r
Location.Push (ref_name);\r
} else {\r
ref_line = System.Int32.Parse (arg);\r
}\r
}\r
\r
+ /// <summary>\r
+ /// Handles #pragma directive\r
+ /// </summary>\r
+ void PreProcessPragma (string arg)\r
+ {\r
+ const string disable = "warning disable";\r
+ const string restore = "warning restore";\r
+\r
+ if (arg == disable) {\r
+ Report.RegisterWarningRegion (Location).WarningDisable (line);\r
+ return;\r
+ }\r
+\r
+ if (arg == restore) {\r
+ Report.RegisterWarningRegion (Location).WarningEnable (line);\r
+ return;\r
+ }\r
+\r
+ if (arg.StartsWith (disable)) {\r
+ int[] codes = ParseNumbers (arg.Substring (disable.Length));\r
+ foreach (int code in codes) {\r
+ if (code != 0)\r
+ Report.RegisterWarningRegion (Location).WarningDisable (Location, code);\r
+ }\r
+ return;\r
+ }\r
+\r
+ if (arg.StartsWith (restore)) {\r
+ int[] codes = ParseNumbers (arg.Substring (restore.Length));\r
+ foreach (int code in codes) {\r
+ Report.RegisterWarningRegion (Location).WarningEnable (Location, code);\r
+ }\r
+ return;\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
+ int[] ParseNumbers (string text)\r
+ {\r
+ string[] string_array = text.Split (',');\r
+ int[] values = new int [string_array.Length];\r
+ int index = 0;\r
+ foreach (string string_code in string_array) {\r
+ try {\r
+ values[index++] = int.Parse (string_code, System.Globalization.CultureInfo.InvariantCulture);\r
+ }\r
+ catch (FormatException) {\r
+ Report.Warning (1692, Location, "Invalid number");\r
+ }\r
+ }\r
+ return values;\r
+ }\r
+\r
bool eval_val (string s)\r
{\r
if (s == "true")\r
//\r
switch (cmd){\r
case "pragma":\r
- if (RootContext.V2)\r
- return true;\r
- break;\r
+ if (RootContext.Version == LanguageVersion.ISO_1) {\r
+ Report.FeatureIsNotStandardized (Location, "#pragma");\r
+ return caller_is_taking;\r
+ }\r
+\r
+ PreProcessPragma (arg);\r
+ return caller_is_taking;\r
\r
case "line":\r
if (!PreProcessLine (arg))\r
Report.Error (\r
1576, Location,\r
"Argument to #line directive is missing or invalid");\r
- return true;\r
+ return caller_is_taking;\r
\r
case "region":\r
region_directive = true;\r
return true;\r
\r
case "warning":\r
- Report.Warning (1030, Location, "#warning: '" + arg + "'");\r
+ Report.Warning (1030, Location, "#warning: '{0}'", arg);\r
return true;\r
}\r
\r
return Token.EOF;\r
}\r
\r
+ private int consume_identifier (int s)\r
+ {\r
+ int res = consume_identifier (s, false);\r
+\r
+ if (res == Token.PARTIAL) {\r
+ // Save current position and parse next token.\r
+ int old = reader.Position;\r
+ int old_putback = putback_char;\r
+\r
+ putback_char = -1;\r
+\r
+ int next_token = token ();\r
+ bool ok = (next_token == Token.CLASS) ||\r
+ (next_token == Token.STRUCT) ||\r
+ (next_token == Token.INTERFACE);\r
+\r
+ reader.Position = old;\r
+ putback_char = old_putback;\r
+\r
+ if (ok)\r
+ return res;\r
+ else {\r
+ val = "partial";\r
+ return Token.IDENTIFIER;\r
+ }\r
+ }\r
+\r
+ return res;\r
+ }\r
+\r
private int consume_identifier (int s, bool quoted) \r
{\r
int pos = 1;\r
// Optimization: avoids doing the keyword lookup\r
// on uppercase letters and _\r
//\r
- if (s >= 'a'){\r
+ if (!quoted && (s >= 'a' || s == '_')){\r
int keyword = GetKeyword (id_builder, pos);\r
- if (keyword != -1 && !quoted)\r
+ if (keyword != -1)\r
return keyword;\r
}\r
\r
+ //\r
+ // Keep identifiers in an array of hashtables to avoid needless\r
+ // allocations\r
+ //\r
+\r
+ if (identifiers [pos] != null) {\r
+ val = identifiers [pos][id_builder];\r
+ if (val != null) {\r
+ return Token.IDENTIFIER;\r
+ }\r
+ }\r
+ else\r
+ identifiers [pos] = new CharArrayHashtable (pos);\r
+\r
val = new String (id_builder, 0, pos);\r
\r
+ char [] chars = new char [pos];\r
+ Array.Copy (id_builder, chars, pos);\r
+\r
+ identifiers [pos] [chars] = val;\r
+\r
return Token.IDENTIFIER;\r
}\r
- \r
- public int xtoken ()\r
+\r
+ int consume_whitespace ()\r
{\r
int t;\r
bool doread = false;\r
val = null;\r
// optimization: eliminate col and implement #directive semantic correctly.\r
for (;(c = getChar ()) != -1; col++) {\r
- if (c == ' ' || c == '\t' || c == '\f' || c == '\v' || c == '\r' || c == 0xa0){\r
- \r
- if (c == '\t')\r
- col = (((col + 8) / 8) * 8) - 1;\r
+ if (c == ' ')\r
+ continue;\r
+ \r
+ if (c == '\t') {\r
+ col = (((col + 8) / 8) * 8) - 1;\r
+ continue;\r
+ }\r
+ \r
+ if (c == ' ' || c == '\f' || c == '\v' || c == 0xa0)\r
+ continue;\r
+\r
+ if (c == '\r') {\r
+ if (peekChar () == '\n')\r
+ getChar ();\r
+\r
+ line++;\r
+ ref_line++;\r
+ col = 0;\r
+ any_token_seen |= tokens_seen;\r
+ tokens_seen = false;\r
continue;\r
}\r
\r
goto is_punct_label;\r
}\r
\r
- \r
- if (is_identifier_start_character ((char)c)){\r
- tokens_seen = true;\r
- return consume_identifier (c, false);\r
- }\r
-\r
is_punct_label:\r
- if ((t = is_punct ((char)c, ref doread)) != Token.ERROR){\r
- tokens_seen = true;\r
- if (doread){\r
- getChar ();\r
- col++;\r
- }\r
- return t;\r
- }\r
-\r
// white space\r
if (c == '\n'){\r
line++;\r
continue;\r
}\r
\r
- if (c >= '0' && c <= '9'){\r
- tokens_seen = true;\r
- return is_number (c);\r
- }\r
-\r
- if (c == '.'){\r
- tokens_seen = true;\r
- int peek = peekChar ();\r
- if (peek >= '0' && peek <= '9')\r
- return is_number (c);\r
- return Token.DOT;\r
- }\r
- \r
/* For now, ignore pre-processor commands */\r
// FIXME: In C# the '#' is not limited to appear\r
// on the first column.\r
Report.Error (1027, Location, "#endif/#endregion expected");\r
continue;\r
}\r
- \r
- if (c == '"') \r
- return consume_string (false);\r
\r
- if (c == '\''){\r
- c = getChar ();\r
- tokens_seen = true;\r
- if (c == '\''){\r
- error_details = "Empty character literal";\r
- Report.Error (1011, Location, error_details);\r
- return Token.ERROR;\r
- }\r
- c = escape (c);\r
- if (c == -1)\r
- return Token.ERROR;\r
- val = new System.Char ();\r
- val = (char) c;\r
- c = getChar ();\r
+ return c;\r
+ }\r
\r
- if (c != '\''){\r
- error_details = "Too many characters in character literal";\r
- Report.Error (1012, Location, error_details);\r
+ return -1;\r
+ }\r
+ \r
+ public int xtoken ()\r
+ {\r
+ int t;\r
+ bool doread = false;\r
+ int c;\r
\r
- // Try to recover, read until newline or next "'"\r
- while ((c = getChar ()) != -1){\r
- if (c == '\n' || c == '\''){\r
- line++;\r
- ref_line++;\r
- col = 0;\r
- break;\r
- } else\r
- col++;\r
- \r
- }\r
- return Token.ERROR;\r
- }\r
- return Token.LITERAL_CHARACTER;\r
- }\r
- \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
+ val = null;\r
+ // optimization: eliminate col and implement #directive semantic correctly.\r
+\r
+ c = consume_whitespace ();\r
+ if (c == -1)\r
+ return Token.EOF;\r
+\r
+ if (is_identifier_start_character ((char)c)){\r
+ tokens_seen = true;\r
+ return consume_identifier (c);\r
+ }\r
+\r
+ is_punct_label:\r
+ if ((t = is_punct ((char)c, ref doread)) != Token.ERROR){\r
+ tokens_seen = true;\r
+ if (doread){\r
+ getChar ();\r
+ col++;\r
}\r
+ return t;\r
+ }\r
+\r
+ if (c >= '0' && c <= '9'){\r
+ tokens_seen = true;\r
+ return is_number (c);\r
+ }\r
\r
- if (c == '#') {\r
- error_details = "Preprocessor directives must appear as the first non-whitespace " +\r
- "character on a line.";\r
+ if (c == '.'){\r
+ tokens_seen = true;\r
+ int peek = peekChar ();\r
+ if (peek >= '0' && peek <= '9')\r
+ return is_number (c);\r
+ return Token.DOT;\r
+ }\r
\r
- Report.Error (1040, Location, error_details);\r
+ if (c == '"') \r
+ return consume_string (false);\r
\r
+ if (c == '\''){\r
+ c = getChar ();\r
+ tokens_seen = true;\r
+ if (c == '\''){\r
+ error_details = "Empty character literal";\r
+ Report.Error (1011, Location, error_details);\r
return Token.ERROR;\r
}\r
+ c = escape (c);\r
+ if (c == -1)\r
+ return Token.ERROR;\r
+ val = new System.Char ();\r
+ val = (char) c;\r
+ c = getChar ();\r
+\r
+ if (c != '\''){\r
+ error_details = "Too many characters in character literal";\r
+ Report.Error (1012, Location, error_details);\r
\r
- error_details = ((char)c).ToString ();\r
+ // Try to recover, read until newline or next "'"\r
+ while ((c = getChar ()) != -1){\r
+ if (c == '\n' || c == '\''){\r
+ line++;\r
+ ref_line++;\r
+ col = 0;\r
+ break;\r
+ } else\r
+ col++;\r
+ }\r
+ return Token.ERROR;\r
+ }\r
+ return Token.LITERAL_CHARACTER;\r
+ }\r
\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
+ if (c == '#') {\r
+ error_details = "Preprocessor directives must appear as the first non-whitespace " +\r
+ "character on a line.";\r
+\r
+ Report.Error (1040, Location, error_details);\r
+\r
return Token.ERROR;\r
}\r
\r
- return Token.EOF;\r
+ error_details = ((char)c).ToString ();\r
+\r
+ return Token.ERROR;\r
}\r
\r
public void cleanup ()\r
}\r
\r
}\r
-\r
}\r
}\r
\r