bool Parser::Impl::parseTest() { // test := identifier arguments // arguments := *argument [ test / test-list ] // // identifier // if ( !obtainToken() || atEnd() ) return false; if ( token() != Lexer::Identifier ) return false; if ( scriptBuilder() ) scriptBuilder()->testStart( tokenValue() ); consumeToken(); // // *argument // if ( !obtainToken() ) return false; if ( atEnd() ) // a test w/o args goto TestEnd; if ( isArgumentToken() && !parseArgumentList() ) { assert( error() ); return false; } // // test / test-list // if ( !obtainToken() ) return false; if ( atEnd() ) // a test w/o nested tests goto TestEnd; if ( token() == Lexer::Special && tokenValue() == "(" ) { // test-list if ( !parseTestList() ) { assert( error() ); return false; } } else if ( token() == Lexer::Identifier ) { // should be test: if ( !parseTest() ) { assert( error() ); return false; } } TestEnd: if ( scriptBuilder() ) scriptBuilder()->testEnd(); return true; }
bool Parser::Impl::parseArgument() { // argument := string-list / number / tag if ( !obtainToken() || atEnd() ) return false; if ( token() == Lexer::Number ) { if ( !parseNumber() ) { assert( error() ); return false; } return true; } else if ( token() == Lexer::Tag ) { if ( scriptBuilder() ) scriptBuilder()->taggedArgument( tokenValue() ); consumeToken(); return true; } else if ( isStringToken() ) { if ( scriptBuilder() ) scriptBuilder()->stringArgument( tokenValue(), token() == Lexer::MultiLineString, QString() ); consumeToken(); return true; } else if ( token() == Lexer::Special && tokenValue() == "[" ) { if ( !parseStringList() ) { assert( error() ); return false; } return true; } return false; }
bool Parser::Impl::obtainToken() { while ( !mToken && !lexer.atEnd() && !lexer.error() ) { mToken = lexer.nextToken( mTokenValue ); if ( lexer.error() ) break; // comments and line feeds are semantically invisible and may // appear anywhere, so we handle them here centrally: switch ( token() ) { case Lexer::HashComment: if ( scriptBuilder() ) scriptBuilder()->hashComment( tokenValue() ); consumeToken(); break; case Lexer::BracketComment: if ( scriptBuilder() ) scriptBuilder()->bracketComment( tokenValue() ); consumeToken(); break; case Lexer::LineFeeds: for ( unsigned int i = 0, end = tokenValue().toUInt() ; i < end ; ++i ) if ( scriptBuilder() ) // better check every iteration, b/c // we call out to ScriptBuilder, // where nasty things might happen! scriptBuilder()->lineFeed(); consumeToken(); break; default: ; // make compiler happy } } if ( lexer.error() && scriptBuilder() ) scriptBuilder()->error( lexer.error() ); return !lexer.error(); }
bool Parser::Impl::parseBlock() { // our ABNF: // block := "{" [ command-list ] "}" if(!obtainToken() || atEnd()) return false; if(token() != Lexer::Special || tokenValue() != "{") return false; if(scriptBuilder()) scriptBuilder()->blockStart(); consumeToken(); if(!obtainToken()) return false; if(atEnd()) { makeError(Error::PrematureEndOfBlock); return false; } if(token() == Lexer::Identifier) { if(!parseCommandList()) { assert(error()); return false; } } if(!obtainToken()) return false; if(atEnd()) { makeError(Error::PrematureEndOfBlock); return false; } if(token() != Lexer::Special || tokenValue() != "}") { makeError(Error::NonCommandInCommandList); return false; } if(scriptBuilder()) scriptBuilder()->blockEnd(); consumeToken(); return true; }
ListNode addToList(int lineNo, int tokenId, char* tokenString, Token tokenType, ListNode head){ ListNode this = head; ListNode newNode; newNode = (ListNode) malloc(sizeof(struct node)); newNode -> lineNo = lineNo; newNode -> tokenId = tokenId; newNode -> tokenStr = strdup(tokenString); newNode -> tokenType = tokenType; newNode -> token = tokenValue(newNode -> tokenType, newNode -> tokenStr); newNode -> next = NULL; if(head == NULL){ head = newNode; return head; } while(this -> next != NULL){ this = this -> next; } this -> next = newNode; return head; }
bool Parser::Impl::parseNumber() { // The lexer returns the number including the quantifier as a // single token value. Here, we split is an check that the number // is not out of range: if(!obtainToken() || atEnd()) return false; if(token() != Lexer::Number) return false; // number: unsigned long result = 0; unsigned int i = 0; const QCString s = tokenValue().latin1(); for(const unsigned int len = s.length() ; i < len && isdigit(s[i]) ; ++i) { const unsigned long digitValue = s[i] - '0' ; if(willOverflowULong(result, digitValue)) { makeError(Error::NumberOutOfRange); return false; } else { result *= 10 ; result += digitValue ; } } // optional quantifier: char quantifier = '\0'; if(i < s.length()) { assert(i + 1 == s.length()); quantifier = s[i]; const unsigned long factor = factorForQuantifier(quantifier); if(result > double(ULONG_MAX) / double(factor)) { makeError(Error::NumberOutOfRange); return false; } result *= factor; } if(scriptBuilder()) scriptBuilder()->numberArgument(result, quantifier); consumeToken(); return true; }
short Scanner::getToken( YYSTYPE & lval ) //--------------------------------------- // get the next token from the input stream. // at each call, the next character should be // in _current. { const int MaxBufLen = 512; char buffer[ MaxBufLen ]; int bufPos; // position in buffer char special; gobble(); if( isEOF() ) { return 0; } if( isSpecial() ) { special = (char) _current; get(); // set up for next call return special; // <-------- early return } if( isQuote() ) { readQuotedString( lval ); return T_String; // <-------- early return } if( _current == '0' ) { get(); if( toupper( _current ) == 'X' ) { readHex( lval ); } else { if( isDigit() ) { readDecimal( lval ); } else { lval = 0; } } return T_Number; // <-------- early return } if( isDigit() ) { readDecimal( lval ); return T_Number; // <-------- early return } for( bufPos = 0; bufPos < MaxBufLen; bufPos += 1 ) { buffer[ bufPos ] = (char) _current; get(); if( isEOF() || isSpace() || isSpecial() ) break; } bufPos += 1; assert( bufPos < MaxBufLen ); buffer[ bufPos ] = '\0'; return tokenValue( buffer, lval ); }
bool Parser::Impl::parseStringList() { // string-list := "[" string *("," string) "]" / string // ;; if there is only a single string, the brackets are optional // // However, since strings are already handled separately from // string lists in parseArgument(), our ABNF is modified to: // string-list := "[" string *("," string) "]" if ( !obtainToken() || atEnd() ) return false; if ( token() != Lexer::Special || tokenValue() != "[" ) return false; if ( scriptBuilder() ) scriptBuilder()->stringListArgumentStart(); consumeToken(); // generic while/switch construct for comma-separated lists. See // parseTestList() for another one. Any fix here is like to apply there, too. bool lastWasComma = true; while ( !atEnd() ) { if ( !obtainToken() ) return false; switch ( token() ) { case Lexer::None: break; case Lexer::Special: assert( tokenValue().length() == 1 ); switch ( tokenValue()[0].toLatin1() ) { case ']': consumeToken(); if ( lastWasComma ) { makeError( Error::ConsecutiveCommasInStringList ); return false; } if ( scriptBuilder() ) scriptBuilder()->stringListArgumentEnd(); return true; case ',': consumeToken(); if ( lastWasComma ) { makeError( Error::ConsecutiveCommasInStringList ); return false; } lastWasComma = true; break; default: makeError( Error::NonStringInStringList ); return false; } break; case Lexer::QuotedString: case Lexer::MultiLineString: if ( !lastWasComma ) { makeError( Error::MissingCommaInStringList ); return false; } lastWasComma = false; if ( scriptBuilder() ) scriptBuilder()->stringListEntry( tokenValue(), token() == Lexer::MultiLineString, QString() ); consumeToken(); break; default: makeError( Error::NonStringInStringList ); return false; } } makeError( Error::PrematureEndOfStringList ); return false; }
bool Parser::Impl::parseTestList() { // test-list := "(" test *("," test) ")" if ( !obtainToken() || atEnd() ) return false; if ( token() != Lexer::Special || tokenValue() != "(" ) return false; if ( scriptBuilder() ) scriptBuilder()->testListStart(); consumeToken(); // generic while/switch construct for comma-separated lists. See // parseStringList() for another one. Any fix here is like to apply there, too. bool lastWasComma = true; while ( !atEnd() ) { if ( !obtainToken() ) return false; switch ( token() ) { case Lexer::None: break; case Lexer::Special: assert( tokenValue().length() == 1 ); assert( tokenValue()[0].toLatin1() ); switch ( tokenValue()[0].toLatin1() ) { case ')': consumeToken(); if ( lastWasComma ) { makeError( Error::ConsecutiveCommasInTestList ); return false; } if ( scriptBuilder() ) scriptBuilder()->testListEnd(); return true; case ',': consumeToken(); if( lastWasComma ) { makeError( Error::ConsecutiveCommasInTestList ); return false; } lastWasComma = true; break; default: makeError( Error::NonStringInStringList ); return false; } break; case Lexer::Identifier: if ( !lastWasComma ) { makeError( Error::MissingCommaInTestList ); return false; } else { lastWasComma = false; if ( !parseTest() ) { assert( error() ); return false; } } break; default: makeUnexpectedTokenError( Error::NonTestInTestList ); return false; } } makeError( Error::PrematureEndOfTestList ); return false; }
bool Parser::Impl::parseCommand() { // command := identifier arguments ( ";" / block ) // arguments := *argument [ test / test-list ] // block := "{" *command "}" // our ABNF: // block := "{" [ command-list ] "}" if ( atEnd() ) return false; // // identifier // if ( !obtainToken() || token() != Lexer::Identifier ) return false; if ( scriptBuilder() ) scriptBuilder()->commandStart( tokenValue() ); consumeToken(); // // *argument // if ( !obtainToken() ) return false; if ( atEnd() ) { makeError( Error::MissingSemicolonOrBlock ); return false; } if ( isArgumentToken() && !parseArgumentList() ) { assert( error() ); return false; } // // test / test-list // if ( !obtainToken() ) return false; if ( atEnd() ) { makeError( Error::MissingSemicolonOrBlock ); return false; } if ( token() == Lexer::Special && tokenValue() == "(" ) { // test-list if ( !parseTestList() ) { assert( error() ); return false; } } else if ( token() == Lexer::Identifier ) { // should be test: if ( !parseTest() ) { assert( error() ); return false; } } // // ";" / block // if ( !obtainToken() ) return false; if ( atEnd() ) { makeError( Error::MissingSemicolonOrBlock ); return false; } if ( token() != Lexer::Special ) { makeUnexpectedTokenError( Error::ExpectedBlockOrSemicolon ); return false; } if ( tokenValue() == ";" ) consumeToken(); else if ( tokenValue() == "{" ) { // block if ( !parseBlock() ) return false; // it's an error since we saw '{' } else { makeError( Error::MissingSemicolonOrBlock ); return false; } if ( scriptBuilder() ) scriptBuilder()->commandEnd(); return true; }