#region Copyright
// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (C) 2015 Ian Horswill
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in the
// Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// --------------------------------------------------------------------------------------------------------------------
#endregion
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using Object = System.Object;
// Port of Koen De Bosschere's C-language Prolog reader
// Anything good about this code is due to him, anything bad is
// due to Ian Horswill's lame port of it to C#.
// There are a lot of stylistic things that ReSharper complains about either because of C/C#
// stylistic differences or because I had to do surgery on the code to make it work in a
// different environment. I could let resharper fix them, but then if something went wrong
// then I'd have to debug a big chunk of code that I don't fully understand. So instead I'm
// just disabling ReSharper's stylistic complaints.
// ReSharper disable InconsistentNaming
// ReSharper disable UnusedParameter.Local
// ReSharper disable RedundantIfElseBlock
// ReSharper disable PossibleNullReferenceException
// ReSharper disable RedundantAssignment
// ReSharper disable SuggestUseVarKeywordEvident
// ReSharper disable TooWideLocalVariableScope
// ReSharper disable JoinDeclarationAndInitializer
namespace Prolog
{
public class ISOPrologReader
{
///
/// Reads a term from a string.
///
/// String to read the term from
/// The term represented in the string
public static object Read(string s)
{
return new ISOPrologReader(s).ReadTerm();
}
#region Constructors
public ISOPrologReader(TextReader input) : this(input, new List())
{
}
public ISOPrologReader(TextReader input, List vars)
{
inputReader = input;
Variables = vars;
}
public ISOPrologReader(string input) : this(new StringReader(input)) {}
public ISOPrologReader(string input, List vars) : this(new StringReader(input), vars) { }
static ISOPrologReader()
{
InitTokenizer();
InitOperators();
}
#endregion
private readonly TextReader inputReader;
private int linenumber = 1;
public int LineNumber
{
get { return linenumber; }
}
public void Close()
{
var s = inputReader as StreamReader;
if (s != null) s.Close();
}
#region Operator table
private class OperatorInfo
{
public int Prefixpriority;
public int Infixpriority;
public int Postfixpriority;
// ReSharper disable once InconsistentNaming
public int specifier;
}
static readonly Dictionary OperatorTable = new Dictionary();
internal static bool Operator(string op, out int prepri, out int inpri, out int postpri, out int spec)
{
OperatorInfo info;
if (OperatorTable.TryGetValue(op, out info))
{
prepri = info.Prefixpriority;
inpri = info.Infixpriority;
postpri = info.Postfixpriority;
spec = info.specifier;
return true;
}
prepri = inpri = postpri = spec = 0;
return false;
}
public static bool DeclareOperator(int pri, int spec, string op)
{
OperatorInfo i;
if (!OperatorTable.TryGetValue(op, out i))
{
i = new OperatorInfo();
OperatorTable[op] = i;
}
if ((isprefix(spec) && isprefix(i.specifier) && pri != i.Prefixpriority)
|| (isinfix(spec) && ((isinfix(i.specifier) && pri != i.Infixpriority) || ispostfix(i.specifier)))
|| (ispostfix(spec) && ((ispostfix(i.specifier) && pri != i.Postfixpriority) || isinfix(i.specifier))))
throw new InvalidOperationException("Operator definition conflicts with previous definition.");
i.specifier |= spec;
if (isprefix(spec))
i.Prefixpriority = pri;
else if (isinfix(spec))
i.Infixpriority = pri;
else
i.Postfixpriority = pri;
return true;
}
public static void DeclareOperator(int pri, Symbol type, Symbol op)
{
DeclareOperator(pri, Specifier(type.Name), op.Name);
}
static void InitOperators()
{
DeclareOperator(1200, XFX, ":-");
DeclareOperator(1200, XFX, "-->");
DeclareOperator(1200, FX, ":-");
DeclareOperator(1200, FX, "?-");
DeclareOperator(1100, XFY, ";");
DeclareOperator(1050, XFY, "->");
DeclareOperator(1000, XFY, ",");
DeclareOperator(900, FY, "\\+"); /* binprolog */
DeclareOperator(700, XFX, "=");
DeclareOperator(700, XFX, "\\=");
DeclareOperator(700, XFX, "==");
DeclareOperator(700, XFX, "\\==");
DeclareOperator(700, XFX, "@<");
DeclareOperator(700, XFX, "@=<");
DeclareOperator(700, XFX, "@>");
DeclareOperator(700, XFX, "@>=");
DeclareOperator(700, XFX, "=..");
DeclareOperator(700, XFX, "is");
DeclareOperator(700, XFX, "=:=");
DeclareOperator(700, XFX, "=\\=");
DeclareOperator(700, XFX, "<");
DeclareOperator(700, XFX, "=<");
DeclareOperator(700, XFX, ">");
DeclareOperator(700, XFX, ">=");
//DeclareOperator(600, XFY, ":");
DeclareOperator(500, YFX, "+");
DeclareOperator(500, YFX, "-");
DeclareOperator(500, YFX, "/\\");
DeclareOperator(500, YFX, "\\/");
DeclareOperator(500, YFX, "#"); /* binprolog */
DeclareOperator(400, YFX, "*");
DeclareOperator(400, YFX, ":"); // Differs from SWI!
DeclareOperator(400, YFX, "/");
DeclareOperator(400, YFX, "//");
DeclareOperator(400, YFX, "rem");
DeclareOperator(400, YFX, "mod");
DeclareOperator(400, YFX, "<<");
DeclareOperator(400, YFX, ">>");
DeclareOperator(300, FX, "/");
DeclareOperator(200, XFX, "**");
DeclareOperator(200, XFY, "^");
DeclareOperator(200, FY, "-");
DeclareOperator(200, FY, "~");
DeclareOperator(200, FY, "\\");
DeclareOperator(100, XFY, "@");
DeclareOperator(40, YFX, ".");
DeclareOperator(40, XFX, "::");
DeclareOperator(950, YF, "&");
DeclareOperator(950, FY, "?");
/* addoperator(950, FY, "!"); */
DeclareOperator(200, FY, "++");
DeclareOperator(200, YF, "--");
DeclareOperator(945, XF, "xf");
DeclareOperator(945, YF, "yf");
DeclareOperator(945, FX, "fx");
DeclareOperator(945, FY, "fy");
DeclareOperator(945, XFX, "xfx");
DeclareOperator(945, XFY, "xfy");
DeclareOperator(945, YFX, "yfx");
DeclareOperator(1150, FX, "dynamic");
DeclareOperator(1150, FX, "randomizable");
DeclareOperator(1150, FX, "discontiguous");
DeclareOperator(1150, FX, "multifile");
DeclareOperator(1150, FX, "public");
DeclareOperator(1150, FX, "external");
DeclareOperator(1150, FX, "shadow");
DeclareOperator(1150, FX, "higher_order");
DeclareOperator(1150, FX, "indexical");
}
#endregion
#region Input buffer
private const int InputBufferSize = 1024;
private readonly char[] inputBuffer = new char[InputBufferSize];
private int bufferptr;
private int bufferend;
#endregion
#region Token buffer
// ReSharper disable InconsistentNaming
private const int MAXTOKENLENGTH = 1024;
private const int SLACK = 64;
// ReSharper restore InconsistentNaming
private readonly char[] tokenBuffer = new char[MAXTOKENLENGTH];
private int tokenptr;
private char tokenchar;
private string TokenString
{
get
{
if (tokenptr < 2)
return "";
return new string(this.tokenBuffer, 0, this.tokenptr - 1);
}
}
private float floattoken;
private int integertoken;
private int parseerror;
#endregion
#region Tokenizer
private const int SEPARATORBIT = 128;
private const int EOFFILE = 0;
private const int NAME_TOKEN = 1;
private const int VARIABLE_TOKEN = 2;
private const int INTEGER_TOKEN = 3;
private const int FLOAT_NUMBER_TOKEN = 4;
private const int CHAR_CODE_LIST_TOKEN = 5;
private const int OPEN_TOKEN = (6 + SEPARATORBIT);
private const int OPEN_CT_TOKEN = (7 + SEPARATORBIT);
private const int CLOSE_TOKEN = (8 + SEPARATORBIT);
private const int OPEN_LIST_TOKEN = (9 + SEPARATORBIT);
private const int CLOSE_LIST_TOKEN = (10 + SEPARATORBIT);
private const int OPEN_CURLY_TOKEN = (11 + SEPARATORBIT);
private const int CLOSE_CURLY_TOKEN = (12 + SEPARATORBIT);
private const int HEAD_TAIL_SEPARATOR_TOKEN = (13 + SEPARATORBIT);
private const int COMMA_TOKEN = (14 + SEPARATORBIT);
private const int END_TOKEN = 15;
private const int TERMTYPE = 40; /* meta token */
private static bool separator_token(int X)
{
return ((X) & SEPARATORBIT) > 0;
}
private char LOOKAHEAD_CHAR
{
get
{
return ((bufferptr >= bufferend)
? lookahead_char2()
: inputBuffer[bufferptr]);
}
}
private bool open_token(char X)
{
return open_char(X);
}
private bool close_token(char X)
{
return close_char(X);
}
private bool open_list_token(char X)
{
return open_list_char(X);
}
private bool close_list_token(char X)
{
return close_list_char(X);
}
private bool open_curly_token(char X)
{
return open_curly_char(X);
}
private bool close_curly_token(char X)
{
return close_curly_char(X);
}
private bool head_tail_separator_token(char X)
{
return head_tail_separator_char(X);
}
private bool comma_token(char X)
{
return comma_char(X);
}
private bool end_token(char X)
{
return end_char(X);
}
private bool semicolon_token(char X)
{
return semicolon_char(X);
}
private bool cut_token(char X)
{
return cut_char(X);
}
/* character definitions */
/* symbols for use in inittokenizer */
private const char _PROLOGCHAR = (char) 1;
private const char _GRAPHIC_CHAR = (char) 2;
private const char _GRAPHIC_TOKEN_CHAR = (char) 4;
private const char _ALPHA_NUMERIC_CHAR = (char) 8;
private const char _HEXADECIMAL_DIGIT_CHAR = (char) 16;
private const char _SOLO_CHAR = (char) 32;
private const char _SYMBOLIC_CONTROL_CHAR = (char) 64;
private const char _LAYOUT_CHAR = (char) 128;
public static bool PROLOGCHAR(char X)
{
return ((GRAPHIC_CHAR(X)) || (ALPHA_NUMERIC_CHAR(X)) ||
(SOLO_CHAR(X)) || (LAYOUT_CHAR(X)) || (meta_char(X)));
}
public static bool GRAPHIC_CHAR(char X)
{
return ((X) == '#' || (X) == '$' || (X) == '&' ||
(X) == '*' || (X) == '+' || (X) == '-' ||
(X) == '.' || (X) == '/' || (X) == ':' ||
(X) == '<' || (X) == '=' || (X) == '>' ||
(X) == '?' || (X) == '@' || (X) == '^' ||
(X) == '~' || (extra_graphic_char(X)));
}
public static bool GRAPHIC_TOKEN_CHAR(char X)
{
return (GRAPHIC_CHAR(X) || backslash_char(X));
}
public static bool ALPHA_NUMERIC_CHAR(char X)
{
return ((alpha_char(X)) || (decimal_digit_char(X)));
}
public static bool HEXADECIMAL_DIGIT_CHAR(char X)
{
return ((X) >= '0' && (X) <= '9' ||
(X) >= 'A' && (X) <= 'F' ||
(X) >= 'a' && (X) <= 'f');
}
public static bool SOLO_CHAR(char X)
{
return ((cut_char(X)) ||
(open_char(X)) ||
(close_char(X)) ||
(comma_char(X)) ||
(semicolon_char(X)) ||
(open_list_char(X)) ||
(close_list_char(X)) ||
(open_curly_char(X)) ||
(close_curly_char(X)) ||
(head_tail_separator_char(X)) ||
(end_line_comment_char(X)) ||
(extra_solo_char(X)));
}
public static bool SYMBOLIC_CONTROL_CHAR(char X)
{
return (symbolic_alert_char(X) ||
symbolic_backspace_char(X) ||
symbolic_form_feed_char(X) ||
symbolic_new_line_char(X) ||
symbolic_carriage_return_char(X) ||
symbolic_horizontal_tab_char(X) ||
symbolic_vertical_tab_char(X));
}
public static bool LAYOUT_CHAR(char X)
{
return ((space_char(X)) ||
(new_line_char(X)) ||
(extra_layout_char(X)));
//|| X == (char)0); // Added idh to treat end of file as a layout character.
}
public static bool prologchar(char X)
{
return (chararr[X] & _PROLOGCHAR) > 0;
}
public static bool graphic_char(char X)
{
return (chararr[X] & _GRAPHIC_CHAR) > 0;
}
public static bool graphic_token_char(char X)
{
return (chararr[X] & _GRAPHIC_TOKEN_CHAR) > 0;
}
public static bool alpha_numeric_char(char X)
{
return (chararr[X] & _ALPHA_NUMERIC_CHAR) > 0;
}
public static bool alpha_char(char X)
{
return ((underscore_char(X)) || (letter_char(X)));
}
public static bool letter_char(char X)
{
return ((capital_letter_char(X)) || (small_letter_char(X)));
}
public static bool small_letter_char(char X)
{
return ((X) >= 'a' && (X) <= 'z' ||
extra_small_letter_char(X));
}
public static bool capital_letter_char(char X)
{
return ((X) >= 'A' && (X) <= 'Z' ||
extra_capital_letter_char(X));
}
public static bool decimal_digit_char(char X)
{
return ((X) >= '0' && (X) <= '9');
}
public static bool binary_digit_char(char X)
{
return ((X) >= '0' && (X) <= '1');
}
public static bool octal_digit_char(char X)
{
return ((X) >= '0' && (X) <= '7');
}
public static bool hexadecimal_digit_char(char X)
{
return (chararr[X] & _HEXADECIMAL_DIGIT_CHAR) > 0;
}
public static bool underscore_char(char X)
{
return ((X) == '_');
}
public static bool solo_char(char X)
{
return (chararr[X] & _SOLO_CHAR) > 0;
}
public static bool cut_char(char X)
{
return ((X) == '!');
}
public static bool open_char(char X)
{
return ((X) == '(');
}
public static bool close_char(char X)
{
return ((X) == ')');
}
public static bool comma_char(char X)
{
return ((X) == ',');
}
public static bool semicolon_char(char X)
{
return ((X) == ';');
}
public static bool open_list_char(char X)
{
return ((X) == '[');
}
public static bool close_list_char(char X)
{
return ((X) == ']');
}
public static bool open_curly_char(char X)
{
return ((X) == '{');
}
public static bool close_curly_char(char X)
{
return ((X) == '}');
}
public static bool head_tail_separator_char(char X)
{
return ((X) == '|');
}
public static bool end_line_comment_char(char X)
{
return ((X) == '%');
}
public static bool layout_char(char X)
{
return (chararr[X] & _LAYOUT_CHAR) > 0;
}
public static bool space_char(char X)
{
return ((X) == ' ');
}
public static bool new_line_char(char X)
{
return ((X) == '\n'); /* implementation dependent */
}
public static bool meta_char(char X)
{
return ((backslash_char(X)) ||
(single_quote_char(X)) ||
(double_quote_char(X)) ||
(back_quote_char(X)));
}
public static bool backslash_char(char X)
{
return ((X) == '\\');
}
public static bool single_quote_char(char X)
{
return ((X) == '\'');
}
public static bool double_quote_char(char X)
{
return ((X) == '"');
}
public static bool back_quote_char(char X)
{
return ((X) == '`');
}
public static bool comment_1_char(char X)
{
return ((X) == '/');
}
public static bool comment_2_char(char X)
{
return ((X) == '*');
}
public static bool end_char(char X)
{
return ((X) == '.');
}
public static bool symbolic_alert_char(char X)
{
return ((X) == 'a');
}
public static bool symbolic_backspace_char(char X)
{
return ((X) == 'b');
}
public static bool symbolic_form_feed_char(char X)
{
return ((X) == 'f');
}
public static bool symbolic_new_line_char(char X)
{
return ((X) == 'n');
}
public static bool symbolic_carriage_return_char(char X)
{
return ((X) == 'r');
}
public static bool symbolic_horizontal_tab_char(char X)
{
return ((X) == 't');
}
public static bool symbolic_vertical_tab_char(char X)
{
return ((X) == 'v');
}
public static bool symbolic_hexadecimal_char(char X)
{
return ((X) == 'x');
}
public static bool symbolic_control_char(char X)
{
return (chararr[X] & _SYMBOLIC_CONTROL_CHAR) > 0;
}
public static bool positive_sign_char(char X)
{
return ((X) == '+');
}
public static bool negative_sign_char(char X)
{
return ((X) == '-');
}
public static bool sign_char(char X)
{
return (positive_sign_char(X) || negative_sign_char(X));
}
public static bool decimal_point_char(char X)
{
return ((X) == '.');
}
public static bool exponent_char(char X)
{
return ((X) == 'e' || (X) == 'E');
}
public static bool variable_indicator_char(char X)
{
return underscore_char(X);
}
/* error flags */
private const int ERR_NOERROR = 0;
//private const int ERR_MISSING_QUOTE = 1;
//private const int ERR_TOKEN_TOO_LONG = 2;
//private const int ERR_UNEXPECTED_EOF = 3;
//private const int ERR_BACK_QUOTED_STRING = 4;
//private const int ERR_NONDET = 5;
//private const int ERR_INCOMPLETE_REDUCTION = 6;
#if UnusedParserStuff
private static bool is_latin1_upper(char X)
{
return (((X) >= 192) && ((X) <= 214) ||
((X) >= 216) && ((X) <= 222));
}
private static bool is_latin1_lower(char X)
{
return (((X) >= 223) && ((X) <= 246) ||
((X) >= 248) && ((X) <= 255));
}
#endif
private static bool extra_graphic_char(char X)
{
return false;
}
private static bool extra_small_letter_char(char X)
{
return false; /* is_latin1_lower(X) */
}
private static bool extra_capital_letter_char(char X)
{
return false; /* is_latin1_upper(X) */
}
private static bool extra_solo_char(char X)
{
return false;
}
private static bool extra_layout_char(char X)
{
return ((carriage_return_char(X)) ||
(tab_char(X)) ||
(formfeed_char(X)) ||
(vertab_char(X)));
}
private static bool carriage_return_char(char X)
{
return ((X) == '\r'); /* ascii */
}
private static bool tab_char(char X)
{
return ((X) == '\t'); /* ascii */
}
private static bool formfeed_char(char X)
{
return ((X) == 12); /* ascii */
}
private static bool vertab_char(char X)
{
return ((X) == 11); /* ascii */
}
private static readonly char[] chararr = new char[256];
private static readonly char[] charconv = new char[256];
private void CHAR_CONVERSION()
{
tokenchar = charconv[tokenchar];
}
private void RESETTOKEN()
{
tokenptr = 0;
}
private void ADDTOKENCHAR(char c)
{
if (tokenptr < MAXTOKENLENGTH)
{
tokenBuffer[tokenptr++] = (c);
}
else
throw new SyntaxErrorException(this.TokenString, "Token too long", inputReader);
//seterr(ERR_TOKEN_TOO_LONG);
}
private int TOKENLENGTH
{
get { return tokenptr; }
}
/* return next char and skip it ; update line count */
private char SKIPCHAR()
{
if (new_line_char(inputBuffer[bufferptr]))
linenumber++;
return inputBuffer[bufferptr++];
}
private static void InitTokenizer()
{
for (var i = (char) 0; i <= (char) 255; i++)
{
chararr[i] = (char) 0;
if (PROLOGCHAR(i)) chararr[i] |= _PROLOGCHAR;
if (GRAPHIC_CHAR(i)) chararr[i] |= _GRAPHIC_CHAR;
if (GRAPHIC_TOKEN_CHAR(i)) chararr[i] |= _GRAPHIC_TOKEN_CHAR;
if (ALPHA_NUMERIC_CHAR(i)) chararr[i] |= _ALPHA_NUMERIC_CHAR;
if (HEXADECIMAL_DIGIT_CHAR(i)) chararr[i] |= _HEXADECIMAL_DIGIT_CHAR;
if (SOLO_CHAR(i)) chararr[i] |= _SOLO_CHAR;
if (SYMBOLIC_CONTROL_CHAR(i)) chararr[i] |= _SYMBOLIC_CONTROL_CHAR;
if (LAYOUT_CHAR(i)) chararr[i] |= _LAYOUT_CHAR;
//printf("");
}
for (var i = (char) 0; i <= (char) 255; i++)
{
charconv[i] = i;
}
}
private char lookahead_char2()
/* return current char and refill buffer is empty */
{
if (bufferptr >= bufferend)
{
int count = inputReader.Read(inputBuffer, SLACK, InputBufferSize - SLACK);
// fileread(&(inputbuffer[SLACK]), INPUTBUFFERSIZE);
if (count == 0)
{
/* end-of-file ; return false */
count++;
inputBuffer[SLACK] = (char) 0;
}
bufferend = SLACK + count;
bufferptr = SLACK;
}
return inputBuffer[bufferptr];
}
private void returnchar(char c)
/* return char to buffer */
/* SLACK is used in case the buffer would have been refilled */
{
if (new_line_char(c)) linenumber--;
inputBuffer[--bufferptr] = c;
}
private void single_line_comment()
/*
* single line comment (* 6.4.1 *)
* = end line comment char (* 6.5.3 *),
* comment txt (* 6.4.1 *),
* new line char (* 6.5.4 *) ;
*/
{
/* end_line_comment_char(LOOKAHEAD_CHAR) is true */
SKIPCHAR();
while (prologchar(LOOKAHEAD_CHAR) && !new_line_char(LOOKAHEAD_CHAR))
SKIPCHAR();
SKIPCHAR();
}
private bool bracketed_comment()
/*
* bracketed comment (* 6.4.1 *)
* = comment open (* 6.4.1 *),
* comment text (* 6.4.1 *),
* comment close (* 6.4.1 *) ;
* comment open (* 6.4.1 *)
* = comment 1 char (* 6.4.1 *),
* comment 2 char (* 6.4.1 *) ;
* comment close (* 6.4.1 *)
* = comment 2 char (* 6.4.1 *),
* comment 1 char (* 6.4.1 *) ;
* comment text (* 6.4.1 *)
* = { char (* 6.5 *) } ;
*/
{
if (comment_1_char(LOOKAHEAD_CHAR))
{
char c = SKIPCHAR();
if (comment_2_char(LOOKAHEAD_CHAR))
{
SKIPCHAR();
do
{
while (prologchar(LOOKAHEAD_CHAR) && !comment_2_char(LOOKAHEAD_CHAR))
SKIPCHAR();
SKIPCHAR();
} while (prologchar(LOOKAHEAD_CHAR) && !comment_1_char(LOOKAHEAD_CHAR));
SKIPCHAR();
return true;
}
else
{
returnchar(c);
return false;
}
}
else
return false;
}
private bool char_code_list_token()
/*
* char code list token (* 6.4.6 *)
* = double quote char (* 6.5.5 *),
* { double quoted item } (* 6.5.6 *),
* double quote char (* 6.5.5 *) ;
*/
{
/* double_quote_token(LOOKAHEAD_CHAR) is true */
SKIPCHAR();
RESETTOKEN();
while (get_double_quoted_item())
{
}
if (double_quote_char(LOOKAHEAD_CHAR))
{
SKIPCHAR();
ADDTOKENCHAR((char) 0); /* terminator */
return true;
}
else
return false;
}
private int number_token()
/*
* float number token (* 6.4.5 *)
* = integer constant (* 6.4.4 *),
* fraction (* 6.4.5 *),
* [ exponent (* 6.4.5 *) ] ;
* fraction (* 6.4.5 *)
* = decimal point char (* 6.4.5 *),
* decimal digit char (* 6.4.5 *),
* { decimal digit char (* 6.5.2 *) ;
* exponent (* 6.4.5 *)
* = exponent char (* 6.4.5 *),
* sign (* 6.4.5 *),
* integer constant (* 6.4.4 *) ;
* sign (* 6.4.5 *)
* = negative sign char (* 6.4.5 *)
* | [ positive sign char (* 6.4.5 *) ] ;
* integer token (* 6.4.4 *)
* = integer constant (* 6.4.4 *)
* | character code constant (* 6.4.4 *)
* | binary constant (* 6.4.4 *)
* | octal constant (* 6.4.4 *)
* | hexadecimal constant (* 6.4.4 *) ;
* integer constant (* 6.4.4 *)
* = decimal digit char (* 6.4.4 *),
* { decimal digit char (* 6.4.4 *) } ;
* character code constant (* 6.4.4 *)
* = "0", single quote char (* 6.5.5 *),
* single quoted char (* 6.4.2.1 *) ;
*/
{
RESETTOKEN();
ADDTOKENCHAR(SKIPCHAR());
while (decimal_digit_char(LOOKAHEAD_CHAR))
ADDTOKENCHAR(SKIPCHAR());
if (decimal_point_char(LOOKAHEAD_CHAR))
{
SKIPCHAR();
if (decimal_digit_char(LOOKAHEAD_CHAR))
{
ADDTOKENCHAR('.');
ADDTOKENCHAR(SKIPCHAR());
while (decimal_digit_char(LOOKAHEAD_CHAR))
ADDTOKENCHAR(SKIPCHAR());
if (exponent_char(LOOKAHEAD_CHAR))
{
ADDTOKENCHAR(SKIPCHAR());
if (sign_char(LOOKAHEAD_CHAR))
ADDTOKENCHAR(SKIPCHAR());
if (decimal_digit_char(LOOKAHEAD_CHAR))
{
ADDTOKENCHAR(SKIPCHAR());
while (decimal_digit_char(LOOKAHEAD_CHAR))
ADDTOKENCHAR(SKIPCHAR());
ADDTOKENCHAR((char) 0); /* terminator */
floattoken = float.Parse(this.TokenString);
return FLOAT_NUMBER_TOKEN;
}
else
return 0;
}
else
{
ADDTOKENCHAR((char) 0); /* terminator */
floattoken = float.Parse(this.TokenString);
return FLOAT_NUMBER_TOKEN;
}
}
else
{
returnchar('.');
ADDTOKENCHAR((char) 0); /* terminator */
integertoken = int.Parse(this.TokenString);
return INTEGER_TOKEN;
}
}
else
{
/* up to here we have read an integer */
if (tokenBuffer[0] == '0' && TOKENLENGTH == 1)
{
char c = LOOKAHEAD_CHAR;
if (c == 'x' &&
(integertoken = hexadecimal_constant()) != -1)
return INTEGER_TOKEN;
if (c == 'o' &&
(integertoken = octal_constant()) != -1)
return INTEGER_TOKEN;
if (c == 'b' &&
(integertoken = binary_constant()) != -1)
return INTEGER_TOKEN;
if (single_quote_char(c))
{
SKIPCHAR();
if (get_single_quoted_char())
{
integertoken = tokenchar;
return INTEGER_TOKEN;
}
else
return 0;
}
integertoken = 0; /* read number 0 */
return INTEGER_TOKEN;
}
else
{
ADDTOKENCHAR((char) 0); /* terminator */
integertoken = int.Parse(this.TokenString);
return INTEGER_TOKEN;
}
}
}
private int hexadecimal_constant()
/*
* hexadecimal constant (* 6.4.4 *)
* = hexadecimal constant indicator (* 6.4.4 *),
* hexadecimal digit char (* 6.5.2 *),
* { hexadecimal digit char (* 6.5.2 *) } ;
*
* hexadecimal constant indicator (* 6.4.4 *)
* = "0x" ; ---> 0 already read by caller
*/
{
int n = 0;
/* LOOKAHEAD == x is true */
SKIPCHAR();
if (hexadecimal_digit_char(LOOKAHEAD_CHAR))
{
char c;
while (hexadecimal_digit_char(c = LOOKAHEAD_CHAR))
{
if (decimal_digit_char(c))
n = n*16 + SKIPCHAR() - '0';
else if (capital_letter_char(c))
n = n*16 + SKIPCHAR() - 'A' + 10;
else
n = n*16 + SKIPCHAR() - 'a' + 10;
}
return n;
}
else
{
returnchar('x');
return -1;
}
}
private int octal_constant()
/*
* octal constant (* 6.4.4 *)
* = octal constant indicator (* 6.4.4 *),
* octal digit char (* 6.5.2 *),
* { octal digit char (* 6.5.2 *) } ;
*
* octal constant indicator (* 6.4.4 *)
* = "0o" ; ---> 0 already read by caller
*/
{
int n = 0;
/* LOOKAHEAD == o is true */
SKIPCHAR();
if (octal_digit_char(LOOKAHEAD_CHAR))
{
while (octal_digit_char(LOOKAHEAD_CHAR))
{
n = n*8 + SKIPCHAR() - '0';
}
return n;
}
else
{
returnchar('o');
return -1;
}
}
private int binary_constant()
/*
* binary constant (* 6.4.4 *)
* = binary constant indicator (* 6.4.4 *),
* binary digit char (* 6.5.2 *),
* { binary digit char (* 6.5.2 *) } ;
*
* binary constant indicator (* 6.4.4 *)
* = "0b" ; ---> 0 already read by caller
*/
{
int n = 0;
/* LOOKAHEAD == b is true */
SKIPCHAR();
if (binary_digit_char(LOOKAHEAD_CHAR))
{
while (binary_digit_char(LOOKAHEAD_CHAR))
{
n = n*2 + SKIPCHAR() - '0';
}
return n;
}
else
{
returnchar('b');
return -1;
}
}
private int variable_token()
/*
* variable token (* 6.4.3 *)
* = anonymous variable (* 6.4.3 *)
* | named variable (* 6.4.3 *)
* anonymous variable (* 6.4.3 *)
* = variable indicator char (* 6.4.3 *)
* named variable (* 6.4.3 *)
* = variable indicator char (* 6.4.3 *),
* alpha numeric char (* 6.5.2 *),
* { alpha numeric char (* 6.5.2 *) }
* | capital letter char (* 6.5.2 *),
* { alpha numeric char (* 6.5.2 *) } ;
*/
{
/* variable_indicator_char(LOOKAHEAD_CHAR) ||
capital_letter_char(LOOKAHEAD_CHAR) is true */
RESETTOKEN();
ADDTOKENCHAR(SKIPCHAR());
while (alpha_numeric_char(LOOKAHEAD_CHAR))
ADDTOKENCHAR(SKIPCHAR());
ADDTOKENCHAR((char) 0); /* terminator */
return VARIABLE_TOKEN;
}
private bool get_meta_escape_sequence()
/*
* meta escape sequence (* 6.4.2.1 *)
* = backslash char (* 6.5.5 *),
* meta char (* 6.5.5 *)
*/
{
if (backslash_char(LOOKAHEAD_CHAR))
{
char c = SKIPCHAR();
if (meta_char(LOOKAHEAD_CHAR))
{
tokenchar = SKIPCHAR();
return true;
}
else
{
returnchar(c);
return false;
}
}
else
return false;
}
private bool get_control_escape_sequence()
/*
* control escape sequence (* 6.4.2.1 *)
* = backslash char (* 6.5.5 *),
* symbolic control char (* 6.4.2.1 *)
* symbolic control char (* 6.4.2.1 *)
* = symbolic alert char (* 6.4.2.1 *) "a"
* = symbolic vertical tab char (* 6.4.2.1 *) "v"
* = symbolic horizontal tab char (* 6.4.2.1 *) "t"
* = symbolic backspace char (* 6.4.2.1 *) "b"
* = symbolic form feed char (* 6.4.2.1 *) "f"
* = symbolic new line char (* 6.4.2.1 *) "n"
* = symbolic carriage return char (* 6.4.2.1 *) "r"
*/
{
if (backslash_char(LOOKAHEAD_CHAR))
{
char c = SKIPCHAR();
if (symbolic_control_char(LOOKAHEAD_CHAR))
{
switch (SKIPCHAR())
{
case 'a':
tokenchar = (char) 7;
break; /* alert char, bell */
case 'b':
tokenchar = (char) 8;
break; /* backspace */
case 'f':
tokenchar = (char) 12;
break; /* formfeed */
case 'n':
tokenchar = (char) 10;
break; /* newline */
case 'r':
tokenchar = (char) 13;
break; /* carriage return */
case 't':
tokenchar = (char) 9;
break; /* horizontal tab */
case 'v':
tokenchar = (char) 11;
break; /* vertical tab */
}
return true;
}
else
{
returnchar(c);
return false;
}
}
else
return false;
}
private bool get_octal_escape_sequence()
/*
* octal escape sequence (* 6.4.2.1 *)
* = backslash char (* 6.5.5 *),
* octal digit char (* 6.5.2 *),
* { octal digit char (* 6.5.2 *) },
* backslash char (* 6.5.5 *) ;
*/
{
if (backslash_char(LOOKAHEAD_CHAR))
{
char c = SKIPCHAR();
if (octal_digit_char(LOOKAHEAD_CHAR))
{
int n = SKIPCHAR() - '0';
while (octal_digit_char(LOOKAHEAD_CHAR))
{
n = n*8 + SKIPCHAR() - '0';
}
if (backslash_char(LOOKAHEAD_CHAR))
{
SKIPCHAR();
tokenchar = (char) n;
return true;
}
else
{
SyntaxError("Error in octal constant");
return false;
}
}
else
{
returnchar(c);
return false;
}
}
else
return false;
}
private bool get_hexadecimal_escape_sequence()
/*
* hexadecimal escape sequence (* 6.4.2.1 *)
* = backslash char (* 6.5.5 *),
* symbolic hexadecimal char (* 6.4.2.1 *),
* hexadecimal digit char (* 6.5.2 *),
* { hexadecimal digit char (* 6.5.2 *) },
* backslash char (* 6.5.5 *) ;
*/
{
if (backslash_char(LOOKAHEAD_CHAR))
{
char c = SKIPCHAR();
if (symbolic_hexadecimal_char(LOOKAHEAD_CHAR))
{
char lac;
int n = 0;
SKIPCHAR();
while (hexadecimal_digit_char(lac = LOOKAHEAD_CHAR))
{
if (decimal_digit_char(lac))
n = n*16 + SKIPCHAR() - '0';
else if (capital_letter_char(lac))
n = n*16 + SKIPCHAR() - 'A' + 10;
else
n = n*16 + SKIPCHAR() - 'a' + 10;
}
if (backslash_char(lac))
{
tokenchar = (char) n;
SKIPCHAR();
return true;
}
else
{
SyntaxError("Error in hexidecimal constant");
return false;
}
}
else
{
returnchar(c);
return false;
}
}
else
return false;
}
private bool get_non_quote_char()
/*
* non quote char (* 6.4.2.1 *)
* = graphic char (* 6.5.1 *)
* | alpha numeric char (* 6.5.2 *)
* | solo char (* 6.5.3 *)
* | space char (* 6.5.4 *)
* | meta escape sequence (* 6.4.2.1 *)
* | control escape sequence (* 6.4.2.1 *)
* | octal escape sequence (* 6.4.2.1 *)
* | hexadecimal escape sequence (* 6.4.2.1 *)
*/
{
if (graphic_char(LOOKAHEAD_CHAR) ||
alpha_numeric_char(LOOKAHEAD_CHAR) ||
solo_char(LOOKAHEAD_CHAR) ||
space_char(LOOKAHEAD_CHAR))
{
tokenchar = SKIPCHAR();
return true;
}
else
{
if (get_meta_escape_sequence()) return true;
if (get_control_escape_sequence()) return true;
if (get_octal_escape_sequence()) return true;
if (get_hexadecimal_escape_sequence()) return true;
return false;
}
}
private bool get_single_quoted_char()
/*
* single quoted char (* 6.4.2.1 *)
* = non quote char (* 6.4.2.1 *)
* | single quote char (* 6.5.5 *),
* single quote char (* 6.5.5 *)
* | double quote char (* 6.5.5 *)
* | back quote char (* 6.5.5 *) ;
*/
{
if (single_quote_char(LOOKAHEAD_CHAR))
{
char c = SKIPCHAR();
if (!single_quote_char(LOOKAHEAD_CHAR))
{
returnchar(c);
return false;
}
else
{
tokenchar = SKIPCHAR();
return true;
}
}
if (double_quote_char(LOOKAHEAD_CHAR))
{
tokenchar = SKIPCHAR();
return true;
}
if (back_quote_char(LOOKAHEAD_CHAR))
{
tokenchar = SKIPCHAR();
return true;
}
if (get_non_quote_char())
{
CHAR_CONVERSION();
return true;
}
return false;
}
private bool get_double_quoted_char()
/*
* double quoted char (* 6.4.2.1 *)
* = non quote char (* 6.4.2.1 *)
* | single quote char (* 6.5.5 *)
* | double quote char (* 6.5.5 *),
* double quote char (* 6.5.5 *)
* | back quote char (* 6.5.5 *) ;
*/
{
if (double_quote_char(LOOKAHEAD_CHAR))
{
char c = SKIPCHAR();
if (!double_quote_char(LOOKAHEAD_CHAR))
{
returnchar(c);
return false;
}
else
{
tokenchar = SKIPCHAR();
return true;
}
}
if (single_quote_char(LOOKAHEAD_CHAR))
{
tokenchar = SKIPCHAR();
return true;
}
if (back_quote_char(LOOKAHEAD_CHAR))
{
tokenchar = SKIPCHAR();
return true;
}
if (get_non_quote_char())
{
CHAR_CONVERSION();
return true;
}
return false;
}
private bool get_back_quoted_char()
/*
* back quoted char (* 6.4.2.1 *)
* = non quote char (* 6.4.2.1 *)
* | single quote char (* 6.5.5 *)
* | double quote char (* 6.5.5 *)
* | back quote char (* 6.5.5 *),
* back quote char (* 6.5.5 *) ;
*/
{
if (back_quote_char(LOOKAHEAD_CHAR))
{
char c = SKIPCHAR();
if (!back_quote_char(LOOKAHEAD_CHAR))
{
returnchar(c);
return false;
}
else
{
tokenchar = SKIPCHAR();
return true;
}
}
if (single_quote_char(LOOKAHEAD_CHAR))
{
tokenchar = SKIPCHAR();
return true;
}
if (single_quote_char(LOOKAHEAD_CHAR))
{
tokenchar = SKIPCHAR();
return true;
}
if (single_quote_char(LOOKAHEAD_CHAR))
{
tokenchar = SKIPCHAR();
return true;
}
if (get_non_quote_char())
{
CHAR_CONVERSION();
return true;
}
return false;
}
private bool get_single_quoted_item()
/*
* single quoted item (* 6.4.2 *)
* = single quoted char (* 6.4.2.1 *)
* | continuation escape sequence (* 6.4.2.1 *) ;
* continuation escape sequence (* 6.4.2.1 *)
* = backslash char (* 6.5.5 *),
* new line char (* 6.5.4 *);
*/
{
if (backslash_char(LOOKAHEAD_CHAR))
{
char c = SKIPCHAR();
if (new_line_char(LOOKAHEAD_CHAR))
{
SKIPCHAR();
return true;
}
else
returnchar(c);
}
if (get_single_quoted_char())
{
ADDTOKENCHAR(tokenchar);
return true;
}
else
return false;
}
private bool get_double_quoted_item()
/*
* double quoted item (*6.4.6 *)
* = double quoted char (* 6.4.2.1 *)
* | continuation escape sequence (* 6.4.2 *)
*/
{
if (backslash_char(LOOKAHEAD_CHAR))
{
char c = SKIPCHAR();
if (new_line_char(LOOKAHEAD_CHAR))
{
SKIPCHAR();
return true;
}
else
returnchar(c);
}
if (get_double_quoted_char())
{
ADDTOKENCHAR(tokenchar);
return true;
}
else
return false;
}
private bool get_back_quoted_item()
/*
* back quoted item (*6.4.6 *)
* = back quoted char (* 6.4.2.1 *)
* | continuation escape sequence (* 6.4.2 *)
*/
{
if (backslash_char(LOOKAHEAD_CHAR))
{
char c = SKIPCHAR();
if (new_line_char(LOOKAHEAD_CHAR))
{
SKIPCHAR();
ADDTOKENCHAR((char) 0);
return true;
}
else
returnchar(c);
}
if (get_back_quoted_char())
{
return true;
}
else
return false;
}
private bool get_back_quoted_string()
/*
* back quoted string (* 6.4.2 *)
* = back quote char (* 6.5.5 *),
* { back quoted item (* 6.4.2 *) },
* back quote char (* 6.5.5 *)
*/
{
if (back_quote_char(LOOKAHEAD_CHAR))
{
SKIPCHAR();
while (get_back_quoted_item())
{
}
if (back_quote_char(LOOKAHEAD_CHAR))
{
SKIPCHAR();
ADDTOKENCHAR(tokenchar);
return true;
}
else
{
//seterr(ERR_MISSING_QUOTE);
throw new SyntaxErrorException(this.TokenString, "String is missing quote", inputReader);
//return false;
}
}
else
return false;
}
private bool get_name_token()
/*
* name token (* 6.4.2 *)
* = identifier token (* 6.4.2 *)
* | graphic token (* 6.4.2 *)
* | quoted token (* 6.4.2 *)
* | semicolon token (* 6.4.2 *)
* | cut token (* 6.4.2 *)
* identifier token (* 6.4.2 *)
* = small letter char (* 6.5.2 *),
* { alpha numeric char (* 6.5.2 *) } ;
* graphic token (* 6.4.2 *)
* = graphic token char (* 6.4.2 *)
* { graphic token char (* 6.4.2 *) } ;
* quoted token (* 6.4.2 *)
* = single quote char (* 6.5.5 *),
* { single quoted item (* 6.4.2 *) },
* single quote char (* 6.5.5 *)
*/
{
char c = LOOKAHEAD_CHAR;
RESETTOKEN();
if (small_letter_char(c))
{
ADDTOKENCHAR(SKIPCHAR());
while (alpha_numeric_char(LOOKAHEAD_CHAR))
ADDTOKENCHAR(SKIPCHAR());
ADDTOKENCHAR((char) 0); /* term */
return true;
}
if (graphic_token_char(c))
{
ADDTOKENCHAR(SKIPCHAR());
while (graphic_token_char(LOOKAHEAD_CHAR))
ADDTOKENCHAR(SKIPCHAR());
ADDTOKENCHAR((char) 0); /* term */
return true;
}
if (cut_token(c))
{
ADDTOKENCHAR(SKIPCHAR());
ADDTOKENCHAR((char) 0); /* term */
return true;
}
if (semicolon_token(c))
{
ADDTOKENCHAR(SKIPCHAR());
ADDTOKENCHAR((char) 0); /* term */
return true;
}
if (single_quote_char(c))
{
SKIPCHAR();
while (get_single_quoted_item())
{
}
if (single_quote_char(LOOKAHEAD_CHAR))
{
SKIPCHAR();
ADDTOKENCHAR((char) 0); /* term */
return true;
}
else
{
//seterr(ERR_MISSING_QUOTE);
throw new SyntaxErrorException(this.TokenString, "String is missing quote", inputReader);
//return false;
}
}
if (get_back_quoted_string()) throw new SyntaxErrorException(this.TokenString, "Back quoted strings not supported", inputReader);//seterr(ERR_BACK_QUOTED_STRING);
return false;
}
private int token()
/*
* token (* 6.4 *)
* = name token (* 6.4.2 *)
* | variable token (* 6.4.3 *)
* | integer token (* 6.4.4 *)
* | float token (* 6.4.5 *)
* | char code list token (* 6.4.6 *)
* | open token (* 6.4.8 *)
* | close token (* 6.4.8 *)
* | open list token (* 6.4.8 *)
* | close list token (* 6.4.8 *)
* | open curly token (* 6.4.8 *)
* | close curly token (* 6.4.8 *)
* | head tail separator token (* 6.4.8 *)
* | comma token (* 6.4.8 *)
* | end token (* 6.4.8 *)
* layout text sequence (* 6.4.1 *)
* = layout text (* 6.4.1 *),
* { layout text (* 6.4.1 *) } ;
* layout text (* 6.4.1 *)
* = layout char (* 6.5.4 *)
* | comment (* 6.4.1 *)
* comment (* 6.4.1 *)
* = single line commment (* 6.4.1 *)
* | bracketed comment (* 6.4.1 *)
*/
{
bool layout_inserted = SkipLayout();
char c = LOOKAHEAD_CHAR;
if (capital_letter_char(c) || variable_indicator_char(c))
return variable_token();
if (comma_token(c))
{
SKIPCHAR();
return COMMA_TOKEN;
}
if (close_token(c))
{
SKIPCHAR();
return CLOSE_TOKEN;
}
if (open_token(c))
{
SKIPCHAR();
return layout_inserted ? OPEN_TOKEN : OPEN_CT_TOKEN;
}
if (end_token(c))
{
SKIPCHAR();
if (layout_char(LOOKAHEAD_CHAR) || end_line_comment_char(LOOKAHEAD_CHAR)
|| LOOKAHEAD_CHAR == (char)0) // ADDED BY IDH FOR .NET COMPAT
return END_TOKEN;
else
returnchar('.');
}
if (decimal_digit_char(c)) return number_token();
if (close_list_token(c))
{
SKIPCHAR();
return CLOSE_LIST_TOKEN;
}
if (open_list_token(c))
{
SKIPCHAR();
return OPEN_LIST_TOKEN;
}
if (head_tail_separator_token(c))
{
SKIPCHAR();
return HEAD_TAIL_SEPARATOR_TOKEN;
}
if (open_curly_token(c))
{
SKIPCHAR();
return OPEN_CURLY_TOKEN;
}
if (close_curly_token(c))
{
SKIPCHAR();
return CLOSE_CURLY_TOKEN;
}
if (double_quote_char(LOOKAHEAD_CHAR))
{
if (char_code_list_token())
return CHAR_CODE_LIST_TOKEN;
}
if (get_name_token())
return NAME_TOKEN;
if (LOOKAHEAD_CHAR == (char) 0)
{
SKIPCHAR();
return EOFFILE;
}
return 0;
}
///
/// Skip over whitespace and comments.
///
public bool SkipLayout()
{
bool layout_inserted = false;
bool more_layout = true;
do
{
if (layout_char(LOOKAHEAD_CHAR))
{
SKIPCHAR();
layout_inserted = true;
}
else if (end_line_comment_char(LOOKAHEAD_CHAR))
{
single_line_comment();
layout_inserted = true;
}
else if (comment_1_char(LOOKAHEAD_CHAR))
{
if (bracketed_comment())
layout_inserted = true;
else
more_layout = false;
}
else
more_layout = false;
} while (more_layout);
return layout_inserted;
}
#if UnusedParserStuff
private bool char_conversion(char c1, char c2)
{
charconv[c1] = c2;
return true;
}
#endif
#endregion
#region Parser
static int Specifier(string specifierName)
{
switch (specifierName)
{
case "xfx":
return XFX;
case "xfy":
return XFY;
case "xf":
return XF;
case "yf":
return YF;
case "fx":
return FX;
case "fy":
return FY;
default:
throw new ArgumentException("Invalid operator specified: " + specifierName, "specifierName");
}
}
private const ushort XFX = 0x0001;
private const ushort XFY = 0x0002;
private const ushort YFX = 0x0004;
private const ushort XF = 0x0010;
public const ushort YF = 0x0020;
public const ushort FX = 0x0040;
public const ushort FY = 0x0080;
private const ushort DELIMITER = 0x0100;
private const ushort TERM = 0x1000;
private const ushort LTERM = 0x3000;
public static bool isprefix(int X)
{
return ((X) & (FX | FY)) != 0;
}
private static int prefixbits(int X)
{
return ((X) & (FX | FY));
}
public static bool ispostfix(int X)
{
return ((X) & (XF | YF)) != 0;
}
public static bool isinfix(int X)
{
return ((X) & (XFX | XFY | YFX)) != 0;
}
public static bool isfx(int X)
{
return ((X) & FX) != 0;
}
public static bool isfy(int X)
{
return ((X) & FY) != 0;
}
public static bool isxf(int X)
{
return ((X) & XF) != 0;
}
public static bool isyf(int X)
{
return ((X) & YF) != 0;
}
public static bool isxfx(int X)
{
return ((X) & XFX) != 0;
}
public static bool isxfy(int X)
{
return ((X) & XFY) != 0;
}
public static bool isyfx(int X)
{
return ((X) & YFX) != 0;
}
private static bool isop(int X)
{
return ((X) & (XFX | XFY | YFX | XF | YF | FX | FY)) != 0;
}
private static bool isterm(int X)
{
return ((X) & TERM) != 0;
}
private static bool islterm(int X)
{
return (((X) & LTERM) == LTERM);
}
#if UnusedParserStuff
private static bool isdelimiter(int X)
{
return ((X) & DELIMITER) != 0;
}
#endif
/* parse stack */
private class StackFrame
{
public int tokentype;
public int priority;
public int specifier;
public Object term;
public StackFrame down;
}
private StackFrame pStack;
public readonly List Variables;
/* variable management ; all correctly parsed variable names are put
in a list to be used later to return the variables names to the
options of read_term/3 */
private void initvars()
/* initialize variable list */
{
Variables.Clear();
}
private void reduce(int newpri)
/*
* lterm = term, op, term ;
* f(a,b) a f b
* n n-a n n-1
* xfx
*
* lterm = lterm, op, term ;
* f(a,b) a f b
* n n n n-1
* yfx
*
* term = term, op, term ;
* f(a,b) a f b
* n n-1 n n
* xfy
*
* lterm = lterm, op ;
* f(a) a f
* n n n
* yf
*
* lterm = term, op ;
* f(a) a f
* n n-1 n
* xf
*
* term = op, term ;
* f(a) f a
* n n n
* fy
*
* lterm = op, term ;
* f(a) f a
* n n n-1
* fx
*/
{
StackFrame top1, top2, top3;
reduce:
if ((top1 = pStack) != null)
{
if ((top2 = top1.down) != null)
{
if ((top3 = top2.down) != null)
{
if (isxfx(top2.specifier))
{
if (top2.priority <= newpri &&
isterm(top3.specifier) && top3.priority < top2.priority &&
isterm(top1.specifier) && top1.priority < top2.priority)
{
top2.term = new Structure((Symbol) top2.term, top3.term, top1.term);
top2.down = top3.down;
//BFREE(top3);
//BFREE(top1);
pStack = top2;
pStack.specifier = LTERM;
pStack.tokentype = TERMTYPE;
goto reduce;
}
}
else if (isyfx(top2.specifier))
{
if (top2.priority <= newpri &&
(isterm(top3.specifier) && top3.priority < top2.priority ||
islterm(top3.specifier) && top3.priority == top2.priority) &&
isterm(top1.specifier) && top1.priority < top2.priority)
{
top2.term = new Structure((Symbol) top2.term, top3.term, top1.term);
top2.down = top3.down;
//BFREE(top3);
//BFREE(top1);
pStack = top2;
pStack.specifier = LTERM;
pStack.tokentype = TERMTYPE;
goto reduce;
}
}
else if (isxfy(top2.specifier))
{
if (top2.priority < newpri &&
isterm(top3.specifier) && top3.priority < top2.priority &&
isterm(top1.specifier) && top1.priority <= top2.priority)
{
top2.term = new Structure((Symbol) top2.term, top3.term, top1.term);
top2.down = top3.down;
//BFREE(top3);
//BFREE(top1);
pStack = top2;
pStack.specifier = TERM;
pStack.tokentype = TERMTYPE;
goto reduce;
}
}
}
if (isyf(top1.specifier))
{
if (isterm(top2.specifier) && top2.priority < top1.priority ||
islterm(top2.specifier) && top2.priority == top1.priority)
{
top1.term = new Structure((Symbol) top1.term, top2.term);
top1.down = top2.down;
//BFREE(top2);
pStack.specifier = LTERM;
pStack.tokentype = TERMTYPE;
goto reduce;
}
}
else if (isxf(top1.specifier))
{
if (isterm(top2.specifier) && top2.priority < top1.priority)
{
top1.term = new Structure((Symbol) top1.term, top2.term);
top1.down = top2.down;
//BFREE(top2);
pStack.specifier = LTERM;
pStack.tokentype = TERMTYPE;
goto reduce;
}
}
else if (isfy(top2.specifier))
{
if (top2.priority < newpri &&
isterm(top1.specifier) && top1.priority <= top2.priority)
{
top2.term = new Structure((Symbol) top2.term, top1.term);
//BFREE(top1);
pStack = top2;
pStack.specifier = TERM;
pStack.tokentype = TERMTYPE;
goto reduce;
}
}
else if (isfx(top2.specifier))
{
if (top2.priority <= newpri &&
isterm(top1.specifier) && top1.priority < top2.priority)
{
top2.term = new Structure((Symbol) top2.term, top1.term);
//BFREE(top1);
pStack = top2;
pStack.specifier = LTERM;
pStack.tokentype = TERMTYPE;
goto reduce;
}
}
else if (top2.term == Symbol.DollarSign && Structure.IsFunctor(top1.term, Symbol.Text, 1))
{
var arg = ((Structure)top1.term).Arguments[0];
var str = arg as string;
if (str == null)
throw new SyntaxErrorException(arg, "Invalid $- expression; should be a string.");
top2.term = Prolog.StringToWordList(str, true, Variables);
//BFREE(top1);
pStack = top2;
pStack.specifier = LTERM;
pStack.tokentype = TERMTYPE;
goto reduce;
}
// Kluge to handle Twig's $ operator but still allow legacy code to redefine it.
else if (top2.term==Symbol.DollarSign && (top1.term is Symbol || top1.term is string))
{
var name = top1.term as string;
top2.term = name!=null?ResolveNamedString(name): ResolveNamedValue((Symbol)top1.term);
//BFREE(top1);
pStack = top2;
pStack.specifier = LTERM;
pStack.tokentype = TERMTYPE;
goto reduce;
}
}
}
}
static private object ResolveNamedString(string name)
{
var result =
GameObject.Find(name)
?? (object)GameObject.Find(char.ToUpper(name[0])+name.Substring(1))
?? TypeUtils.FindType(name);
if (result == null)
{
throw new SyntaxErrorException(name, "Unknown global constant name: " + name);
}
return result;
}
static object ResolveNamedValue(Symbol nameSymbol)
{
if (nameSymbol == Symbol.Global)
return KnowledgeBase.Global;
return Indexical.Find(nameSymbol) ?? ResolveNamedString(nameSymbol.Name);
}
private void shift(int tok, Object tterm, int pri, int spec)
{
pStack = new StackFrame
{
tokentype = tok,
term = tterm,
priority = pri,
specifier = spec,
down = pStack
};
}
private void releasestack()
/* return memory used for the variable list */
{
StackFrame vlp = pStack;
while (vlp != null)
{
StackFrame vlq = vlp.down;
//BFREE(vlp);
vlp = vlq;
}
}
private void shift_char_code_list(string s)
/*
* term = char code list
*
* this is list containing the ascii values of the characters belonging
* to the string.
*/
{
// termtype listterm, secondarg;
// string p = s+strlen(s);
// secondarg = Symbol.Intern("[]");
// while (p > s) {
// listterm = maketerm(".", 2);
// __ARG(listterm,1) = makeinteger(*--p);
// __ARG(listterm,2) = secondarg;
// secondarg = listterm;
// }
//shift(TERMTYPE,secondarg,0,TERM);
shift(TERMTYPE, s, 0, TERM);
}
private void shifttoken(int tok)
/*
* term = integer ; (* 6.3.1.1 *)
* term = float number ; (* 6.3.1.1 *)
* term = - integer ; (* 6.3.1.2 *)
* term = - float number ; (* 6.3.1.2 *)
* term = atom ; (not an operator) (* 6.3.1.2 *)
* term = atom ; (an operator ) (* 6.3.1.2 *)
* atom = name ;
* atom = empty list ;
* empty list = open list, close list ;
* atom = curly brackets ;
* curly brackets = open curly, close curly ;
* term = variable
*/
{
switch (tok)
{
case NAME_TOKEN:
{
int prepri, inpri, postpri, spec;
int inpostpri, sumpri;
if (Operator(this.TokenString, out prepri, out inpri, out postpri, out spec))
{
/* an operator */
if (prepri > 0 && (inpostpri = inpri + postpri) > 0)
{
/* infix and postfix do never occur together 6.3.4.2 */
if (open_char(LOOKAHEAD_CHAR))
{
/* prefix can never be followed directly by an open char */
reduce(inpostpri);
shift(NAME_TOKEN, Symbol.Intern(this.TokenString), inpostpri,
spec & (XFX | XFY | YFX | YF | XF));
}
else
{
if (pStack != null)
{
reduce(inpostpri); /* must be done before testing the stack */
if (isterm(pStack.specifier))
{
/* can be either infix of postfix */
shift(NAME_TOKEN, Symbol.Intern(this.TokenString), inpostpri,
spec & (XFX | XFY | YFX | XF | YF));
}
else
{
/* in the beginning of an expression . must be prefix */
shift(NAME_TOKEN, Symbol.Intern(this.TokenString), prepri, prefixbits(spec));
}
}
else /* empty stack */
shift(NAME_TOKEN, Symbol.Intern(this.TokenString), prepri, spec & (FX | FY));
}
}
else
{
/* there is only one specifier with priority sumpri */
reduce(sumpri = prepri + inpri + postpri);
shift(NAME_TOKEN, Symbol.Intern(this.TokenString), sumpri, spec);
}
}
else /* not an operator */
switch (this.TokenString)
{
// GROSS KLUGE ADDED BY IAN TO DEAL WITH CONSTANTS YOU WANT FOR .NET
case "null":
shift(NAME_TOKEN, null, 0, TERM);
break;
case "true":
shift(NAME_TOKEN, true, 0, TERM);
break;
case "false":
shift(NAME_TOKEN, false, 0, TERM);
break;
default:
shift(NAME_TOKEN, Symbol.Intern(this.TokenString), 0, TERM);
break;
}
break;
}
case VARIABLE_TOKEN:
string name = this.TokenString;
// Look for existing variable if name doesn't start with underscore
var lv = (name[0] == '_')?null:Variables.Find(v => v.Name.Name == name);
if (lv == null)
{
// Anonymous or otherwise new variable
lv = new LogicVariable(Symbol.Intern(name));
Variables.Add(lv);
}
shift(VARIABLE_TOKEN, lv, 0, TERM);
break;
case INTEGER_TOKEN:
if (pStack != null && pStack.term != null &&
(pStack.term is Symbol) && isprefix(pStack.specifier))
{
/*
* if a is a numeric constant, f is not -
*/
string s = ((Symbol) (pStack.term)).Name;
if (s[0] == '-' && s.Length == 1)
{
//StackFrame sp = pStack;
pStack = pStack.down;
//BFREE(sp);
shift(INTEGER_TOKEN, -integertoken, 0, TERM);
break;
}
}
shift(INTEGER_TOKEN, integertoken, 0, TERM);
break;
case FLOAT_NUMBER_TOKEN:
if (pStack != null && pStack.term != null &&
(pStack.term is Symbol) && isprefix(pStack.specifier))
{
/*
* if a is a numeric constant, f is not -
*/
string s = ((Symbol) (pStack.term)).Name;
if (s[0] == '-' && s.Length == 1)
{
//StackFrame sp = pStack;
pStack = pStack.down;
//BFREE(sp);
shift(FLOAT_NUMBER_TOKEN, -floattoken, 0, TERM);
break;
}
}
shift(FLOAT_NUMBER_TOKEN, floattoken, 0, TERM);
break;
case CHAR_CODE_LIST_TOKEN:
shift_char_code_list(this.TokenString);
break;
case OPEN_TOKEN:
shift(OPEN_TOKEN, null, 1300, DELIMITER);
break;
case OPEN_CT_TOKEN:
shift(OPEN_CT_TOKEN, null, 1300, DELIMITER);
break;
case CLOSE_TOKEN:
if (!reduceterm())
if (!reducebrackets())
//seterr(ERR_NONDET);
SyntaxError("Ambiguous input");
break;
case OPEN_LIST_TOKEN:
shift(OPEN_LIST_TOKEN, null, 1300, DELIMITER);
break;
case CLOSE_LIST_TOKEN:
if (!reducelist()) SyntaxError("Parse error in list");//puts("Error in reducelist");
break;
case OPEN_CURLY_TOKEN:
shift(OPEN_CURLY_TOKEN, null, 1300, DELIMITER);
break;
case CLOSE_CURLY_TOKEN:
if (!reducecurly()) SyntaxError("Parse error in { } expression");//puts("Error in reducecurly");
break;
case HEAD_TAIL_SEPARATOR_TOKEN:
reduce(1000);
shift(HEAD_TAIL_SEPARATOR_TOKEN, null, 1000, DELIMITER);
break;
case COMMA_TOKEN:
reduce(1000);
shift(COMMA_TOKEN, Symbol.Comma, 1000, XFY);
break;
case EOFFILE:
reduce(1400);
shift(EOFFILE, Symbol.EndOfFile, 1400, DELIMITER);
break;
case END_TOKEN:
break;
}
}
public static List