blob: 0a7ea58b0459a15ffbeea232af3449aaac2cabe8 [file] [log] [blame]
Chris Lattner4b009652007-07-25 00:24:17 +00001//===--- Parser.cpp - C Language Family Parser ----------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the Parser interfaces.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Parse/Parser.h"
15#include "clang/Parse/DeclSpec.h"
16#include "clang/Parse/Scope.h"
17using namespace clang;
18
19Parser::Parser(Preprocessor &pp, Action &actions)
20 : PP(pp), Actions(actions), Diags(PP.getDiagnostics()) {
21 Tok.setKind(tok::eof);
22 CurScope = 0;
23 NumCachedScopes = 0;
24 ParenCount = BracketCount = BraceCount = 0;
25}
26
27/// Out-of-line virtual destructor to provide home for Action class.
28Action::~Action() {}
29
30
31void Parser::Diag(SourceLocation Loc, unsigned DiagID,
32 const std::string &Msg) {
33 Diags.Report(Loc, DiagID, &Msg, 1);
34}
35
36/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'),
37/// this helper function matches and consumes the specified RHS token if
38/// present. If not present, it emits the specified diagnostic indicating
39/// that the parser failed to match the RHS of the token at LHSLoc. LHSName
40/// should be the name of the unmatched LHS token.
41SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok,
42 SourceLocation LHSLoc) {
43
44 if (Tok.getKind() == RHSTok)
45 return ConsumeAnyToken();
46
47 SourceLocation R = Tok.getLocation();
48 const char *LHSName = "unknown";
49 diag::kind DID = diag::err_parse_error;
50 switch (RHSTok) {
51 default: break;
52 case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break;
53 case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break;
54 case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break;
55 case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break;
56 }
57 Diag(Tok, DID);
58 Diag(LHSLoc, diag::err_matching, LHSName);
59 SkipUntil(RHSTok);
60 return R;
61}
62
63/// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the
64/// input. If so, it is consumed and false is returned.
65///
66/// If the input is malformed, this emits the specified diagnostic. Next, if
67/// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is
68/// returned.
69bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
70 const char *Msg, tok::TokenKind SkipToTok) {
71 if (Tok.getKind() == ExpectedTok) {
72 ConsumeAnyToken();
73 return false;
74 }
75
76 Diag(Tok, DiagID, Msg);
77 if (SkipToTok != tok::unknown)
78 SkipUntil(SkipToTok);
79 return true;
80}
81
82//===----------------------------------------------------------------------===//
83// Error recovery.
84//===----------------------------------------------------------------------===//
85
86/// SkipUntil - Read tokens until we get to the specified token, then consume
87/// it (unless DontConsume is true). Because we cannot guarantee that the
88/// token will ever occur, this skips to the next token, or to some likely
89/// good stopping point. If StopAtSemi is true, skipping will stop at a ';'
90/// character.
91///
92/// If SkipUntil finds the specified token, it returns true, otherwise it
93/// returns false.
94bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
95 bool StopAtSemi, bool DontConsume) {
96 // We always want this function to skip at least one token if the first token
97 // isn't T and if not at EOF.
98 bool isFirstTokenSkipped = true;
99 while (1) {
100 // If we found one of the tokens, stop and return true.
101 for (unsigned i = 0; i != NumToks; ++i) {
102 if (Tok.getKind() == Toks[i]) {
103 if (DontConsume) {
104 // Noop, don't consume the token.
105 } else {
106 ConsumeAnyToken();
107 }
108 return true;
109 }
110 }
111
112 switch (Tok.getKind()) {
113 case tok::eof:
114 // Ran out of tokens.
115 return false;
116
117 case tok::l_paren:
118 // Recursively skip properly-nested parens.
119 ConsumeParen();
120 SkipUntil(tok::r_paren, false);
121 break;
122 case tok::l_square:
123 // Recursively skip properly-nested square brackets.
124 ConsumeBracket();
125 SkipUntil(tok::r_square, false);
126 break;
127 case tok::l_brace:
128 // Recursively skip properly-nested braces.
129 ConsumeBrace();
130 SkipUntil(tok::r_brace, false);
131 break;
132
133 // Okay, we found a ']' or '}' or ')', which we think should be balanced.
134 // Since the user wasn't looking for this token (if they were, it would
135 // already be handled), this isn't balanced. If there is a LHS token at a
136 // higher level, we will assume that this matches the unbalanced token
137 // and return it. Otherwise, this is a spurious RHS token, which we skip.
138 case tok::r_paren:
139 if (ParenCount && !isFirstTokenSkipped)
140 return false; // Matches something.
141 ConsumeParen();
142 break;
143 case tok::r_square:
144 if (BracketCount && !isFirstTokenSkipped)
145 return false; // Matches something.
146 ConsumeBracket();
147 break;
148 case tok::r_brace:
149 if (BraceCount && !isFirstTokenSkipped)
150 return false; // Matches something.
151 ConsumeBrace();
152 break;
153
154 case tok::string_literal:
155 case tok::wide_string_literal:
156 ConsumeStringToken();
157 break;
158 case tok::semi:
159 if (StopAtSemi)
160 return false;
161 // FALL THROUGH.
162 default:
163 // Skip this token.
164 ConsumeToken();
165 break;
166 }
167 isFirstTokenSkipped = false;
168 }
169}
170
171//===----------------------------------------------------------------------===//
172// Scope manipulation
173//===----------------------------------------------------------------------===//
174
175/// EnterScope - Start a new scope.
176void Parser::EnterScope(unsigned ScopeFlags) {
177 if (NumCachedScopes) {
178 Scope *N = ScopeCache[--NumCachedScopes];
179 N->Init(CurScope, ScopeFlags);
180 CurScope = N;
181 } else {
182 CurScope = new Scope(CurScope, ScopeFlags);
183 }
184}
185
186/// ExitScope - Pop a scope off the scope stack.
187void Parser::ExitScope() {
188 assert(CurScope && "Scope imbalance!");
189
190 // Inform the actions module that this scope is going away.
191 Actions.PopScope(Tok.getLocation(), CurScope);
192
193 Scope *OldScope = CurScope;
194 CurScope = OldScope->getParent();
195
196 if (NumCachedScopes == ScopeCacheSize)
197 delete OldScope;
198 else
199 ScopeCache[NumCachedScopes++] = OldScope;
200}
201
202
203
204
205//===----------------------------------------------------------------------===//
206// C99 6.9: External Definitions.
207//===----------------------------------------------------------------------===//
208
209Parser::~Parser() {
210 // If we still have scopes active, delete the scope tree.
211 delete CurScope;
212
213 // Free the scope cache.
214 for (unsigned i = 0, e = NumCachedScopes; i != e; ++i)
215 delete ScopeCache[i];
216}
217
218/// Initialize - Warm up the parser.
219///
220void Parser::Initialize() {
221 // Prime the lexer look-ahead.
222 ConsumeToken();
223
Chris Lattnera7549902007-08-26 06:24:45 +0000224 // Create the translation unit scope. Install it as the current scope.
Chris Lattner4b009652007-07-25 00:24:17 +0000225 assert(CurScope == 0 && "A scope is already active?");
Chris Lattnera7549902007-08-26 06:24:45 +0000226 EnterScope(Scope::DeclScope);
227
Chris Lattner4b009652007-07-25 00:24:17 +0000228 // Install builtin types.
229 // TODO: Move this someplace more useful.
230 {
231 const char *Dummy;
232
233 //__builtin_va_list
234 DeclSpec DS;
235 bool Error = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, SourceLocation(),
236 Dummy);
237
238 // TODO: add a 'TST_builtin' type?
239 Error |= DS.SetTypeSpecType(DeclSpec::TST_int, SourceLocation(), Dummy);
240 assert(!Error && "Error setting up __builtin_va_list!");
241
242 Declarator D(DS, Declarator::FileContext);
243 D.SetIdentifier(PP.getIdentifierInfo("__builtin_va_list"),SourceLocation());
244 Actions.ParseDeclarator(CurScope, D, 0, 0);
245 }
246
Chris Lattner7bdc85d2007-08-25 05:47:03 +0000247 if (Tok.getKind() == tok::eof &&
248 !getLang().CPlusPlus) // Empty source file is an extension in C
Chris Lattner4b009652007-07-25 00:24:17 +0000249 Diag(Tok, diag::ext_empty_source_file);
Chris Lattner32352462007-08-29 22:54:08 +0000250
251 // Initialization for Objective-C context sensitive keywords recognition.
252 // Referenced in Parser::isObjCTypeQualifier.
253 if (getLang().ObjC1) {
254 ObjcTypeQuals[objc_in] = &PP.getIdentifierTable().get("in");
255 ObjcTypeQuals[objc_out] = &PP.getIdentifierTable().get("out");
256 ObjcTypeQuals[objc_inout] = &PP.getIdentifierTable().get("inout");
257 ObjcTypeQuals[objc_oneway] = &PP.getIdentifierTable().get("oneway");
258 ObjcTypeQuals[objc_bycopy] = &PP.getIdentifierTable().get("bycopy");
259 ObjcTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref");
260 }
Fariborz Jahanian6668b8c2007-08-31 16:11:31 +0000261 if (getLang().ObjC2) {
262 ObjcPropertyAttrs[objc_readonly] = &PP.getIdentifierTable().get("readonly");
263 ObjcPropertyAttrs[objc_getter] = &PP.getIdentifierTable().get("getter");
264 ObjcPropertyAttrs[objc_setter] = &PP.getIdentifierTable().get("setter");
265 ObjcPropertyAttrs[objc_assign] = &PP.getIdentifierTable().get("assign");
266 ObjcPropertyAttrs[objc_readwrite] =
267 &PP.getIdentifierTable().get("readwrite");
268 ObjcPropertyAttrs[objc_retain] = &PP.getIdentifierTable().get("retain");
269 ObjcPropertyAttrs[objc_copy] = &PP.getIdentifierTable().get("copy");
270 ObjcPropertyAttrs[objc_nonatomic] =
271 &PP.getIdentifierTable().get("nonatomic");
272 }
Chris Lattner4b009652007-07-25 00:24:17 +0000273}
274
275/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
276/// action tells us to. This returns true if the EOF was encountered.
277bool Parser::ParseTopLevelDecl(DeclTy*& Result) {
278 Result = 0;
279 if (Tok.getKind() == tok::eof) return true;
280
281 Result = ParseExternalDeclaration();
282 return false;
283}
284
285/// Finalize - Shut down the parser.
286///
287void Parser::Finalize() {
288 ExitScope();
289 assert(CurScope == 0 && "Scope imbalance!");
290}
291
292/// ParseTranslationUnit:
293/// translation-unit: [C99 6.9]
294/// external-declaration
295/// translation-unit external-declaration
296void Parser::ParseTranslationUnit() {
297 Initialize();
298
299 DeclTy *Res;
300 while (!ParseTopLevelDecl(Res))
301 /*parse them all*/;
302
303 Finalize();
304}
305
306/// ParseExternalDeclaration:
307/// external-declaration: [C99 6.9]
Chris Lattner06f4e752007-08-10 20:57:02 +0000308/// function-definition
309/// declaration
Chris Lattner4b009652007-07-25 00:24:17 +0000310/// [EXT] ';'
311/// [GNU] asm-definition
Chris Lattner06f4e752007-08-10 20:57:02 +0000312/// [GNU] __extension__ external-declaration
Chris Lattner4b009652007-07-25 00:24:17 +0000313/// [OBJC] objc-class-definition
314/// [OBJC] objc-class-declaration
315/// [OBJC] objc-alias-declaration
316/// [OBJC] objc-protocol-definition
317/// [OBJC] objc-method-definition
318/// [OBJC] @end
319///
320/// [GNU] asm-definition:
321/// simple-asm-expr ';'
322///
323Parser::DeclTy *Parser::ParseExternalDeclaration() {
324 switch (Tok.getKind()) {
325 case tok::semi:
326 Diag(Tok, diag::ext_top_level_semi);
327 ConsumeToken();
328 // TODO: Invoke action for top-level semicolon.
329 return 0;
Chris Lattner06f4e752007-08-10 20:57:02 +0000330 case tok::kw___extension__: {
331 ConsumeToken();
332 // FIXME: Disable extension warnings.
333 DeclTy *RV = ParseExternalDeclaration();
334 // FIXME: Restore extension warnings.
335 return RV;
336 }
Chris Lattner4b009652007-07-25 00:24:17 +0000337 case tok::kw_asm:
338 ParseSimpleAsm();
339 ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
340 "top-level asm block");
341 // TODO: Invoke action for top-level asm.
342 return 0;
343 case tok::at:
344 // @ is not a legal token unless objc is enabled, no need to check.
345 ParseObjCAtDirectives();
346 return 0;
347 case tok::minus:
348 if (getLang().ObjC1) {
Steve Naroff72f17fb2007-08-22 22:17:26 +0000349 ParseObjCInstanceMethodDefinition();
Chris Lattner4b009652007-07-25 00:24:17 +0000350 } else {
351 Diag(Tok, diag::err_expected_external_declaration);
352 ConsumeToken();
353 }
354 return 0;
355 case tok::plus:
356 if (getLang().ObjC1) {
Steve Naroff72f17fb2007-08-22 22:17:26 +0000357 ParseObjCClassMethodDefinition();
Chris Lattner4b009652007-07-25 00:24:17 +0000358 } else {
359 Diag(Tok, diag::err_expected_external_declaration);
360 ConsumeToken();
361 }
362 return 0;
Chris Lattnerf7b2e552007-08-25 06:57:03 +0000363 case tok::kw_namespace:
Chris Lattner4b009652007-07-25 00:24:17 +0000364 case tok::kw_typedef:
Chris Lattner9c135722007-08-25 18:15:16 +0000365 // A function definition cannot start with a these keywords.
Chris Lattner4b009652007-07-25 00:24:17 +0000366 return ParseDeclaration(Declarator::FileContext);
367 default:
368 // We can't tell whether this is a function-definition or declaration yet.
369 return ParseDeclarationOrFunctionDefinition();
370 }
371}
372
373/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or
374/// a declaration. We can't tell which we have until we read up to the
375/// compound-statement in function-definition.
376///
377/// function-definition: [C99 6.9.1]
378/// declaration-specifiers[opt] declarator declaration-list[opt]
Chris Lattneraac973e2007-08-22 06:06:56 +0000379/// compound-statement
Chris Lattner4b009652007-07-25 00:24:17 +0000380/// declaration: [C99 6.7]
Chris Lattneraac973e2007-08-22 06:06:56 +0000381/// declaration-specifiers init-declarator-list[opt] ';'
382/// [!C99] init-declarator-list ';' [TODO: warn in c99 mode]
Chris Lattner4b009652007-07-25 00:24:17 +0000383/// [OMP] threadprivate-directive [TODO]
384///
385Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() {
386 // Parse the common declaration-specifiers piece.
387 DeclSpec DS;
388 ParseDeclarationSpecifiers(DS);
389
390 // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
391 // declaration-specifiers init-declarator-list[opt] ';'
392 if (Tok.getKind() == tok::semi) {
393 ConsumeToken();
394 return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
395 }
396
Steve Naroffa7f62782007-08-23 19:56:30 +0000397 // ObjC2 allows prefix attributes on class interfaces.
398 if (getLang().ObjC2 && Tok.getKind() == tok::at) {
Steve Narofffb367882007-08-20 21:31:48 +0000399 SourceLocation AtLoc = ConsumeToken(); // the "@"
400 if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_interface)
401 return ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes());
402 }
403
Chris Lattner4b009652007-07-25 00:24:17 +0000404 // Parse the first declarator.
405 Declarator DeclaratorInfo(DS, Declarator::FileContext);
406 ParseDeclarator(DeclaratorInfo);
407 // Error parsing the declarator?
408 if (DeclaratorInfo.getIdentifier() == 0) {
409 // If so, skip until the semi-colon or a }.
410 SkipUntil(tok::r_brace, true);
411 if (Tok.getKind() == tok::semi)
412 ConsumeToken();
413 return 0;
414 }
415
416 // If the declarator is the start of a function definition, handle it.
417 if (Tok.getKind() == tok::equal || // int X()= -> not a function def
418 Tok.getKind() == tok::comma || // int X(), -> not a function def
419 Tok.getKind() == tok::semi || // int X(); -> not a function def
420 Tok.getKind() == tok::kw_asm || // int X() __asm__ -> not a fn def
421 Tok.getKind() == tok::kw___attribute) {// int X() __attr__ -> not a fn def
422 // FALL THROUGH.
423 } else if (DeclaratorInfo.isFunctionDeclarator() &&
424 (Tok.getKind() == tok::l_brace || // int X() {}
425 isDeclarationSpecifier())) { // int X(f) int f; {}
426 return ParseFunctionDefinition(DeclaratorInfo);
427 } else {
428 if (DeclaratorInfo.isFunctionDeclarator())
429 Diag(Tok, diag::err_expected_fn_body);
430 else
431 Diag(Tok, diag::err_expected_after_declarator);
432 SkipUntil(tok::semi);
433 return 0;
434 }
435
436 // Parse the init-declarator-list for a normal declaration.
437 return ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
438}
439
440/// ParseFunctionDefinition - We parsed and verified that the specified
441/// Declarator is well formed. If this is a K&R-style function, read the
442/// parameters declaration-list, then start the compound-statement.
443///
444/// declaration-specifiers[opt] declarator declaration-list[opt]
445/// compound-statement [TODO]
446///
447Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) {
448 const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0);
449 assert(FnTypeInfo.Kind == DeclaratorChunk::Function &&
450 "This isn't a function declarator!");
451 const DeclaratorChunk::FunctionTypeInfo &FTI = FnTypeInfo.Fun;
452
453 // If this declaration was formed with a K&R-style identifier list for the
454 // arguments, parse declarations for all of the args next.
455 // int foo(a,b) int a; float b; {}
456 if (!FTI.hasPrototype && FTI.NumArgs != 0)
457 ParseKNRParamDeclarations(D);
458
459 // Enter a scope for the function body.
Chris Lattnera7549902007-08-26 06:24:45 +0000460 EnterScope(Scope::FnScope|Scope::DeclScope);
Chris Lattner4b009652007-07-25 00:24:17 +0000461
462 // Tell the actions module that we have entered a function definition with the
463 // specified Declarator for the function.
464 DeclTy *Res = Actions.ParseStartOfFunctionDef(CurScope, D);
465
466
467 // We should have an opening brace now.
468 if (Tok.getKind() != tok::l_brace) {
469 Diag(Tok, diag::err_expected_fn_body);
470
471 // Skip over garbage, until we get to '{'. Don't eat the '{'.
472 SkipUntil(tok::l_brace, true, true);
473
474 // If we didn't find the '{', bail out.
475 if (Tok.getKind() != tok::l_brace) {
476 ExitScope();
477 return 0;
478 }
479 }
480
481 // Do not enter a scope for the brace, as the arguments are in the same scope
482 // (the function body) as the body itself. Instead, just read the statement
483 // list and put it into a CompoundStmt for safe keeping.
484 StmtResult FnBody = ParseCompoundStatementBody();
485 if (FnBody.isInvalid) {
486 ExitScope();
487 return 0;
488 }
489
490 // Leave the function body scope.
491 ExitScope();
492
493 // TODO: Pass argument information.
494 return Actions.ParseFunctionDefBody(Res, FnBody.Val);
495}
496
497/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides
498/// types for a function with a K&R-style identifier list for arguments.
499void Parser::ParseKNRParamDeclarations(Declarator &D) {
500 // We know that the top-level of this declarator is a function.
501 DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
502
503 // Read all the argument declarations.
504 while (isDeclarationSpecifier()) {
505 SourceLocation DSStart = Tok.getLocation();
506
507 // Parse the common declaration-specifiers piece.
508 DeclSpec DS;
509 ParseDeclarationSpecifiers(DS);
510
511 // C99 6.9.1p6: 'each declaration in the declaration list shall have at
512 // least one declarator'.
513 // NOTE: GCC just makes this an ext-warn. It's not clear what it does with
514 // the declarations though. It's trivial to ignore them, really hard to do
515 // anything else with them.
516 if (Tok.getKind() == tok::semi) {
517 Diag(DSStart, diag::err_declaration_does_not_declare_param);
518 ConsumeToken();
519 continue;
520 }
521
522 // C99 6.9.1p6: Declarations shall contain no storage-class specifiers other
523 // than register.
524 if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
525 DS.getStorageClassSpec() != DeclSpec::SCS_register) {
526 Diag(DS.getStorageClassSpecLoc(),
527 diag::err_invalid_storage_class_in_func_decl);
528 DS.ClearStorageClassSpecs();
529 }
530 if (DS.isThreadSpecified()) {
531 Diag(DS.getThreadSpecLoc(),
532 diag::err_invalid_storage_class_in_func_decl);
533 DS.ClearStorageClassSpecs();
534 }
535
536 // Parse the first declarator attached to this declspec.
537 Declarator ParmDeclarator(DS, Declarator::KNRTypeListContext);
538 ParseDeclarator(ParmDeclarator);
539
540 // Handle the full declarator list.
541 while (1) {
542 DeclTy *AttrList;
543 // If attributes are present, parse them.
544 if (Tok.getKind() == tok::kw___attribute)
545 // FIXME: attach attributes too.
546 AttrList = ParseAttributes();
547
548 // Ask the actions module to compute the type for this declarator.
549 Action::TypeResult TR =
550 Actions.ParseParamDeclaratorType(CurScope, ParmDeclarator);
551 if (!TR.isInvalid &&
552 // A missing identifier has already been diagnosed.
553 ParmDeclarator.getIdentifier()) {
554
555 // Scan the argument list looking for the correct param to apply this
556 // type.
557 for (unsigned i = 0; ; ++i) {
558 // C99 6.9.1p6: those declarators shall declare only identifiers from
559 // the identifier list.
560 if (i == FTI.NumArgs) {
561 Diag(ParmDeclarator.getIdentifierLoc(), diag::err_no_matching_param,
562 ParmDeclarator.getIdentifier()->getName());
563 break;
564 }
565
566 if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) {
567 // Reject redefinitions of parameters.
568 if (FTI.ArgInfo[i].TypeInfo) {
569 Diag(ParmDeclarator.getIdentifierLoc(),
570 diag::err_param_redefinition,
571 ParmDeclarator.getIdentifier()->getName());
572 } else {
573 FTI.ArgInfo[i].TypeInfo = TR.Val;
574 }
575 break;
576 }
577 }
578 }
579
580 // If we don't have a comma, it is either the end of the list (a ';') or
581 // an error, bail out.
582 if (Tok.getKind() != tok::comma)
583 break;
584
585 // Consume the comma.
586 ConsumeToken();
587
588 // Parse the next declarator.
589 ParmDeclarator.clear();
590 ParseDeclarator(ParmDeclarator);
591 }
592
593 if (Tok.getKind() == tok::semi) {
594 ConsumeToken();
595 } else {
596 Diag(Tok, diag::err_parse_error);
597 // Skip to end of block or statement
598 SkipUntil(tok::semi, true);
599 if (Tok.getKind() == tok::semi)
600 ConsumeToken();
601 }
602 }
603
604 // The actions module must verify that all arguments were declared.
605}
606
607
608/// ParseAsmStringLiteral - This is just a normal string-literal, but is not
609/// allowed to be a wide string, and is not subject to character translation.
610///
611/// [GNU] asm-string-literal:
612/// string-literal
613///
614void Parser::ParseAsmStringLiteral() {
615 if (!isTokenStringLiteral()) {
616 Diag(Tok, diag::err_expected_string_literal);
617 return;
618 }
619
620 ExprResult Res = ParseStringLiteralExpression();
621 if (Res.isInvalid) return;
622
623 // TODO: Diagnose: wide string literal in 'asm'
624}
625
626/// ParseSimpleAsm
627///
628/// [GNU] simple-asm-expr:
629/// 'asm' '(' asm-string-literal ')'
630///
631void Parser::ParseSimpleAsm() {
632 assert(Tok.getKind() == tok::kw_asm && "Not an asm!");
633 ConsumeToken();
634
635 if (Tok.getKind() != tok::l_paren) {
636 Diag(Tok, diag::err_expected_lparen_after, "asm");
637 return;
638 }
639
640 SourceLocation Loc = ConsumeParen();
641
642 ParseAsmStringLiteral();
643
644 MatchRHSPunctuation(tok::r_paren, Loc);
645}
646