//\r
// Values for the associated token returned\r
//\r
- System.Text.StringBuilder number;\r
int putback_char;\r
Object val;\r
\r
// pre-processor if stack state:\r
//\r
Stack ifstack;\r
+\r
+ static System.Text.StringBuilder id_builder;\r
+ static System.Text.StringBuilder string_builder;\r
+ static System.Text.StringBuilder number_builder;\r
\r
//\r
// Details about the error encoutered by the tokenizer\r
static Tokenizer ()\r
{\r
InitTokens ();\r
- csharp_format_info = new NumberFormatInfo ();\r
- csharp_format_info.CurrencyDecimalSeparator = ".";\r
- styles = NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint;\r
+ csharp_format_info = NumberFormatInfo.InvariantInfo;\r
+ styles = NumberStyles.Float;\r
+ \r
+ id_builder = new System.Text.StringBuilder ();\r
+ string_builder = new System.Text.StringBuilder ();\r
+ number_builder = new System.Text.StringBuilder ();\r
}\r
\r
bool is_keyword (string name)\r
return new Location (ref_line);\r
}\r
}\r
+\r
+ void define (string def)\r
+ {\r
+ if (!RootContext.AllDefines.Contains (def)){\r
+ RootContext.AllDefines [def] = true;\r
+ }\r
+ if (defines.Contains (def))\r
+ return;\r
+ defines [def] = true;\r
+ }\r
\r
public Tokenizer (System.IO.Stream input, string fname, ArrayList defs)\r
{\r
if (defs != null){\r
defines = new Hashtable ();\r
foreach (string def in defs)\r
- defines [def] = true;\r
+ define (def);\r
}\r
\r
//\r
bool seen_digits = false;\r
\r
if (c != -1)\r
- number.Append ((char) c);\r
+ number_builder.Append ((char) c);\r
\r
while ((d = peekChar ()) != -1){\r
if (Char.IsDigit ((char)d)){\r
- number.Append ((char) d);\r
+ number_builder.Append ((char) d);\r
getChar ();\r
seen_digits = true;\r
} else\r
\r
bool is_hex (char e)\r
{\r
- return Char.IsDigit (e) || (e >= 'A' && e <= 'F');\r
+ return Char.IsDigit (e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');\r
}\r
\r
void hex_digits (int c)\r
int d;\r
\r
if (c != -1)\r
- number.Append ((char) c);\r
+ number_builder.Append ((char) c);\r
while ((d = peekChar ()) != -1){\r
char e = Char.ToUpper ((char) d);\r
\r
if (is_hex (e)){\r
- number.Append ((char) e);\r
+ number_builder.Append ((char) e);\r
getChar ();\r
} else\r
break;\r
//\r
int adjust_int (int c)\r
{\r
- ulong ul = System.UInt64.Parse (number.ToString ());\r
- return integer_type_suffix (ul, c);\r
+ try {\r
+ ulong ul = System.UInt64.Parse (number_builder.ToString ());\r
+ return integer_type_suffix (ul, c);\r
+ } catch (OverflowException) {\r
+ error_details = "Integral constant is too large";\r
+ Report.Error (1021, Location, error_details);\r
+ val = 0ul;\r
+ return Token.LITERAL_INTEGER;\r
+ }\r
}\r
-\r
+ \r
int adjust_real (int t)\r
{\r
- string s = number.ToString ();\r
+ string s = number_builder.ToString ();\r
\r
switch (t){\r
case Token.LITERAL_DECIMAL:\r
- val = new System.Decimal ();\r
- val = System.Decimal.Parse (\r
- s, styles, csharp_format_info);\r
- break;\r
- case Token.LITERAL_DOUBLE:\r
- val = new System.Double ();\r
- val = System.Double.Parse (\r
- s, styles, csharp_format_info);\r
+ try {\r
+ val = System.Decimal.Parse (s, styles, csharp_format_info);\r
+ } catch (OverflowException) {\r
+ val = 0m; \r
+ error_details = "Floating-point constant is outside the range of the type 'decimal'";\r
+ Report.Error(594, Location, error_details);\r
+ }\r
break;\r
case Token.LITERAL_FLOAT:\r
- val = new System.Double ();\r
- val = (float) System.Double.Parse (\r
- s, styles, csharp_format_info);\r
+ try {\r
+ val = (float) System.Double.Parse (s, styles, csharp_format_info);\r
+ } catch (OverflowException) {\r
+ val = 0.0f; \r
+ error_details = "Floating-point constant is outside the range of the type 'float'";\r
+ Report.Error(594, Location, error_details);\r
+ }\r
break;\r
-\r
+ \r
+ case Token.LITERAL_DOUBLE:\r
case Token.NONE:\r
- val = new System.Double ();\r
- val = System.Double.Parse (\r
- s, styles, csharp_format_info);\r
t = Token.LITERAL_DOUBLE;\r
+ try {\r
+ val = System.Double.Parse (s, styles, csharp_format_info);\r
+ } catch (OverflowException) {\r
+ val = 0.0; \r
+ error_details = "Floating-point constant is outside the range of the type 'double'";\r
+ Report.Error(594, Location, error_details);\r
+ }\r
break;\r
}\r
return t;\r
int is_number (int c)\r
{\r
bool is_real = false;\r
- number = new System.Text.StringBuilder ();\r
int type;\r
\r
- number.Length = 0;\r
+ number_builder.Length = 0;\r
\r
if (Char.IsDigit ((char)c)){\r
if (c == '0' && peekChar () == 'x' || peekChar () == 'X'){\r
getChar ();\r
hex_digits (-1);\r
\r
- string s = number.ToString ();\r
+ string s = number_builder.ToString ();\r
\r
ul = System.UInt64.Parse (s, NumberStyles.HexNumber);\r
return integer_type_suffix (ul, peekChar ());\r
c = getChar ();\r
} else {\r
putback ('.');\r
- number.Length -= 1;\r
+ number_builder.Length -= 1;\r
return adjust_int (-1);\r
}\r
}\r
\r
if (c == 'e' || c == 'E'){\r
is_real = true;\r
- number.Append ("e");\r
+ number_builder.Append ("e");\r
c = getChar ();\r
\r
- if (c == '+'){\r
- number.Append ((char) c);\r
- c = getChar ();\r
- } else if (c == '-'){\r
- number.Append ((char) c);\r
- c = getChar ();\r
- }\r
+ if (c == '+')\r
+ number_builder.Append ((char) c);\r
+ else if (c == '-')\r
+ number_builder.Append ((char) c);\r
decimal_digits (-1);\r
c = getChar ();\r
}\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
\r
char [] quotes = { '\"' };\r
\r
- ref_name = arg.Substring (pos);\r
- ref_name.TrimStart (quotes);\r
- ref_name.TrimEnd (quotes);\r
+ ref_name = arg.Substring (pos). Trim(quotes);\r
} else {\r
ref_line = System.Int32.Parse (arg);\r
}\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
- defines [arg] = 1;\r
+ define (arg);\r
} else {\r
if (defines == null)\r
return;\r
\r
bool pp_primary (ref string s)\r
{\r
- s.Trim ();\r
+ s = s.Trim ();\r
int len = s.Length;\r
\r
if (len > 0){\r
if (c == '('){\r
s = s.Substring (1);\r
bool val = pp_expr (ref s);\r
- if (s.Length > 0 && s [0] == ')')\r
+ if (s.Length > 0 && s [0] == ')'){\r
+ s = s.Substring (1);\r
return val;\r
+ }\r
Error_InvalidDirective ();\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
s = s.Trim ();\r
int len = s.Length;\r
if (len > 0){\r
- if (s [0] == '|'){\r
+ char c = s [0];\r
+ \r
+ if (c == '|'){\r
if (len > 2 && s [1] == '|'){\r
s = s.Substring (2);\r
return va || pp_and (ref s);\r
Error_InvalidDirective ();\r
return false;\r
}\r
- } else {\r
- Error_InvalidDirective ();\r
- return false;\r
- }\r
+ } \r
}\r
\r
return va;\r
bool eval (string s)\r
{\r
bool v = pp_expr (ref s);\r
+ s = s.Trim ();\r
+ if (s.Length != 0){\r
+ Error_InvalidDirective ();\r
+ return false;\r
+ }\r
\r
return v;\r
}\r
// if false, the code stays in a loop until another directive is\r
// reached.\r
//\r
- bool handle_preprocessing_directive ()\r
+ bool handle_preprocessing_directive (bool caller_is_taking)\r
{\r
char [] blank = { ' ', '\t' };\r
string cmd, arg;\r
\r
get_cmd_arg (out cmd, out arg);\r
- \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
switch (cmd){\r
case "line":\r
if (!PreProcessLine (arg))\r
"Argument to #line directive is missing or invalid");\r
return true;\r
\r
- case "define":\r
- if (any_token_seen){\r
- Error_TokensSeen ();\r
- return true;\r
- }\r
- PreProcessDefinition (true, arg);\r
- return true;\r
-\r
- case "undef":\r
- if (any_token_seen){\r
- Error_TokensSeen ();\r
- return true;\r
- }\r
- PreProcessDefinition (false, arg);\r
- return true;\r
-\r
- case "error":\r
- Report.Error (1029, Location, "#error: '" + arg + "'");\r
- return true;\r
-\r
- case "warning":\r
- Report.Warning (1030, Location, "#warning: '" + arg + "'");\r
- return true;\r
-\r
case "region":\r
arg = "true";\r
goto case "if";\r
return false;\r
}\r
}\r
- \r
+\r
+ //\r
+ // These are only processed if we are in a `taking' block\r
+ //\r
+ if (!caller_is_taking)\r
+ return false;\r
+ \r
+ switch (cmd){\r
+ case "define":\r
+ if (any_token_seen){\r
+ Error_TokensSeen ();\r
+ return true;\r
+ }\r
+ PreProcessDefinition (true, arg);\r
+ return true;\r
+\r
+ case "undef":\r
+ if (any_token_seen){\r
+ Error_TokensSeen ();\r
+ return true;\r
+ }\r
+ PreProcessDefinition (false, arg);\r
+ return true;\r
+\r
+ case "error":\r
+ Report.Error (1029, Location, "#error: '" + arg + "'");\r
+ return true;\r
+\r
+ case "warning":\r
+ Report.Warning (1030, Location, "#warning: '" + arg + "'");\r
+ return true;\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
- System.Text.StringBuilder id = new System.Text.StringBuilder ();\r
- string ids;\r
-\r
+ if (is_identifier_start_character((char)c)){\r
tokens_seen = true;\r
- id.Append ((char) c);\r
- \r
- while ((c = peekChar ()) != -1) {\r
- if (is_identifier_part_character ((char) c)){\r
- id.Append ((char)getChar ());\r
- col++;\r
- } else \r
- break;\r
- }\r
- \r
- ids = id.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
// FIXME: In C# the '#' is not limited to appear\r
// on the first column.\r
if (c == '#' && !tokens_seen){\r
+ bool cont = true;\r
+ \r
start_again:\r
\r
- bool cont = handle_preprocessing_directive ();\r
+ cont = handle_preprocessing_directive (cont);\r
\r
if (cont){\r
col = 0;\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
- System.Text.StringBuilder s = new System.Text.StringBuilder ();\r
- tokens_seen = true;\r
- \r
- while ((c = getChar ()) != -1){\r
- if (c == '"'){\r
- if (allow_keyword_as_ident && peekChar () == '"'){\r
- s.Append ((char) c);\r
- getChar ();\r
- continue;\r
- } \r
- allow_keyword_as_ident = false;\r
- val = s.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
- s.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