Parser is finished (or very nearly so)!!! :-)
+ Added support for extended notation floating point numbers, as well as signed (+ and -) floats. + Finished up parsing code + Moved Err class into it's own header/source pair, since I started using it all over the place in the sniffer code. + Did my darndest to make sure I wasn't leaking memory anywhere. + Matched up error messages as best as possible with R5's error message. Some couldn't be matched, some were improved. There *are* a few things left to do. I don't think priorities are verified to be valid (0.0 <= x <= 1.0). More tests also need to be written. Things have solidified enough now that documentation is a reasonable thing to start considering as well. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@608 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
01293d6ed7
commit
390dce8da6
|
@ -10,23 +10,21 @@
|
|||
#define _sk_sniffer_parser_h_
|
||||
|
||||
#include <SupportDefs.h>
|
||||
#include <sniffer/Err.h>
|
||||
#include <sniffer/Range.h>
|
||||
#include <sniffer/Rule.h>
|
||||
#include <List.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class BString;
|
||||
|
||||
namespace Sniffer {
|
||||
|
||||
class Rule;
|
||||
class Expr;
|
||||
class Range;
|
||||
class RPattern;
|
||||
class Pattern;
|
||||
typedef std::vector<Expr*> ExprList;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// The mighty parsing function ;-)
|
||||
|
@ -38,21 +36,6 @@ status_t parse(const char *rule, Rule *result, BString *parseError = NULL);
|
|||
// Classes used internally by the parser
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class Err {
|
||||
public:
|
||||
Err(const char *msg, const ssize_t pos);
|
||||
Err(const std::string &msg, const ssize_t pos);
|
||||
Err(const Err &ref);
|
||||
Err& operator=(const Err &ref);
|
||||
const char* Msg() const;
|
||||
ssize_t Pos() const;
|
||||
|
||||
private:
|
||||
void SetMsg(const char *msg);
|
||||
char *fMsg;
|
||||
ssize_t fPos;
|
||||
};
|
||||
|
||||
class CharStream {
|
||||
public:
|
||||
CharStream(const char *string = NULL);
|
||||
|
@ -63,6 +46,7 @@ public:
|
|||
status_t InitCheck() const;
|
||||
bool IsEmpty() const;
|
||||
ssize_t Pos() const;
|
||||
const char *String() const;
|
||||
|
||||
char Get();
|
||||
void Unget();
|
||||
|
@ -102,7 +86,7 @@ public:
|
|||
virtual int32 Int() const;
|
||||
virtual double Float() const;
|
||||
ssize_t Pos() const;
|
||||
bool operator==(Token &ref);
|
||||
bool operator==(Token &ref) const;
|
||||
protected:
|
||||
TokenType fType;
|
||||
ssize_t fPos;
|
||||
|
@ -143,10 +127,16 @@ public:
|
|||
void Unset();
|
||||
status_t InitCheck() const;
|
||||
|
||||
Token* Get();
|
||||
void Unget(Token *token);
|
||||
const Token* Get();
|
||||
void Unget();
|
||||
|
||||
bool IsEmpty();
|
||||
void Read(TokenType type);
|
||||
bool CondRead(TokenType type);
|
||||
|
||||
ssize_t Pos() const;
|
||||
ssize_t EndPos() const;
|
||||
|
||||
bool IsEmpty() const;
|
||||
|
||||
private:
|
||||
void AddToken(TokenType type, ssize_t pos);
|
||||
|
@ -154,9 +144,12 @@ private:
|
|||
void AddInt(const char *str, ssize_t pos);
|
||||
void AddFloat(const char *str, ssize_t pos);
|
||||
|
||||
BList fTokenList;
|
||||
std::vector<Token*> fTokenList;
|
||||
int fPos;
|
||||
int fStrLen;
|
||||
status_t fCStatus;
|
||||
|
||||
|
||||
TokenStream(const TokenStream &ref);
|
||||
TokenStream& operator=(const TokenStream &ref);
|
||||
};
|
||||
|
@ -164,22 +157,31 @@ private:
|
|||
class Parser {
|
||||
public:
|
||||
Parser();
|
||||
~Parser();
|
||||
status_t Parse(const char *rule, Rule *result, BString *parseError = NULL);
|
||||
private:
|
||||
std::string ErrorMessage(Err *err, const char *rule);
|
||||
|
||||
// Things that get done a lot :-)
|
||||
void ThrowEndOfStreamError();
|
||||
inline void ThrowOutOfMemError(ssize_t pos);
|
||||
void ThrowUnexpectedTokenError(TokenType expected, const Token *found);
|
||||
void ThrowUnexpectedTokenError(TokenType expected1, TokenType expected2, const Token *found);
|
||||
|
||||
// Parsing functions
|
||||
void ParseRule(Rule *result);
|
||||
double ParsePriority();
|
||||
ExprList* ParseExprList();
|
||||
std::vector<Expr*>* ParseExprList();
|
||||
Expr* ParseExpr();
|
||||
Range ParseRange();
|
||||
Expr* ParsePatternList();
|
||||
Expr* ParsePatternList(Range range);
|
||||
Expr* ParseRPatternList();
|
||||
RPattern* ParseRPattern();
|
||||
Pattern* ParsePattern();
|
||||
|
||||
TokenStream stream;
|
||||
|
||||
Err *fOutOfMemErr;
|
||||
};
|
||||
|
||||
} // namespace Sniffer
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
|
||||
//#include <sniffer/Expr.h>
|
||||
#include <sniffer/Parser.h>
|
||||
//#include <sniffer/Pattern.h>
|
||||
//#include <sniffer/PatternList.h>
|
||||
//#include <sniffer/Range.h>
|
||||
//#include <sniffer/RPatternList.h>
|
||||
#include <sniffer/Pattern.h>
|
||||
#include <sniffer/PatternList.h>
|
||||
#include <sniffer/Range.h>
|
||||
#include <sniffer/RPattern.h>
|
||||
#include <sniffer/RPatternList.h>
|
||||
#include <sniffer/Rule.h>
|
||||
|
||||
#include <new.h>
|
||||
|
@ -42,62 +43,6 @@ Sniffer::parse(const char *rule, Rule *result, BString *parseError) {
|
|||
return parser.Parse(rule, result, parseError);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Err
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Err::Err(const char *msg, const ssize_t pos)
|
||||
: fMsg(NULL)
|
||||
, fPos(pos)
|
||||
{
|
||||
SetMsg(msg);
|
||||
}
|
||||
|
||||
Err::Err(const std::string &msg, const ssize_t pos)
|
||||
: fMsg(NULL)
|
||||
, fPos(pos)
|
||||
{
|
||||
SetMsg(msg.c_str());
|
||||
}
|
||||
|
||||
Err::Err(const Err &ref)
|
||||
: fMsg(NULL)
|
||||
, fPos(-1)
|
||||
{
|
||||
*this = ref;
|
||||
}
|
||||
|
||||
Err&
|
||||
Err::operator=(const Err &ref) {
|
||||
SetMsg(ref.Msg());
|
||||
return *this;
|
||||
}
|
||||
|
||||
const char*
|
||||
Err::Msg() const {
|
||||
return fMsg;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
Err::Pos() const {
|
||||
return fPos;
|
||||
}
|
||||
|
||||
void
|
||||
Err::SetMsg(const char *msg) {
|
||||
if (fMsg) {
|
||||
delete fMsg;
|
||||
fMsg = NULL;
|
||||
}
|
||||
if (msg == NULL)
|
||||
fMsg = NULL;
|
||||
else {
|
||||
fMsg = new(nothrow) char[strlen(msg)+1];
|
||||
if (fMsg)
|
||||
strcpy(fMsg, msg);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CharStream
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -154,6 +99,11 @@ CharStream::Pos() const {
|
|||
return fPos;
|
||||
}
|
||||
|
||||
const char*
|
||||
CharStream::String() const {
|
||||
return fString;
|
||||
}
|
||||
|
||||
char
|
||||
CharStream::Get() {
|
||||
if (fCStatus != B_OK)
|
||||
|
@ -217,7 +167,7 @@ Token::Pos() const {
|
|||
}
|
||||
|
||||
bool
|
||||
Token::operator==(Token &ref) {
|
||||
Token::operator==(Token &ref) const {
|
||||
// Compare types, then data if necessary
|
||||
if (Type() == ref.Type()) {
|
||||
switch (Type()) {
|
||||
|
@ -325,6 +275,8 @@ FloatToken::Float() const {
|
|||
|
||||
TokenStream::TokenStream(const char *string = NULL)
|
||||
: fCStatus(B_NO_INIT)
|
||||
, fPos(-1)
|
||||
, fStrLen(-1)
|
||||
{
|
||||
SetTo(string);
|
||||
}
|
||||
|
@ -335,10 +287,12 @@ TokenStream::~TokenStream() {
|
|||
|
||||
status_t
|
||||
TokenStream::SetTo(const char *string) {
|
||||
int q = 0;
|
||||
Unset();
|
||||
if (string) {
|
||||
fStrLen = strlen(string);
|
||||
CharStream stream(string);
|
||||
if (stream.InitCheck() != B_OK)
|
||||
if (stream.InitCheck() != B_OK)
|
||||
throw new Err("Sniffer scanner error: Unable to intialize character stream", -1);
|
||||
|
||||
typedef enum TokenStreamScannerState {
|
||||
|
@ -353,8 +307,10 @@ TokenStream::SetTo(const char *string) {
|
|||
tsssIntOrFloat,
|
||||
tsssFloat,
|
||||
tsssLonelyDecimalPoint,
|
||||
tsssLonelyMinusOrPlusSign,
|
||||
tsssPosNegInt,
|
||||
tsssLonelyMinusOrPlus,
|
||||
tsssLonelyFloatExtension,
|
||||
tsssLonelyFloatExtensionWithSign,
|
||||
tsssExtendedFloat,
|
||||
tsssUnquoted,
|
||||
tsssEscape,
|
||||
tsssEscapeX,
|
||||
|
@ -372,17 +328,19 @@ TokenStream::SetTo(const char *string) {
|
|||
char lastChar; // For two char lookahead
|
||||
char lastLastChar; // For three char lookahead
|
||||
bool keepLooping = true;
|
||||
ssize_t startPos;
|
||||
while (keepLooping) {
|
||||
ssize_t pos = stream.Pos();
|
||||
char ch = stream.Get();
|
||||
switch (state) {
|
||||
case tsssStart:
|
||||
startPos = pos;
|
||||
switch (ch) {
|
||||
case 0x3: // End-Of-Text
|
||||
if (stream.IsEmpty())
|
||||
if (stream.IsEmpty())
|
||||
keepLooping = false;
|
||||
else
|
||||
throw new Err(std::string("Sniffer scanner error: unexpected character '") + ch + "'", pos);
|
||||
else
|
||||
throw new Err(std::string("Sniffer scanner error: invalid character '") + ch + "'", pos);
|
||||
break;
|
||||
|
||||
case '\t':
|
||||
|
@ -404,7 +362,7 @@ TokenStream::SetTo(const char *string) {
|
|||
case '+':
|
||||
case '-':
|
||||
charStr = ch;
|
||||
state = tsssLonelyMinusOrPlusSign;
|
||||
state = tsssLonelyMinusOrPlus;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
|
@ -446,7 +404,7 @@ TokenStream::SetTo(const char *string) {
|
|||
case '|': AddToken(Divider, pos); break;
|
||||
|
||||
default:
|
||||
throw new Err(std::string("Sniffer scanner error: unexpected character '") + ch + "'", pos);
|
||||
throw new Err(std::string("Sniffer scanner error: invalid character '") + ch + "'", pos);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -457,7 +415,7 @@ TokenStream::SetTo(const char *string) {
|
|||
state = tsssEscape; // Handle the escape sequence
|
||||
break;
|
||||
case '\'':
|
||||
AddString(charStr.c_str(), pos);
|
||||
AddString(charStr.c_str(), startPos);
|
||||
state = tsssStart;
|
||||
break;
|
||||
case 0x3:
|
||||
|
@ -479,7 +437,7 @@ TokenStream::SetTo(const char *string) {
|
|||
state = tsssEscape; // Handle the escape sequence
|
||||
break;
|
||||
case '"':
|
||||
AddString(charStr.c_str(), pos);
|
||||
AddString(charStr.c_str(), startPos);
|
||||
state = tsssStart;
|
||||
break;
|
||||
case 0x3:
|
||||
|
@ -504,13 +462,9 @@ TokenStream::SetTo(const char *string) {
|
|||
} else if (ch == '.') {
|
||||
charStr += ch;
|
||||
state = tsssFloat;
|
||||
} else if (ch == 0x3 && stream.IsEmpty()) {
|
||||
// Terminate the number and then the loop
|
||||
AddInt(charStr.c_str(), pos);
|
||||
keepLooping = false;
|
||||
} else {
|
||||
// Terminate the number
|
||||
AddInt(charStr.c_str(), pos);
|
||||
AddInt(charStr.c_str(), startPos);
|
||||
|
||||
// Push the last char back on and try again
|
||||
stream.Unget();
|
||||
|
@ -522,35 +476,27 @@ TokenStream::SetTo(const char *string) {
|
|||
if (isHexChar(ch)) {
|
||||
lastChar = ch;
|
||||
state = tsssOneHex;
|
||||
} else if (ch == 0x3 && stream.IsEmpty())
|
||||
} else
|
||||
throw new Err(std::string("Sniffer scanner error: incomplete hex code"), pos);
|
||||
else
|
||||
throw new Err(std::string("Sniffer scanner error: unexpected character '") + ch + "'", pos);
|
||||
break;
|
||||
|
||||
case tsssOneHex:
|
||||
if (isHexChar(ch)) {
|
||||
charStr += hexToChar(lastChar, ch);
|
||||
state = tsssTwoHex;
|
||||
} else if (ch == 0x3 && stream.IsEmpty())
|
||||
throw new Err(std::string("Sniffer scanner error: incomplete hex code (the number of hex digits must be a multiple of two)"), pos);
|
||||
else
|
||||
throw new Err(std::string("Sniffer scanner error: unexpected character '") + ch + "'", pos);
|
||||
} else
|
||||
throw new Err(std::string("Sniffer pattern error: bad hex literal"), pos); // Same as R5
|
||||
break;
|
||||
|
||||
case tsssTwoHex:
|
||||
if (isHexChar(ch)) {
|
||||
lastChar = ch;
|
||||
state = tsssOneHex;
|
||||
} else if (isWhiteSpace(ch) || isPunctuation(ch)) {
|
||||
AddString(charStr.c_str(), pos);
|
||||
} else {
|
||||
AddString(charStr.c_str(), startPos);
|
||||
stream.Unget(); // So punctuation gets handled properly
|
||||
state = tsssStart;
|
||||
} else if (ch == 0x3 && stream.IsEmpty()) {
|
||||
AddString(charStr.c_str(), pos);
|
||||
keepLooping = false;
|
||||
} else
|
||||
throw new Err(std::string("Sniffer scanner error: unexpected character '") + ch + "'", pos);
|
||||
}
|
||||
break;
|
||||
|
||||
case tsssIntOrFloat:
|
||||
|
@ -559,9 +505,12 @@ TokenStream::SetTo(const char *string) {
|
|||
else if (ch == '.') {
|
||||
charStr += ch;
|
||||
state = tsssFloat;
|
||||
} else if (ch == 'e' || ch == 'E') {
|
||||
charStr += ch;
|
||||
state = tsssLonelyFloatExtension;
|
||||
} else {
|
||||
// Terminate the number
|
||||
AddInt(charStr.c_str(), pos);
|
||||
AddInt(charStr.c_str(), startPos);
|
||||
|
||||
// Push the last char back on and try again
|
||||
stream.Unget();
|
||||
|
@ -572,9 +521,12 @@ TokenStream::SetTo(const char *string) {
|
|||
case tsssFloat:
|
||||
if (isDecimalChar(ch))
|
||||
charStr += ch;
|
||||
else {
|
||||
else if (ch == 'e' || ch == 'E') {
|
||||
charStr += ch;
|
||||
state = tsssLonelyFloatExtension;
|
||||
} else {
|
||||
// Terminate the number
|
||||
AddFloat(charStr.c_str(), pos);
|
||||
AddFloat(charStr.c_str(), startPos);
|
||||
|
||||
// Push the last char back on and try again
|
||||
stream.Unget();
|
||||
|
@ -586,30 +538,47 @@ TokenStream::SetTo(const char *string) {
|
|||
if (isDecimalChar(ch)) {
|
||||
charStr += ch;
|
||||
state = tsssFloat;
|
||||
} else if (ch == 0x3 && stream.IsEmpty())
|
||||
} else
|
||||
throw new Err(std::string("Sniffer scanner error: incomplete floating point number"), pos);
|
||||
else
|
||||
throw new Err(std::string("Sniffer scanner error: unexpected character '") + ch + "'", pos);
|
||||
break;
|
||||
|
||||
case tsssLonelyMinusOrPlusSign:
|
||||
case tsssLonelyMinusOrPlus:
|
||||
if (isDecimalChar(ch)) {
|
||||
charStr += ch;
|
||||
state = tsssPosNegInt;
|
||||
} else if (ch == 0x3 && stream.IsEmpty())
|
||||
throw new Err(std::string("Sniffer scanner error: incomplete signed integer"), pos);
|
||||
else
|
||||
throw new Err(std::string("Sniffer scanner error: unexpected character '") + ch + "'", pos);
|
||||
state = tsssIntOrFloat;
|
||||
} else if (ch == '.') {
|
||||
charStr += ch;
|
||||
state = tsssLonelyDecimalPoint;
|
||||
} else
|
||||
throw new Err(std::string("Sniffer scanner error: incomplete signed number"), pos);
|
||||
break;
|
||||
|
||||
case tsssPosNegInt:
|
||||
if (isDecimalChar(ch))
|
||||
case tsssLonelyFloatExtension:
|
||||
if (ch == '+' || ch == '-') {
|
||||
charStr += ch;
|
||||
else if (ch == '.')
|
||||
throw new Err(std::string("Sniffer scanner error: negative floating point numbers are useless and thus signs (both + and -) are disallowed on floating points"), pos);
|
||||
else {
|
||||
state = tsssLonelyFloatExtensionWithSign;
|
||||
} else if (isDecimalChar(ch)) {
|
||||
charStr += ch;
|
||||
state = tsssExtendedFloat;
|
||||
} else
|
||||
throw new Err(std::string("Sniffer pattern error: incomplete extended-notation floating point number"), pos);
|
||||
break;
|
||||
|
||||
case tsssLonelyFloatExtensionWithSign:
|
||||
if (isDecimalChar(ch)) {
|
||||
charStr += ch;
|
||||
state = tsssExtendedFloat;
|
||||
} else
|
||||
throw new Err(std::string("Sniffer pattern error: incomplete extended-notation floating point number"), pos);
|
||||
break;
|
||||
|
||||
case tsssExtendedFloat:
|
||||
if (isDecimalChar(ch)) {
|
||||
charStr += ch;
|
||||
state = tsssExtendedFloat;
|
||||
} else {
|
||||
// Terminate the number
|
||||
AddInt(charStr.c_str(), pos);
|
||||
AddFloat(charStr.c_str(), startPos);
|
||||
|
||||
// Push the last char back on and try again
|
||||
stream.Unget();
|
||||
|
@ -622,13 +591,13 @@ TokenStream::SetTo(const char *string) {
|
|||
escapedState = state; // Save our state
|
||||
state = tsssEscape; // Handle the escape sequence
|
||||
} else if (isWhiteSpace(ch) || isPunctuation(ch)) {
|
||||
AddString(charStr.c_str(), pos);
|
||||
AddString(charStr.c_str(), startPos);
|
||||
stream.Unget(); // In case it's punctuation, let tsssStart handle it
|
||||
state = tsssStart;
|
||||
} else if (ch == '\'' || ch == '"') {
|
||||
throw new Err(std::string("Sniffer scanner error: illegal unquoted character '") + ch + "'", pos);
|
||||
} else if (ch == 0x3 && stream.IsEmpty()) {
|
||||
AddString(charStr.c_str(), pos);
|
||||
AddString(charStr.c_str(), startPos);
|
||||
keepLooping = false;
|
||||
} else {
|
||||
charStr += ch;
|
||||
|
@ -642,7 +611,7 @@ TokenStream::SetTo(const char *string) {
|
|||
} else {
|
||||
// Check for a true end-of-text marker
|
||||
if (ch == 0x3 && stream.IsEmpty())
|
||||
throw new Err(std::string("Sniffer scanner error: unterminated escape sequence"), pos);
|
||||
throw new Err(std::string("Sniffer scanner error: incomplete escape sequence"), pos);
|
||||
else {
|
||||
charStr += escapeChar(ch);
|
||||
state = escapedState; // Return to the state we were in before the escape
|
||||
|
@ -693,18 +662,18 @@ TokenStream::SetTo(const char *string) {
|
|||
if (isHexChar(ch)) {
|
||||
charStr += hexToChar(lastChar, ch);
|
||||
state = escapedState;
|
||||
} else if (ch == 0x3 && stream.IsEmpty())
|
||||
throw new Err(std::string("Sniffer scanner error: incomplete escaped hex code (the number of hex digits must be a multiple of two)"), pos);
|
||||
else
|
||||
throw new Err(std::string("Sniffer scanner error: unexpected character '") + ch + "'", pos);
|
||||
} else
|
||||
throw new Err(std::string("Sniffer scanner error: incomplete escaped hex code"), pos);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
if (state == tsssStart)
|
||||
if (state == tsssStart) {
|
||||
fCStatus = B_OK;
|
||||
else
|
||||
fPos = 0;
|
||||
} else {
|
||||
throw new Err("Sniffer pattern error: unterminated rule", stream.Pos());
|
||||
}
|
||||
}
|
||||
|
||||
return fCStatus;
|
||||
|
@ -712,9 +681,12 @@ TokenStream::SetTo(const char *string) {
|
|||
|
||||
void
|
||||
TokenStream::Unset() {
|
||||
while (!fTokenList.IsEmpty())
|
||||
delete (Token*)fTokenList.RemoveItem((int32)0);
|
||||
std::vector<Token*>::iterator i;
|
||||
for (i = fTokenList.begin(); i != fTokenList.end(); i++)
|
||||
delete *i;
|
||||
fTokenList.clear();
|
||||
fCStatus = B_NO_INIT;
|
||||
fStrLen = -1;
|
||||
}
|
||||
|
||||
status_t
|
||||
|
@ -722,31 +694,74 @@ TokenStream::InitCheck() const {
|
|||
return fCStatus;
|
||||
}
|
||||
|
||||
Token*
|
||||
const Token*
|
||||
TokenStream::Get() {
|
||||
return (Token*)fTokenList.RemoveItem((int32)0);
|
||||
if (fCStatus != B_OK)
|
||||
throw new Err("Sniffer parser error: TokenStream::Get() called on uninitialized TokenStream object", -1);
|
||||
if (fPos < fTokenList.size())
|
||||
return fTokenList[fPos++];
|
||||
else {
|
||||
throw new Err("Sniffer pattern error: unterminated rule", EndPos());
|
||||
// fPos++; // Increment fPos to keep Unget()s consistent
|
||||
// return NULL; // Return NULL to signal end of list
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TokenStream::Unget(Token *token) {
|
||||
fTokenList.AddItem(token, 0);
|
||||
TokenStream::Unget() {
|
||||
if (fCStatus != B_OK)
|
||||
throw new Err("Sniffer parser error: TokenStream::Unget() called on uninitialized TokenStream object", -1);
|
||||
if (fPos > 0)
|
||||
fPos--;
|
||||
else
|
||||
throw new Err("Sniffer parser error: TokenStream::Unget() called at beginning of token stream", -1);
|
||||
}
|
||||
|
||||
void
|
||||
TokenStream::Read(TokenType type) {
|
||||
const Token *t = Get();
|
||||
if (t->Type() != type) {
|
||||
throw new Err((std::string("Sniffer pattern error: expected ") + tokenTypeToString(type)
|
||||
+ ", found " + tokenTypeToString(t->Type())).c_str(), t->Pos());
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TokenStream::IsEmpty() {
|
||||
return fCStatus != B_OK || fTokenList.IsEmpty();
|
||||
TokenStream::CondRead(TokenType type) {
|
||||
const Token *t = Get();
|
||||
if (t->Type() == type) {
|
||||
return true;
|
||||
} else {
|
||||
Unget();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t
|
||||
TokenStream::Pos() const {
|
||||
return fPos < fTokenList.size() ? fTokenList[fPos]->Pos() : fStrLen;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
TokenStream::EndPos() const {
|
||||
return fStrLen;
|
||||
}
|
||||
|
||||
bool
|
||||
TokenStream::IsEmpty() const {
|
||||
return fCStatus != B_OK || fPos >= fTokenList.size();
|
||||
}
|
||||
|
||||
void
|
||||
TokenStream::AddToken(TokenType type, ssize_t pos) {
|
||||
Token *token = new Token(type, pos);
|
||||
fTokenList.AddItem(token);
|
||||
fTokenList.push_back(token);
|
||||
}
|
||||
|
||||
void
|
||||
TokenStream::AddString(const char *str, ssize_t pos) {
|
||||
Token *token = new StringToken(str, pos);
|
||||
fTokenList.AddItem(token);
|
||||
fTokenList.push_back(token);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -754,7 +769,7 @@ TokenStream::AddInt(const char *str, ssize_t pos) {
|
|||
// Convert the string to an int
|
||||
int32 value = atol(str);
|
||||
Token *token = new IntToken(value, pos);
|
||||
fTokenList.AddItem(token);
|
||||
fTokenList.push_back(token);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -762,7 +777,7 @@ TokenStream::AddFloat(const char *str, ssize_t pos) {
|
|||
// Convert the string to a float
|
||||
double value = atof(str);
|
||||
Token *token = new FloatToken(value, pos);
|
||||
fTokenList.AddItem(token);
|
||||
fTokenList.push_back(token);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -914,7 +929,13 @@ Sniffer::tokenTypeToString(TokenType type) {
|
|||
// Parser
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Parser::Parser() {
|
||||
Parser::Parser()
|
||||
: fOutOfMemErr(new(nothrow) Err("Sniffer parser error: out of memory", -1))
|
||||
{
|
||||
}
|
||||
|
||||
Parser::~Parser() {
|
||||
delete fOutOfMemErr;
|
||||
}
|
||||
|
||||
status_t
|
||||
|
@ -959,35 +980,76 @@ Parser::ParseRule(Rule *result) {
|
|||
// Priority
|
||||
double priority = ParsePriority();
|
||||
// Expression List
|
||||
// ExprList* list = ParseExprList();
|
||||
std::vector<Expr*>* list = ParseExprList();
|
||||
}
|
||||
|
||||
double
|
||||
Parser::ParsePriority() {
|
||||
Token *t = stream.Get();
|
||||
Err *err = NULL;
|
||||
double result;
|
||||
|
||||
// cout << tokenTypeToString(t->Type()) << endl;
|
||||
const Token *t = stream.Get();
|
||||
if (t->Type() == FloatingPoint || t->Type() == Integer)
|
||||
result = t->Float();
|
||||
else
|
||||
err = new Err("Sniffer pattern error: match level expected", t->Pos());
|
||||
|
||||
delete t;
|
||||
if (err)
|
||||
throw err;
|
||||
else
|
||||
return result;
|
||||
throw new Err("Sniffer pattern error: match level expected", t->Pos()); // Same as R5
|
||||
}
|
||||
|
||||
ExprList*
|
||||
std::vector<Expr*>*
|
||||
Parser::ParseExprList() {
|
||||
// Expr+
|
||||
std::vector<Expr*> *list = new(nothrow) std::vector<Expr*>;
|
||||
if (!list)
|
||||
ThrowOutOfMemError(stream.Pos());
|
||||
try {
|
||||
// Expr+
|
||||
int count = 0;
|
||||
while (true) {
|
||||
Expr* expr = ParseExpr();
|
||||
if (!expr)
|
||||
break;
|
||||
else {
|
||||
list->push_back(expr);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count == 0)
|
||||
throw new Err("Sniffer pattern error: missing expression", -1);
|
||||
} catch (...) {
|
||||
delete list;
|
||||
throw;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
Expr*
|
||||
Parser::ParseExpr() {
|
||||
// If we've run out of tokens right now, it's okay, but
|
||||
// we need to let ParseExprList() know what's up
|
||||
if (stream.IsEmpty())
|
||||
return NULL;
|
||||
|
||||
// Peek ahead, then let the appropriate Parse*List()
|
||||
// functions handle things
|
||||
const Token *t1 = stream.Get();
|
||||
|
||||
// PatternList | RangeList
|
||||
if (t1->Type() == LeftParen) {
|
||||
const Token *t2 = stream.Get();
|
||||
stream.Unget();
|
||||
stream.Unget();
|
||||
// RangeList
|
||||
if (t2->Type() == LeftBracket) {
|
||||
return ParseRPatternList();
|
||||
// PatternList
|
||||
} else {
|
||||
return ParsePatternList(Range(0,0));
|
||||
}
|
||||
// Range, PatternList
|
||||
} else if (t1->Type() == LeftBracket) {
|
||||
stream.Unget();
|
||||
return ParsePatternList(ParseRange());
|
||||
} else {
|
||||
throw new Err("Sniffer pattern error: missing pattern", t1->Pos()); // Same as R5
|
||||
}
|
||||
|
||||
// PatternList
|
||||
// RangeList
|
||||
// Range + PatternList
|
||||
|
@ -995,41 +1057,197 @@ Parser::ParseExpr() {
|
|||
|
||||
Range
|
||||
Parser::ParseRange() {
|
||||
int32 start, end;
|
||||
// LeftBracket
|
||||
stream.Read(LeftBracket);
|
||||
// Integer
|
||||
// [Colon
|
||||
// Integer]
|
||||
// RightBracket
|
||||
{
|
||||
const Token *t = stream.Get();
|
||||
if (t->Type() == Integer) {
|
||||
start = t->Int();
|
||||
end = start; // In case we aren't given an explicit end
|
||||
} else
|
||||
throw new Err("Sniffer pattern error: pattern offset expected", t->Pos());
|
||||
}
|
||||
// [Colon, Integer] RightBracket
|
||||
{
|
||||
const Token *t = stream.Get();
|
||||
// Colon, Integer, RightBracket
|
||||
if (t->Type() == Colon) {
|
||||
// Integer
|
||||
{
|
||||
const Token *t = stream.Get();
|
||||
if (t->Type() == Integer) {
|
||||
end = t->Int();
|
||||
} else
|
||||
ThrowUnexpectedTokenError(Integer, t);
|
||||
}
|
||||
// RightBracket
|
||||
stream.Read(RightBracket);
|
||||
// !(Colon, Integer) RightBracket
|
||||
} else if (t->Type() == RightBracket) {
|
||||
// Nothing to do here...
|
||||
|
||||
// Something else...
|
||||
} else
|
||||
ThrowUnexpectedTokenError(Colon, Integer, t);
|
||||
}
|
||||
Range range(start, end);
|
||||
if (range.InitCheck() == B_OK)
|
||||
return range;
|
||||
else
|
||||
throw range.GetErr();
|
||||
}
|
||||
|
||||
Expr*
|
||||
Parser::ParsePatternList() {
|
||||
// LeftParen
|
||||
// Pattern
|
||||
// [Divider
|
||||
// Pattern]*
|
||||
// RightParen
|
||||
Parser::ParsePatternList(Range range) {
|
||||
PatternList *list = new(nothrow) PatternList(range);
|
||||
if (!list)
|
||||
ThrowOutOfMemError(stream.Pos());
|
||||
try {
|
||||
// LeftParen
|
||||
stream.Read(LeftParen);
|
||||
// Pattern, (Divider, Pattern)*
|
||||
bool keepLooping = true;
|
||||
while (true) {
|
||||
// Pattern
|
||||
list->Add(ParsePattern());
|
||||
// [Divider]
|
||||
if (!stream.CondRead(Divider))
|
||||
break;
|
||||
}
|
||||
// RightParen
|
||||
const Token *t = stream.Get();
|
||||
if (t->Type() != RightParen)
|
||||
throw new Err("Sniffer pattern error: expecting '|', ')', or possibly '&'", t->Pos());
|
||||
} catch (...) {
|
||||
delete list;
|
||||
throw;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
Expr*
|
||||
Parser::ParseRPatternList() {
|
||||
// LeftParen
|
||||
// RPattern
|
||||
// [Divider
|
||||
// RPattern]*
|
||||
// RightParen
|
||||
RPatternList *list = new(nothrow) RPatternList();
|
||||
if (!list)
|
||||
ThrowOutOfMemError(stream.Pos());
|
||||
try {
|
||||
// LeftParen
|
||||
stream.Read(LeftParen);
|
||||
// RPattern, (Divider, RPattern)*
|
||||
bool keepLooping = true;
|
||||
while (true) {
|
||||
// RPattern
|
||||
list->Add(ParseRPattern());
|
||||
// [Divider]
|
||||
if (!stream.CondRead(Divider))
|
||||
break;
|
||||
}
|
||||
// RightParen
|
||||
const Token *t = stream.Get();
|
||||
if (t->Type() != RightParen)
|
||||
throw new Err("Sniffer pattern error: expecting '|', ')', or possibly '&'", t->Pos());
|
||||
} catch (...) {
|
||||
delete list;
|
||||
throw;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
RPattern*
|
||||
Parser::ParseRPattern() {
|
||||
// Range
|
||||
Range range = ParseRange();
|
||||
// Pattern
|
||||
Pattern *pattern = ParsePattern();
|
||||
|
||||
RPattern *result = new(nothrow) RPattern(range, pattern);
|
||||
if (result) {
|
||||
if (result->InitCheck() == B_OK)
|
||||
return result;
|
||||
else {
|
||||
Err *err = result->GetErr();
|
||||
delete result;
|
||||
throw err;
|
||||
}
|
||||
} else
|
||||
ThrowOutOfMemError(stream.Pos());
|
||||
}
|
||||
|
||||
Pattern*
|
||||
Parser::ParsePattern() {
|
||||
std::string str;
|
||||
// String
|
||||
// [Ampersand
|
||||
// String]
|
||||
{
|
||||
const Token *t = stream.Get();
|
||||
if (t->Type() == CharacterString)
|
||||
str = t->String();
|
||||
else
|
||||
throw new Err("Sniffer pattern error: missing pattern", t->Pos());
|
||||
}
|
||||
// [Ampersand, String]
|
||||
if (stream.CondRead(Ampersand)) {
|
||||
// String (i.e. Mask)
|
||||
const Token *t = stream.Get();
|
||||
if (t->Type() == CharacterString) {
|
||||
Pattern *result = new(nothrow) Pattern(str.c_str(), t->String());
|
||||
if (!result)
|
||||
ThrowOutOfMemError(t->Pos());
|
||||
if (result->InitCheck() == B_OK) {
|
||||
return result;
|
||||
} else {
|
||||
Err *err = result->GetErr();
|
||||
delete result;
|
||||
if (err) {
|
||||
err->SetPos(t->Pos());
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
} else
|
||||
ThrowUnexpectedTokenError(CharacterString, t);
|
||||
} else {
|
||||
// No mask specified.
|
||||
Pattern *result = new(nothrow) Pattern(str.c_str());
|
||||
if (result) {
|
||||
if (result->InitCheck() == B_OK)
|
||||
return result;
|
||||
else {
|
||||
Err *err = result->GetErr();
|
||||
delete result;
|
||||
throw err;
|
||||
}
|
||||
} else
|
||||
ThrowOutOfMemError(stream.Pos());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Parser::ThrowEndOfStreamError() {
|
||||
throw new Err("Sniffer pattern error: unterminated rule", stream.EndPos());
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
Parser::ThrowOutOfMemError(ssize_t pos) {
|
||||
if (fOutOfMemErr)
|
||||
fOutOfMemErr->SetPos(pos);
|
||||
Err *err = fOutOfMemErr;
|
||||
fOutOfMemErr = NULL;
|
||||
throw err;
|
||||
}
|
||||
|
||||
void
|
||||
Parser::ThrowUnexpectedTokenError(TokenType expected, const Token *found) {
|
||||
throw new Err((std::string("Sniffer pattern error: expected ") + tokenTypeToString(expected)
|
||||
+ ", found " + (found ? tokenTypeToString(found->Type()) : "NULL token")).c_str()
|
||||
, (found ? found->Pos() : stream.EndPos()));
|
||||
}
|
||||
|
||||
void
|
||||
Parser::ThrowUnexpectedTokenError(TokenType expected1, TokenType expected2, const Token *found) {
|
||||
throw new Err((std::string("Sniffer pattern error: expected ") + tokenTypeToString(expected1)
|
||||
+ " or " + tokenTypeToString(expected2) + ", found "
|
||||
+ (found ? tokenTypeToString(found->Type()) : "NULL token")).c_str()
|
||||
, (found ? found->Pos() : stream.EndPos()));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue