/// ParseEQUIVALENCEStmt - Parse the EQUIVALENCE statement. /// /// [R554]: /// equivalence-stmt := /// EQUIVALENCE equivalence-set-list Parser::StmtResult Parser::ParseEQUIVALENCEStmt() { // Check if this is an assignment. if (IsNextToken(tok::equal)) return StmtResult(); auto Loc = ConsumeToken(); SmallVector<Stmt*, 8> StmtList; SmallVector<Expr*, 8> ObjectList; bool OuterError = false; while(true) { auto PartLoc = Tok.getLocation(); if(!ExpectAndConsume(tok::l_paren)) { if(!SkipUntil(tok::l_paren)) { OuterError = true; break; } } ObjectList.clear(); bool InnerError = false; do { auto E = ParseExpectedExpression(); if(E.isInvalid()) { InnerError = true; break; } else if(E.isUsable()) ObjectList.push_back(E.get()); } while(ConsumeIfPresent(tok::comma)); auto S = Actions.ActOnEQUIVALENCE(Context, Loc, PartLoc, ObjectList, nullptr); if(S.isUsable()) StmtList.push_back(S.get()); if(InnerError) { if(!SkipUntil(tok::r_paren, true, true)) { OuterError = true; break; } } if(!ExpectAndConsume(tok::r_paren)) { if(!SkipUntil(tok::r_paren)) { OuterError = true; break; } } if(ConsumeIfPresent(tok::comma)) continue; if(IsPresent(tok::l_paren)) { ExpectAndConsume(tok::comma); continue; } break; } if(OuterError) SkipUntilNextStatement(); else ExpectStatementEnd(); return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel); }
/// ParsePARAMETERStmt - Parse the PARAMETER statement. /// /// [R548]: /// parameter-stmt := /// PARAMETER ( named-constant-def-list ) Parser::StmtResult Parser::ParsePARAMETERStmt() { // Check if this is an assignment. if (IsNextToken(tok::equal)) return StmtResult(); auto Loc = ConsumeToken(); SmallVector<Stmt*, 8> StmtList; if(!ExpectAndConsume(tok::l_paren)) { if(!SkipUntil(tok::l_paren)) return StmtError(); } while(true) { auto IDLoc = Tok.getLocation(); auto II = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) { if(!SkipUntil(tok::comma)) break; else continue; } auto EqualLoc = Tok.getLocation(); if(!ExpectAndConsume(tok::equal)) { if(!SkipUntil(tok::comma)) break; else continue; } ExprResult ConstExpr = ParseExpression(); if(ConstExpr.isUsable()) { auto Stmt = Actions.ActOnPARAMETER(Context, Loc, EqualLoc, IDLoc, II, ConstExpr, nullptr); if(Stmt.isUsable()) StmtList.push_back(Stmt.take()); } if(ConsumeIfPresent(tok::comma)) continue; if(isTokenIdentifier() && !Tok.isAtStartOfStatement()) { ExpectAndConsume(tok::comma); continue; } break; } if(!ExpectAndConsume(tok::r_paren)) SkipUntilNextStatement(); return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel); }
/// FIXME: todo implied-do ExprResult Parser::ParseArrayConstructor() { auto Loc = ConsumeParenSlash(); SourceLocation EndLoc = Tok.getLocation(); SmallVector<Expr*, 16> ExprList; if(ConsumeIfPresent(tok::slashr_paren)) return Actions.ActOnArrayConstructorExpr(Context, Loc, EndLoc, ExprList); do { auto E = ParseExpectedExpression(); if(E.isInvalid()) goto error; if(E.isUsable()) ExprList.push_back(E.get()); } while(ConsumeIfPresent(tok::comma)); EndLoc = Tok.getLocation(); if(!ExpectAndConsume(tok::slashr_paren)) goto error; return Actions.ActOnArrayConstructorExpr(Context, Loc, EndLoc, ExprList); error: EndLoc = Tok.getLocation(); SkipUntil(tok::slashr_paren); return Actions.ActOnArrayConstructorExpr(Context, Loc, EndLoc, ExprList); }
JsonNode JsonReader::ParseObject() { JsonNode object = JsonNode(JsonNode::Type::Object); bool end = false; if (*m_data == '{') m_data++; /* Look for the next key name */ while (!end) { std::string key; /* Look for string quotes */ while (*m_data != '\"' && *m_data != '\'' && !EndOfFile()) m_data++; if (EndOfFile()) { PrintError("Syntax Error : '\"' , ''' were expected. "); break; } /* Parse the key as string */ key = ParseString(); SkipUntil(':'); if (EndOfFile()) { PrintError("Syntax Error : ':' was expected. "); break; } m_data++; object[key] = this->ParseValue(); while (*m_data != ',' && *m_data != '}' && !EndOfFile()) m_data++; switch (*m_data) { case ',': m_data++; break; case '}': end = true; m_data++; break; default: PrintError("Syntax Error : ',' , '}' were expected. "); end = true; break; }; } return object; }
/* ExtractWordsIntoList * -------------------- * This uses the Scanner to extract the words from the file, by looping * calling ReadNextToken until it returns false (which indicates end of * file). If the word is over the minimum length, we add it to the list * if not already present. Since we know that we are parsing HTML files, * we make a specific effort to exclude tags by checking if the token * begins with '<', and if so, we quickly skip everything up to the * closing '>'. This avoids entering HTML tag words in our list. * We use the stack for the storage for the word (again since the stack * is cheap and quick), but if we need to store the word permanently * in the list, we have to make a new heap copy, since the stack buffer * will be overwritten each time we read a new token. This copy is made * when adding the word to the list (see function AddWordIfAbsent). */ static void ExtractWordsIntoList(Scanner s, struct wordlist *list) { char word[MAX_WORD_LEN]; while (ReadNextToken(s, word, MAX_WORD_LEN)) { if (word[0] == '<') // if HTML opening tag SkipUntil(s, ">"); // skip to end of tag else if (strlen(word) >= MIN_WORD_LEN && ContainsOnlyAscii(word)) // long enough to list AddWordIfAbsent(word, list); } }
bool Parser::ParseDerivedTypeComponentStmt() { // type-spec DeclSpec DS; if(ParseDeclarationTypeSpec(DS, true, false)) return true; // component-attr-spec if(ConsumeIfPresent(tok::comma)) { do { auto Kind = Tok.getKind(); auto Loc = Tok.getLocation(); auto ID = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) return true; if(Kind == tok::kw_POINTER) Actions.ActOnAttrSpec(Loc, DS, DeclSpec::AS_pointer); else if(Kind == tok::kw_DIMENSION) { if(ParseDimensionAttributeSpec(Loc, DS)) return true; } else { if(isAttributeSpec(Kind)) Diag.Report(Loc, diag::err_use_of_attr_spec_in_type_decl) << ID; else Diag.Report(Loc, diag::err_expected_attr_spec); if(!SkipUntil(tok::coloncolon, true, true)) return true; break; } } while(ConsumeIfPresent(tok::comma)); if(!ExpectAndConsume(tok::coloncolon)) return true; } else ConsumeIfPresent(tok::coloncolon); // component-decl-list do { auto IDLoc = Tok.getLocation(); auto ID = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) return true; DeclSpec ObjectDS(DS); if(ParseObjectArraySpec(IDLoc, ObjectDS)) return true; if(ParseObjectCharLength(IDLoc, ObjectDS)) return true; // FIXME: initialization expressions Actions.ActOnDerivedTypeFieldDecl(Context, ObjectDS, IDLoc, ID); } while(ConsumeIfPresent(tok::comma)); return false; }
// We expect: // whitespace | attribute name | = | attribute value // where attribute value can be quoted AttrInfo *HtmlToken::NextAttr() { // start after the last attribute found (or the beginning) const char *curr = nextAttr; if (!curr) curr = s + nLen; const char *end = s + sLen; // parse attribute name SkipWs(curr, end); if (curr == end) { NoNextAttr: nextAttr = NULL; return NULL; } attrInfo.name = curr; SkipName(curr, end); attrInfo.nameLen = curr - attrInfo.name; if (0 == attrInfo.nameLen) goto NoNextAttr; SkipWs(curr, end); if ((curr == end) || ('=' != *curr)) { // attributes without values get their names as value in HTML attrInfo.val = attrInfo.name; attrInfo.valLen = attrInfo.nameLen; nextAttr = curr; return &attrInfo; } // parse attribute value ++curr; // skip '=' SkipWs(curr, end); if (curr == end) { // attribute with implicit empty value attrInfo.val = curr; attrInfo.valLen = 0; } else if (('\'' == *curr) || ('\"' == *curr)) { // attribute with quoted value ++curr; attrInfo.val = curr; if (!SkipUntil(curr, end, *(curr - 1))) goto NoNextAttr; attrInfo.valLen = curr - attrInfo.val; ++curr; } else { attrInfo.val = curr; SkipNonWs(curr, end); attrInfo.valLen = curr - attrInfo.val; } nextAttr = curr; return &attrInfo; }
/// ParseINTRINSICStmt - Parse the INTRINSIC statement. /// /// [R1216]: /// intrinsic-stmt := /// INTRINSIC [::] intrinsic-procedure-name-list Parser::StmtResult Parser::ParseINTRINSICStmt(bool IsActuallyExternal) { // Check if this is an assignment. if (IsNextToken(tok::equal)) return StmtResult(); auto Loc = ConsumeToken(); ConsumeIfPresent(tok::coloncolon); SmallVector<Stmt *,8> StmtList; while(true) { auto IDLoc = Tok.getLocation(); auto II = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) { if(!SkipUntil(tok::comma, tok::identifier, true, true)) break; if(ConsumeIfPresent(tok::comma)) continue; else { IDLoc = Tok.getLocation(); II = Tok.getIdentifierInfo(); ConsumeToken(); } } auto Stmt = IsActuallyExternal? Actions.ActOnEXTERNAL(Context, Loc, IDLoc, II, nullptr): Actions.ActOnINTRINSIC(Context, Loc, IDLoc, II, nullptr); if(Stmt.isUsable()) StmtList.push_back(Stmt.take()); if(Tok.isAtStartOfStatement()) break; if(!ExpectAndConsume(tok::comma)) { if(!SkipUntil(tok::comma)) break; } } return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel); }
/// ParseDIMENSIONStmt - Parse the DIMENSION statement. /// /// [R535]: /// dimension-stmt := /// DIMENSION [::] array-name ( array-spec ) # /// # [ , array-name ( array-spec ) ] ... Parser::StmtResult Parser::ParseDIMENSIONStmt() { // Check if this is an assignment. if (IsNextToken(tok::equal)) return StmtResult(); auto Loc = ConsumeToken(); ConsumeIfPresent(tok::coloncolon); SmallVector<Stmt*, 8> StmtList; SmallVector<ArraySpec*, 4> Dimensions; while (true) { auto IDLoc = Tok.getLocation(); auto II = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) { if(!SkipUntil(tok::comma, tok::identifier, true, true)) break; if(ConsumeIfPresent(tok::comma)) continue; else { IDLoc = Tok.getLocation(); II = Tok.getIdentifierInfo(); ConsumeToken(); } } // FIXME: improve error recovery Dimensions.clear(); if(ParseArraySpec(Dimensions)) return StmtError(); auto Stmt = Actions.ActOnDIMENSION(Context, Loc, IDLoc, II, Dimensions, nullptr); if(Stmt.isUsable()) StmtList.push_back(Stmt.take()); if(Tok.isAtStartOfStatement()) break; if(!ExpectAndConsume(tok::comma)) { if(!SkipUntil(tok::comma)) break; } } return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel); }
Parser::StmtResult Parser::ParseGotoStmt() { SourceLocation Loc = ConsumeToken(); if(ConsumeIfPresent(tok::l_paren)) { // computed goto. SmallVector<Expr*, 4> Targets; do { auto E = ParseStatementLabelReference(); if(E.isInvalid()) break; Targets.append(1, E.get()); } while(ConsumeIfPresent(tok::comma)); ExprResult Operand; bool ParseOperand = true; if(!ExpectAndConsume(tok::r_paren)) { if(!SkipUntil(tok::r_paren)) ParseOperand = false; } if(ParseOperand) Operand = ParseExpectedExpression(); return Actions.ActOnComputedGotoStmt(Context, Loc, Targets, Operand, StmtLabel); } auto Destination = ParseStatementLabelReference(); if(Destination.isInvalid()) { if(!IsPresent(tok::identifier)) { Diag.Report(getExpectedLoc(), diag::err_expected_stmt_label_after) << "GO TO"; return StmtError(); } auto IDInfo = Tok.getIdentifierInfo(); auto IDLoc = ConsumeToken(); auto VD = Actions.ExpectVarRef(IDLoc, IDInfo); if(!VD) return StmtError(); auto Var = VarExpr::Create(Context, IDLoc, VD); // Assigned goto SmallVector<Expr*, 4> AllowedValues; if(ConsumeIfPresent(tok::l_paren)) { do { auto E = ParseStatementLabelReference(); if(E.isInvalid()) { Diag.Report(getExpectedLoc(), diag::err_expected_stmt_label); SkipUntilNextStatement(); return Actions.ActOnAssignedGotoStmt(Context, Loc, Var, AllowedValues, StmtLabel); } AllowedValues.append(1, E.get()); } while(ConsumeIfPresent(tok::comma)); ExpectAndConsume(tok::r_paren); } return Actions.ActOnAssignedGotoStmt(Context, Loc, Var, AllowedValues, StmtLabel); } // Uncoditional goto return Actions.ActOnGotoStmt(Context, Loc, Destination, StmtLabel); }
Parser::StmtResult Parser::ParseCaseStmt() { auto Loc = ConsumeToken(); if(ConsumeIfPresent(tok::kw_DEFAULT)) { ParseTrailingConstructName(); return Actions.ActOnCaseDefaultStmt(Context, Loc, StmtConstructName, StmtLabel); } SmallVector<Expr*, 8> Values; ExpectAndConsume(tok::l_paren); do { auto ColonLoc = Tok.getLocation(); if(ConsumeIfPresent(tok::colon)) { auto E = ParseExpectedFollowupExpression(":"); if(E.isInvalid()) goto error; if(E.isUsable()) Values.push_back(RangeExpr::Create(Context, ColonLoc, nullptr, E.get())); } else { auto E = ParseExpectedExpression(); if(E.isInvalid()) goto error; ColonLoc = Tok.getLocation(); if(ConsumeIfPresent(tok::colon)) { if(!(IsPresent(tok::comma) || IsPresent(tok::r_paren))) { auto E2 = ParseExpectedFollowupExpression(":"); if(E2.isInvalid()) goto error; if(E.isUsable() || E2.isUsable()) Values.push_back(RangeExpr::Create(Context, ColonLoc, E.get(), E2.get())); } else { if(E.isUsable()) Values.push_back(RangeExpr::Create(Context, ColonLoc, E.get(), nullptr)); } } else { if(E.isUsable()) Values.push_back(E.get()); } } } while(ConsumeIfPresent(tok::comma)); if(ExpectAndConsume(tok::r_paren)) { ParseTrailingConstructName(); } else SkipUntilNextStatement(); return Actions.ActOnCaseStmt(Context, Loc, Values, StmtConstructName, StmtLabel); error: if(SkipUntil(tok::r_paren)) { ParseTrailingConstructName(); } else SkipUntilNextStatement(); return Actions.ActOnCaseStmt(Context, Loc, Values, StmtConstructName, StmtLabel); }
/// ParseSubstring - Parse a substring. /// /// R608: /// substring := /// parent-string ( substring-range ) /// R609: /// parent-string := /// scalar-variable-name /// or array-element /// or coindexed-named-object /// or scalar-structure-component /// or scalar-constant /// R610: /// substring-range := /// [ scalar-int-expr ] : [ scalar-int-expr ] ExprResult Parser::ParseSubstring(ExprResult Target) { ExprResult StartingPoint, EndPoint; auto Loc = ConsumeParen(); if(!ConsumeIfPresent(tok::colon)) { StartingPoint = ParseExpectedFollowupExpression("("); if(StartingPoint.isInvalid()) SkipUntil(tok::colon, true, true); Loc = Tok.getLocation(); if(!ExpectAndConsume(tok::colon, 0, "", tok::r_paren)) goto done; } if(!ConsumeIfPresent(tok::r_paren)) { EndPoint = ParseExpectedFollowupExpression(":"); if(EndPoint.isInvalid()) SkipUntil(tok::r_paren, true, true); ExpectAndConsume(tok::r_paren, 0, "", tok::r_paren); } done: return Actions.ActOnSubstringExpr(Context, Loc, Target.get(), StartingPoint.get(), EndPoint.get()); }
// Given a tag like e.g.: // <tag attr=">" /> // tries to find the closing '>' and not be confused by '>' that // are part of attribute value. We're not very strict here // Returns false if didn't find static bool SkipUntilTagEnd(const char*& s, const char *end) { while (s < end) { char c = *s++; if ('>' == c) { --s; return true; } if (('\'' == c) || ('"' == c)) { if (!SkipUntil(s, end, c)) return false; ++s; } } return false; }
/// ParseWHEREStmt - Parse the WHERE statement. /// /// [R743]: /// where-stmt := /// WHERE ( mask-expr ) where-assignment-stmt Parser::StmtResult Parser::ParseWhereStmt() { auto Loc = ConsumeToken(); ExpectAndConsume(tok::l_paren); auto Mask = ParseExpectedExpression(); if(!Mask.isInvalid()) ExpectAndConsume(tok::r_paren); else SkipUntil(tok::r_paren); if(!Tok.isAtStartOfStatement()) { auto Label = StmtLabel; StmtLabel = nullptr; auto Body = ParseActionStmt(); if(Body.isInvalid()) return Body; return Actions.ActOnWhereStmt(Context, Loc, Mask, Body, Label); } return Actions.ActOnWhereStmt(Context, Loc, Mask, StmtLabel); }
// FIXME: fixed-form THENconstructname Parser::StmtResult Parser::ParseElseIfStmt() { auto Loc = ConsumeToken(); ExprResult Condition; if (!ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "ELSE IF")) goto error; Condition = ParseExpectedFollowupExpression("("); if(Condition.isInvalid()) { if(!SkipUntil(tok::r_paren, true, true)) goto error; } if (!ExpectAndConsume(tok::r_paren)) goto error; if (!ExpectAndConsumeFixedFormAmbiguous(tok::kw_THEN, diag::err_expected_kw, "THEN")) goto error; ParseTrailingConstructName(); return Actions.ActOnElseIfStmt(Context, Loc, Condition, StmtConstructName, StmtLabel); error: SkipUntilNextStatement(); return Actions.ActOnElseIfStmt(Context, Loc, Condition, StmtConstructName, StmtLabel); }
// if s doesn't contain html entities, we just return it // if it contains html entities, we'll return string allocated // with alloc in which entities are converted to their values // Entities are encoded as utf8 in the result. // alloc can be NULL, in which case we'll allocate with malloc() const char *ResolveHtmlEntities(const char *s, const char *end, Allocator *alloc) { char * res = NULL; size_t resLen = 0; char * dst; const char *curr = s; for (;;) { bool found = SkipUntil(curr, end, '&'); if (!found) { if (!res) return s; // copy the remaining string MemAppend(dst, s, end - s); break; } if (!res) { // allocate memory for the result string // I'm banking that text after resolving entities will // be smaller than the original resLen = end - s + 8; // +8 just in case res = (char*)Allocator::Alloc(alloc, resLen); dst = res; } MemAppend(dst, s, curr - s); // curr points at '&' int rune = -1; const char *entEnd = ResolveHtmlEntity(curr + 1, end - curr - 1, rune); if (!entEnd) { // unknown entity, just copy the '&' MemAppend(dst, curr, 1); curr++; } else { str::Utf8Encode(dst, rune); curr = entEnd; } s = curr; } *dst = 0; CrashIf(dst >= res + resLen); return (const char*)res; }
/// ParseFunctionCallArgumentList - Parses an argument list to a call expression. ExprResult Parser::ParseFunctionCallArgumentList(SmallVectorImpl<Expr*> &Args, SourceLocation &RParenLoc) { if(!ExpectAndConsume(tok::l_paren)) return ExprError(); RParenLoc = getExpectedLoc(); if(ConsumeIfPresent(tok::r_paren)) return ExprResult(); auto PunctuationTok = "("; do { if(Tok.isAtStartOfStatement()) break; auto E = ParseExpectedFollowupExpression(PunctuationTok); if(E.isInvalid()) SkipUntil(tok::comma, tok::r_paren, true, true); else Args.push_back(E.get()); PunctuationTok = ","; } while (ConsumeIfPresent(tok::comma)); RParenLoc = getExpectedLoc(); ExpectAndConsume(tok::r_paren, 0, "", tok::r_paren); return ExprResult(); }
/// ParseArrauSubscript - Parse an Array Subscript Expression ExprResult Parser::ParseArraySubscript(ExprResult Target) { SmallVector<Expr*, 8> ExprList; auto Loc = ConsumeParen(); bool IgnoreRParen = false; auto PunctuationTok = "("; do { if(Tok.isAtStartOfStatement()) IgnoreRParen = true; auto E = ParseArraySection(PunctuationTok); if(E.isInvalid()) SkipUntil(tok::comma, tok::r_paren, true, true); if(E.isUsable()) ExprList.push_back(E.get()); PunctuationTok = ","; } while(ConsumeIfPresent(tok::comma)); auto RParenLoc = getExpectedLoc(); if(!IgnoreRParen) ExpectAndConsume(tok::r_paren, 0, "", tok::r_paren); return Actions.ActOnSubscriptExpr(Context, Loc, RParenLoc, Target.get(), ExprList); }
Parser::StmtResult Parser::ParseIfStmt() { auto Loc = ConsumeToken(); ExprResult Condition; if (!ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "IF")) goto error; Condition = ParseExpectedFollowupExpression("("); if(Condition.isInvalid()) { if(!SkipUntil(tok::r_paren, true, true)) goto error; } if (!ExpectAndConsume(tok::r_paren)) goto error; if(Features.FixedForm && !Tok.isAtStartOfStatement()) ReLexAmbiguousIdentifier(FixedFormAmbiguities.getMatcherForKeywordsAfterIF()); if (!ConsumeIfPresent(tok::kw_THEN)) { // if-stmt if(Tok.isAtStartOfStatement()) { Diag.Report(getExpectedLoc(), diag::err_expected_executable_stmt); return StmtError(); } auto Result = Actions.ActOnIfStmt(Context, Loc, Condition, StmtConstructName, StmtLabel); if(Result.isInvalid()) return Result; // NB: Don't give the action stmt my label StmtLabel = nullptr; auto Action = ParseActionStmt(); Actions.ActOnEndIfStmt(Context, Loc, ConstructName(SourceLocation(), nullptr), nullptr); return Action.isInvalid()? StmtError() : Result; } // if-construct. return Actions.ActOnIfStmt(Context, Loc, Condition, StmtConstructName, StmtLabel); error: SkipUntilNextStatement(); return Actions.ActOnIfStmt(Context, Loc, Condition, StmtConstructName, StmtLabel); }
/// ParseIMPLICITStmt - Parse the IMPLICIT statement. /// /// [R560]: /// implicit-stmt := /// IMPLICIT implicit-spec-list /// or IMPLICIT NONE Parser::StmtResult Parser::ParseIMPLICITStmt() { // Check if this is an assignment. if (IsNextToken(tok::equal)) return StmtResult(); auto Loc = ConsumeToken(); if (ConsumeIfPresent(tok::kw_NONE)) { auto Result = Actions.ActOnIMPLICIT(Context, Loc, StmtLabel); ExpectStatementEnd(); return Result; } SmallVector<Stmt*, 8> StmtList; while(true) { // FIXME: improved error recovery DeclSpec DS; if (ParseDeclarationTypeSpec(DS, false)) return StmtError(); if(!ExpectAndConsume(tok::l_paren)) { if(!SkipUntil(tok::l_paren)) break; } bool InnerError = false; while(true) { auto FirstLoc = Tok.getLocation(); auto First = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier, diag::err_expected_letter)) { if(!SkipUntil(tok::comma)) { InnerError = true; break; } continue; } if(First->getName().size() > 1) { Diag.Report(FirstLoc, diag::err_expected_letter); } const IdentifierInfo *Second = nullptr; if (ConsumeIfPresent(tok::minus)) { auto SecondLoc = Tok.getLocation(); Second = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier, diag::err_expected_letter)) { if(!SkipUntil(tok::comma)) { InnerError = true; break; } continue; } if(Second->getName().size() > 1) { Diag.Report(SecondLoc, diag::err_expected_letter); } } auto Stmt = Actions.ActOnIMPLICIT(Context, Loc, DS, std::make_pair(First, Second), nullptr); if(Stmt.isUsable()) StmtList.push_back(Stmt.take()); if(ConsumeIfPresent(tok::comma)) continue; break; } if(InnerError && Tok.isAtStartOfStatement()) break; if(!ExpectAndConsume(tok::r_paren)) { if(!SkipUntil(tok::r_paren)) break; } if(Tok.isAtStartOfStatement()) break; if(!ExpectAndConsume(tok::comma)) { if(!SkipUntil(tok::comma)) break; } } ExpectStatementEnd(); return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel); }
// Returns next part of html or NULL if finished HtmlToken *HtmlPullParser::Next() { if (currPos >= end) return NULL; Next: const char *start = currPos; if (*currPos != '<' || currPos + 1 < end && !IsValidTagStart(*++currPos)) { // this must be text between tags if (!SkipUntil(currPos, end, '<') && IsSpaceOnly(start, currPos)) { // ignore whitespace after the last tag return NULL; } currToken.SetText(start, currPos); return &currToken; } // '<' - tag begins ++start; // skip <? and <! (processing instructions and comments) if (start < end && (('?' == *start) || ('!' == *start))) { if ('!' == *start && start + 2 < end && str::StartsWith(start, "!--")) { currPos = start + 3; if (!SkipUntil(currPos, end, "-->")) { currToken.SetError(HtmlToken::UnclosedTag, start); return &currToken; } currPos += 2; } else if (!SkipUntil(currPos, end, '>')) { currToken.SetError(HtmlToken::UnclosedTag, start); return &currToken; } ++currPos; goto Next; } if (!SkipUntilTagEnd(currPos, end)) { currToken.SetError(HtmlToken::UnclosedTag, start); return &currToken; } CrashIf('>' != *currPos); if (currPos == start || currPos == start + 1 && *start == '/') { // skip empty tags (</>), because we're lenient ++currPos; goto Next; } if (('/' == *start) && ('/' == currPos[-1])) { // </foo/> currToken.SetError(HtmlToken::InvalidTag, start); } else if ('/' == *start) { // </foo> currToken.SetTag(HtmlToken::EndTag, start + 1, currPos); } else if ('/' == currPos[-1]) { // <foo/> currToken.SetTag(HtmlToken::EmptyElementTag, start, currPos - 1); } else { currToken.SetTag(HtmlToken::StartTag, start, currPos); } ++currPos; return &currToken; }