I know FoxPro syntax well but I have new in C#.
I found Concordance.pdf file in leafe.com site which shows FoxPro and VB operator and fuction equivalents.
I found parser code in fyireporting.com
vfpconversion.com descibes this utility but this is not open source.
So I'h thinkig about modifying parser from fyireporting.com to parse FoxPro expressions.
Is this best method ?
Is fyireporting.com parser code best way to implement parser in C# ?
Where to find infomation about creating parser in C# ?
Here is code sample from fyireproting parser. This parser parses RDL VB expressions but I hope I can re-write it to parse FoxRpro expressions.
internal class Lexer
{
private TokenList tokens;
private CharReader reader;
internal Lexer(string expr)
: this(new StringReader(expr))
{
}
internal Lexer(TextReader source)
{
tokens = new TokenList();
reader = new CharReader(source);
}
internal TokenList Lex()
{
Token token = GetNextToken();
while(true)
{
if(token != null)
tokens.Add(token);
else
{
tokens.Add(new Token(null, reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.EOF));
return tokens;
}
token = GetNextToken();
}
}
private Token GetNextToken()
{
while(!reader.EndOfInput())
{
char ch = reader.GetNext();
if(Char.IsWhiteSpace(ch))
{
continue;
}
switch(ch)
{
case '=':
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.EQUAL);
case '+':
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.PLUS);
case '-':
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.MINUS);
case '(':
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.LPAREN);
case ')':
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.RPAREN);
case ',':
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.COMMA);
case '^':
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.EXP);
case '%':
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.MODULUS);
case '!':
if (reader.Peek() == '=')
{
reader.GetNext();
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.NOTEQUAL);
}
else
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.NOT);
case '&':
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.PLUSSTRING);
case '|':
if (reader.Peek() == '|')
{
reader.GetNext();
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.OR);
}
break;
case '>':
if (reader.Peek() == '=')
{
reader.GetNext();
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.GREATERTHANOREQUAL);
}
else
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.GREATERTHAN);
case '/':
if (reader.Peek() == '*')
{
reader.GetNext();
ReadComment();
continue;
}
else
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.FORWARDSLASH);
case '<':
if (reader.Peek() == '=')
{
reader.GetNext();
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.LESSTHANOREQUAL);
}
else if (reader.Peek() == '>')
{
reader.GetNext();
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.NOTEQUAL);
}
else
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.LESSTHAN);
case '*':
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.STAR);
case '"':
case '\'':
return ReadQuoted(ch);
default:
break;
}
if (Char.IsDigit(ch) || ch == '.')
return ReadNumber(ch);
else if (Char.IsLetter(ch) || ch == '_')
return ReadIdentifier(ch);
else
return new Token(ch.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.OTHER);
}
return null;
}
private Token ReadNumber(char ch)
{
int startLine = reader.Line;
int startCol = reader.Column;
bool bDecimal = ch == '.'? true: false;
bool bDecimalType=false;
bool bFloat=false;
char cPeek;
string number = ch.ToString();
while(!reader.EndOfInput() )
{
cPeek = reader.Peek();
if (Char.IsWhiteSpace(cPeek))
break;
if (Char.IsDigit(cPeek))
number += reader.GetNext();
else if (cPeek == 'd' || cPeek == 'D' && !bFloat)
{
reader.GetNext();
bDecimalType = true;
break;
}
else if (cPeek == 'e' || cPeek == 'E' && !bFloat)
{
number += reader.GetNext();
cPeek = reader.Peek();
if (cPeek == '-' || cPeek == '+')
{
number += reader.GetNext();
bFloat = true;
if (Char.IsDigit(reader.Peek()))
continue;
}
throw new ParserException("Invalid number constant.");
}
else if (!bDecimal && !bFloat && cPeek == '.')
{
bDecimal = true;
number += reader.GetNext();
}
else
break;
}
if (number.CompareTo(".") == 0)
throw new ParserException("'.' should be followed by a number");
TokenTypes t;
if (bDecimalType)
t = TokenTypes.NUMBER;
else if (bFloat || bDecimal)
t = TokenTypes.DOUBLE;
else
t = TokenTypes.INTEGER;
return new Token(number, startLine, startCol, reader.Line, reader.Column, t);
}
private Token ReadIdentifier(char ch)
{
int startLine = reader.Line;
int startCol = reader.Column;
char cPeek;
StringBuilder identifier = new StringBuilder(30);
identifier.Append(ch.ToString());
while(!reader.EndOfInput() )
{
cPeek = reader.Peek();
if (Char.IsLetterOrDigit(cPeek) || cPeek == '.' ||
cPeek == '!' || cPeek == '_')
identifier.Append(reader.GetNext());
else
break;
}
string key = identifier.ToString().ToLower();
if (key == "and" || key == "andalso")
return new Token(identifier.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.AND);
else if (key == "or" || key == "orelse")
return new Token(identifier.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.OR);
else if (key == "not")
return new Token(identifier.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.NOT);
else if (key == "mod")
return new Token(identifier.ToString(), reader.Line, reader.Column, reader.Line, reader.Column, TokenTypes.MODULUS);
return new Token(identifier.ToString(), startLine, startCol, reader.Line, reader.Column, TokenTypes.IDENTIFIER);
}
private Token ReadQuoted(char ch)
{
char qChar = ch;
int startLine = reader.Line;
int startCol = reader.Column;
StringBuilder quoted = new StringBuilder();
while(!reader.EndOfInput())
{
ch = reader.GetNext();
if (ch == '\\')
{
char pChar = reader.Peek();
if (pChar == qChar)
ch = reader.GetNext();
else if (pChar == 'n')
{
ch = '\n';
reader.GetNext();
}
else if (pChar == 'r')
{
ch = '\r';
reader.GetNext();
}
}
else if (ch == qChar)
return new Token(quoted.ToString(), startLine, startCol, reader.Line, reader.Column, TokenTypes.QUOTE);
quoted.Append(ch);
}
throw new ParserException("Unterminated string!");
}
private void ReadComment()
{
char ch;
while(!reader.EndOfInput())
{
ch = reader.GetNext();
if (ch == '*' && reader.Peek() == '/')
{
reader.GetNext();
return;
}
}
throw new ParserException("Unterminated comment!");
}
Andrus
|