1*4420c1ceSMichael Pfeiffer /* 2*4420c1ceSMichael Pfeiffer * Copyright 2008, Haiku. 3*4420c1ceSMichael Pfeiffer * Distributed under the terms of the MIT license. 4*4420c1ceSMichael Pfeiffer * 5*4420c1ceSMichael Pfeiffer * Authors: 6*4420c1ceSMichael Pfeiffer * Michael Pfeiffer <laplace@users.sourceforge.net> 7*4420c1ceSMichael Pfeiffer */ 8*4420c1ceSMichael Pfeiffer 9*4420c1ceSMichael Pfeiffer #include "AutoDelete.h" 10*4420c1ceSMichael Pfeiffer #include "CharacterClasses.h" 11*4420c1ceSMichael Pfeiffer #include "Parser.h" 12*4420c1ceSMichael Pfeiffer Parser(const char * file)13*4420c1ceSMichael PfeifferParser::Parser(const char* file) 14*4420c1ceSMichael Pfeiffer : fScanner(file) 15*4420c1ceSMichael Pfeiffer { 16*4420c1ceSMichael Pfeiffer if (InitCheck() == B_OK) { 17*4420c1ceSMichael Pfeiffer NextChar(); 18*4420c1ceSMichael Pfeiffer } 19*4420c1ceSMichael Pfeiffer } 20*4420c1ceSMichael Pfeiffer InitCheck()21*4420c1ceSMichael Pfeifferstatus_t Parser::InitCheck() 22*4420c1ceSMichael Pfeiffer { 23*4420c1ceSMichael Pfeiffer return fScanner.InitCheck(); 24*4420c1ceSMichael Pfeiffer } 25*4420c1ceSMichael Pfeiffer SkipWhitespaces()26*4420c1ceSMichael Pfeiffervoid Parser::SkipWhitespaces() 27*4420c1ceSMichael Pfeiffer { 28*4420c1ceSMichael Pfeiffer while (IsWhitespace(GetCurrentChar())) { 29*4420c1ceSMichael Pfeiffer NextChar(); 30*4420c1ceSMichael Pfeiffer } 31*4420c1ceSMichael Pfeiffer } 32*4420c1ceSMichael Pfeiffer SkipComment()33*4420c1ceSMichael Pfeiffervoid Parser::SkipComment() 34*4420c1ceSMichael Pfeiffer { 35*4420c1ceSMichael Pfeiffer while (GetCurrentChar() != kEof && GetCurrentChar() != kCr) { 36*4420c1ceSMichael Pfeiffer NextChar(); 37*4420c1ceSMichael Pfeiffer } 38*4420c1ceSMichael Pfeiffer NextChar(); 39*4420c1ceSMichael Pfeiffer } 40*4420c1ceSMichael Pfeiffer SkipWhitespaceSeparator()41*4420c1ceSMichael Pfeiffervoid Parser::SkipWhitespaceSeparator() 42*4420c1ceSMichael Pfeiffer { 43*4420c1ceSMichael Pfeiffer while (IsWhitespaceSeparator(GetCurrentChar())) { 44*4420c1ceSMichael Pfeiffer NextChar(); 45*4420c1ceSMichael Pfeiffer } 46*4420c1ceSMichael Pfeiffer } 47*4420c1ceSMichael Pfeiffer ParseKeyword(Statement * statement)48*4420c1ceSMichael Pfeifferbool Parser::ParseKeyword(Statement* statement) 49*4420c1ceSMichael Pfeiffer { 50*4420c1ceSMichael Pfeiffer // ["?"] 51*4420c1ceSMichael Pfeiffer if (GetCurrentChar() == '?') { 52*4420c1ceSMichael Pfeiffer NextChar(); 53*4420c1ceSMichael Pfeiffer statement->SetType(Statement::kQuery); 54*4420c1ceSMichael Pfeiffer } 55*4420c1ceSMichael Pfeiffer // Keyword 56*4420c1ceSMichael Pfeiffer BString* keyword = fScanner.ScanIdent(); 57*4420c1ceSMichael Pfeiffer if (keyword == NULL) { 58*4420c1ceSMichael Pfeiffer Error("Identifier expected"); 59*4420c1ceSMichael Pfeiffer return false; 60*4420c1ceSMichael Pfeiffer } 61*4420c1ceSMichael Pfeiffer statement->SetKeyword(keyword); 62*4420c1ceSMichael Pfeiffer return true; 63*4420c1ceSMichael Pfeiffer } 64*4420c1ceSMichael Pfeiffer ParseTranslation(Value * value,int separator)65*4420c1ceSMichael Pfeifferbool Parser::ParseTranslation(Value* value, int separator) 66*4420c1ceSMichael Pfeiffer { 67*4420c1ceSMichael Pfeiffer BString* translation = fScanner.ScanTranslationValue(separator); 68*4420c1ceSMichael Pfeiffer if (translation == NULL) { 69*4420c1ceSMichael Pfeiffer Error("Out of memory scanning translationn!"); 70*4420c1ceSMichael Pfeiffer return false; 71*4420c1ceSMichael Pfeiffer } 72*4420c1ceSMichael Pfeiffer value->SetTranslation(translation); 73*4420c1ceSMichael Pfeiffer return true; 74*4420c1ceSMichael Pfeiffer } 75*4420c1ceSMichael Pfeiffer ParseOption(Statement * statement)76*4420c1ceSMichael Pfeifferbool Parser::ParseOption(Statement* statement) 77*4420c1ceSMichael Pfeiffer { 78*4420c1ceSMichael Pfeiffer // ["^"] 79*4420c1ceSMichael Pfeiffer bool isSymbolValue = GetCurrentChar() == '^'; 80*4420c1ceSMichael Pfeiffer if (isSymbolValue) { 81*4420c1ceSMichael Pfeiffer NextChar(); 82*4420c1ceSMichael Pfeiffer } 83*4420c1ceSMichael Pfeiffer 84*4420c1ceSMichael Pfeiffer // [ ... Option ...] 85*4420c1ceSMichael Pfeiffer if (IsOptionChar(GetCurrentChar())) { 86*4420c1ceSMichael Pfeiffer 87*4420c1ceSMichael Pfeiffer BString* option = fScanner.ScanOption(); 88*4420c1ceSMichael Pfeiffer if (option == NULL) { 89*4420c1ceSMichael Pfeiffer Error("Out of memory scanning option!"); 90*4420c1ceSMichael Pfeiffer return false; 91*4420c1ceSMichael Pfeiffer } 92*4420c1ceSMichael Pfeiffer Value::Type type; 93*4420c1ceSMichael Pfeiffer if (isSymbolValue) { 94*4420c1ceSMichael Pfeiffer type = Value::kSymbolValue; 95*4420c1ceSMichael Pfeiffer } else { 96*4420c1ceSMichael Pfeiffer type = Value::kStringValue; 97*4420c1ceSMichael Pfeiffer } 98*4420c1ceSMichael Pfeiffer Value* value = new Value(option, type); 99*4420c1ceSMichael Pfeiffer statement->SetOption(value); 100*4420c1ceSMichael Pfeiffer 101*4420c1ceSMichael Pfeiffer SkipWhitespaceSeparator(); 102*4420c1ceSMichael Pfeiffer // ["/" Translation ] 103*4420c1ceSMichael Pfeiffer if (GetCurrentChar() == '/') { 104*4420c1ceSMichael Pfeiffer NextChar(); 105*4420c1ceSMichael Pfeiffer return ParseTranslation(value, ':'); 106*4420c1ceSMichael Pfeiffer } 107*4420c1ceSMichael Pfeiffer } else { 108*4420c1ceSMichael Pfeiffer if (isSymbolValue) { 109*4420c1ceSMichael Pfeiffer Error("Expected symbol value!"); 110*4420c1ceSMichael Pfeiffer return false; 111*4420c1ceSMichael Pfeiffer } 112*4420c1ceSMichael Pfeiffer } 113*4420c1ceSMichael Pfeiffer return true; 114*4420c1ceSMichael Pfeiffer } 115*4420c1ceSMichael Pfeiffer ParseValue(Statement * statement)116*4420c1ceSMichael Pfeifferbool Parser::ParseValue(Statement* statement) 117*4420c1ceSMichael Pfeiffer { 118*4420c1ceSMichael Pfeiffer if (GetCurrentChar() == '"') { 119*4420c1ceSMichael Pfeiffer NextChar(); 120*4420c1ceSMichael Pfeiffer 121*4420c1ceSMichael Pfeiffer // "..." 122*4420c1ceSMichael Pfeiffer AutoDelete<Value> value(new Value()); 123*4420c1ceSMichael Pfeiffer 124*4420c1ceSMichael Pfeiffer BString* string; 125*4420c1ceSMichael Pfeiffer if (statement->GetOption() != NULL) { 126*4420c1ceSMichael Pfeiffer string = fScanner.ScanInvocationValue(); 127*4420c1ceSMichael Pfeiffer value.Get()->SetType(Value::kInvocationValue); 128*4420c1ceSMichael Pfeiffer } else { 129*4420c1ceSMichael Pfeiffer string = fScanner.ScanQuotedValue(); 130*4420c1ceSMichael Pfeiffer value.Get()->SetType(Value::kQuotedValue); 131*4420c1ceSMichael Pfeiffer } 132*4420c1ceSMichael Pfeiffer 133*4420c1ceSMichael Pfeiffer if (string == NULL) { 134*4420c1ceSMichael Pfeiffer Error("Expected value"); 135*4420c1ceSMichael Pfeiffer return false; 136*4420c1ceSMichael Pfeiffer } 137*4420c1ceSMichael Pfeiffer 138*4420c1ceSMichael Pfeiffer // " is expected 139*4420c1ceSMichael Pfeiffer if (GetCurrentChar() != '"') { 140*4420c1ceSMichael Pfeiffer Error("Expected \" at end of value"); 141*4420c1ceSMichael Pfeiffer return false; 142*4420c1ceSMichael Pfeiffer } 143*4420c1ceSMichael Pfeiffer NextChar(); 144*4420c1ceSMichael Pfeiffer 145*4420c1ceSMichael Pfeiffer value.Get()->SetValue(string); 146*4420c1ceSMichael Pfeiffer statement->SetValue(value.Release()); 147*4420c1ceSMichael Pfeiffer } else if (GetCurrentChar() == '^') { 148*4420c1ceSMichael Pfeiffer // ^ SymbolValue 149*4420c1ceSMichael Pfeiffer BString* symbol = fScanner.ScanOption(); 150*4420c1ceSMichael Pfeiffer if (symbol == NULL) { 151*4420c1ceSMichael Pfeiffer Error("Symbol expected!"); 152*4420c1ceSMichael Pfeiffer return false; 153*4420c1ceSMichael Pfeiffer } 154*4420c1ceSMichael Pfeiffer Value* value = new Value(symbol, Value::kSymbolValue); 155*4420c1ceSMichael Pfeiffer statement->SetValue(value); 156*4420c1ceSMichael Pfeiffer } else { 157*4420c1ceSMichael Pfeiffer // StringValue 158*4420c1ceSMichael Pfeiffer BString* stringValue = fScanner.ScanStringValue(); 159*4420c1ceSMichael Pfeiffer if (stringValue == NULL) { 160*4420c1ceSMichael Pfeiffer Error("String value expected!"); 161*4420c1ceSMichael Pfeiffer return false; 162*4420c1ceSMichael Pfeiffer } 163*4420c1ceSMichael Pfeiffer 164*4420c1ceSMichael Pfeiffer Value* value = new Value(stringValue, Value::kStringValue); 165*4420c1ceSMichael Pfeiffer statement->SetValue(value); 166*4420c1ceSMichael Pfeiffer } 167*4420c1ceSMichael Pfeiffer if (GetCurrentChar() == '/') { 168*4420c1ceSMichael Pfeiffer NextChar(); 169*4420c1ceSMichael Pfeiffer return ParseTranslation(statement->GetValue(), kCr); 170*4420c1ceSMichael Pfeiffer } 171*4420c1ceSMichael Pfeiffer return true; 172*4420c1ceSMichael Pfeiffer } 173*4420c1ceSMichael Pfeiffer 174*4420c1ceSMichael Pfeiffer UpdateStatementType(Statement * statement)175*4420c1ceSMichael Pfeiffervoid Parser::UpdateStatementType(Statement* statement) 176*4420c1ceSMichael Pfeiffer { 177*4420c1ceSMichael Pfeiffer if (statement->GetType() != Statement::kUnknown) return; 178*4420c1ceSMichael Pfeiffer 179*4420c1ceSMichael Pfeiffer BString* keyword = statement->GetKeyword(); 180*4420c1ceSMichael Pfeiffer Statement::Type type; 181*4420c1ceSMichael Pfeiffer if (keyword->FindFirst("Default") == 0) { 182*4420c1ceSMichael Pfeiffer type = Statement::kDefault; 183*4420c1ceSMichael Pfeiffer keyword->RemoveFirst("Default"); 184*4420c1ceSMichael Pfeiffer } else if (keyword->FindFirst("Param") == 0) { 185*4420c1ceSMichael Pfeiffer type = Statement::kParam; 186*4420c1ceSMichael Pfeiffer keyword->RemoveFirst("Param"); 187*4420c1ceSMichael Pfeiffer } else { 188*4420c1ceSMichael Pfeiffer type = Statement::kValue; 189*4420c1ceSMichael Pfeiffer } 190*4420c1ceSMichael Pfeiffer statement->SetType(type); 191*4420c1ceSMichael Pfeiffer } 192*4420c1ceSMichael Pfeiffer 193*4420c1ceSMichael Pfeiffer // ["?"]Keyword [["^"]Option["/"Translation]] 194*4420c1ceSMichael Pfeiffer // [":" 195*4420c1ceSMichael Pfeiffer // ["^"]Value ["/" Translation]. 196*4420c1ceSMichael Pfeiffer // ] ParseStatement()197*4420c1ceSMichael PfeifferStatement* Parser::ParseStatement() 198*4420c1ceSMichael Pfeiffer { 199*4420c1ceSMichael Pfeiffer AutoDelete<Statement> statement(new Statement()); 200*4420c1ceSMichael Pfeiffer 201*4420c1ceSMichael Pfeiffer if (!ParseKeyword(statement.Get())) { 202*4420c1ceSMichael Pfeiffer return NULL; 203*4420c1ceSMichael Pfeiffer } 204*4420c1ceSMichael Pfeiffer SkipWhitespaceSeparator(); 205*4420c1ceSMichael Pfeiffer 206*4420c1ceSMichael Pfeiffer if (!ParseOption(statement.Get())) { 207*4420c1ceSMichael Pfeiffer return NULL; 208*4420c1ceSMichael Pfeiffer } 209*4420c1ceSMichael Pfeiffer 210*4420c1ceSMichael Pfeiffer SkipWhitespaceSeparator(); 211*4420c1ceSMichael Pfeiffer // [":" ... ] 212*4420c1ceSMichael Pfeiffer if (GetCurrentChar() == ':') { 213*4420c1ceSMichael Pfeiffer NextChar(); 214*4420c1ceSMichael Pfeiffer SkipWhitespaceSeparator(); 215*4420c1ceSMichael Pfeiffer if (!ParseValue(statement.Get())) { 216*4420c1ceSMichael Pfeiffer return NULL; 217*4420c1ceSMichael Pfeiffer } 218*4420c1ceSMichael Pfeiffer } 219*4420c1ceSMichael Pfeiffer SkipWhitespaceSeparator(); 220*4420c1ceSMichael Pfeiffer if (GetCurrentChar() == kEof || GetCurrentChar() == kLf || GetCurrentChar() == kCr) { 221*4420c1ceSMichael Pfeiffer UpdateStatementType(statement.Get()); 222*4420c1ceSMichael Pfeiffer Statement* result = statement.Release(); 223*4420c1ceSMichael Pfeiffer return result; 224*4420c1ceSMichael Pfeiffer } else { 225*4420c1ceSMichael Pfeiffer Error("Newline expected at end of statement"); 226*4420c1ceSMichael Pfeiffer return NULL; 227*4420c1ceSMichael Pfeiffer } 228*4420c1ceSMichael Pfeiffer } 229*4420c1ceSMichael Pfeiffer Parse()230*4420c1ceSMichael PfeifferStatement* Parser::Parse() 231*4420c1ceSMichael Pfeiffer { 232*4420c1ceSMichael Pfeiffer while (true) { 233*4420c1ceSMichael Pfeiffer int ch = GetCurrentChar(); 234*4420c1ceSMichael Pfeiffer if (ch == -1) { 235*4420c1ceSMichael Pfeiffer return NULL; 236*4420c1ceSMichael Pfeiffer } 237*4420c1ceSMichael Pfeiffer if (IsWhitespace(ch)) { 238*4420c1ceSMichael Pfeiffer SkipWhitespaces(); 239*4420c1ceSMichael Pfeiffer } else if (ch == '*') { 240*4420c1ceSMichael Pfeiffer // begin of comment or statement 241*4420c1ceSMichael Pfeiffer NextChar(); 242*4420c1ceSMichael Pfeiffer ch = GetCurrentChar(); 243*4420c1ceSMichael Pfeiffer if (ch == '%') { 244*4420c1ceSMichael Pfeiffer SkipComment(); 245*4420c1ceSMichael Pfeiffer } else { 246*4420c1ceSMichael Pfeiffer return ParseStatement(); 247*4420c1ceSMichael Pfeiffer } 248*4420c1ceSMichael Pfeiffer } else { 249*4420c1ceSMichael Pfeiffer Error("Expected *"); 250*4420c1ceSMichael Pfeiffer return NULL; 251*4420c1ceSMichael Pfeiffer } 252*4420c1ceSMichael Pfeiffer } 253*4420c1ceSMichael Pfeiffer } 254*4420c1ceSMichael Pfeiffer 255