static void ErrorSkip (void) { /* List of tokens to skip */ static const token_t SkipList[] = { TOK_RPAREN, TOK_SEMI }; /* Skip until closing brace or semicolon */ SkipTokens (SkipList, sizeof (SkipList) / sizeof (SkipList[0])); /* If we have a closing brace, read it, otherwise bail out */ if (CurTok.Tok == TOK_RPAREN) { /* Read the two closing braces */ ConsumeRParen (); ConsumeRParen (); } }
void DoPragma (void) /* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */ { /* Skip the token itself */ NextToken (); /* We expect an opening paren */ if (!ConsumeLParen ()) { return; } /* String literal */ if (CurTok.Tok != TOK_SCONST) { /* Print a diagnostic */ Error ("String literal expected"); /* Try some smart error recovery: Skip tokens until we reach the * enclosing paren, or a semicolon. */ PragmaErrorSkip (); } else { /* Parse the _Pragma statement */ ParsePragma (); } /* Closing paren needed */ ConsumeRParen (); }
static TokList* CollectTokens (unsigned Start, unsigned Count) /* Read a list of tokens that is optionally enclosed in curly braces and * terminated by a right paren. For all tokens starting at the one with index * Start, and ending at (Start+Count-1), place them into a token list, and * return this token list. */ { /* Create the token list */ TokList* List = NewTokList (); /* Determine if the list is enclosed in curly braces. */ token_t Term = GetTokListTerm (TOK_RPAREN); /* Read the token list */ unsigned Current = 0; while (CurTok.Tok != Term) { /* Check for end of line or end of input */ if (TokIsSep (CurTok.Tok)) { Error ("Unexpected end of line"); return List; } /* Collect tokens in the given range */ if (Current >= Start && Current < Start+Count) { /* Add the current token to the list */ AddCurTok (List); } /* Get the next token */ ++Current; NextTok (); } /* Eat the terminator token */ NextTok (); /* If the list was enclosed in curly braces, we do expect now a right paren */ if (Term == TOK_RCURLY) { ConsumeRParen (); } /* Return the list of collected tokens */ return List; }
unsigned TestInParens (unsigned Label, int Invert) /* Evaluate a boolean test expression in parenthesis and jump depending on ** the result of the test * and on Invert. The function returns one of the ** TESTEXPR_xx codes defined above. If the jump is always true, a warning is ** output. */ { unsigned Result; /* Eat the parenthesis */ ConsumeLParen (); /* Do the test */ Result = Test (Label, Invert); /* Check for the closing brace */ ConsumeRParen (); /* Return the result of the expression */ return Result; }
void SwitchStatement (void) /* Handle a switch statement for chars with a cmp cascade for the selector */ { ExprDesc SwitchExpr; /* Switch statement expression */ CodeMark CaseCodeStart; /* Start of code marker */ CodeMark SwitchCodeStart;/* Start of switch code */ CodeMark SwitchCodeEnd; /* End of switch code */ unsigned ExitLabel; /* Exit label */ unsigned SwitchCodeLabel;/* Label for the switch code */ int HaveBreak = 0; /* True if the last statement had a break */ int RCurlyBrace; /* True if last token is right curly brace */ SwitchCtrl* OldSwitch; /* Pointer to old switch control data */ SwitchCtrl SwitchData; /* New switch data */ /* Eat the "switch" token */ NextToken (); /* Read the switch expression and load it into the primary. It must have * integer type. */ ConsumeLParen (); Expression0 (&SwitchExpr); if (!IsClassInt (SwitchExpr.Type)) { Error ("Switch quantity is not an integer"); /* To avoid any compiler errors, make the expression a valid int */ ED_MakeConstAbsInt (&SwitchExpr, 1); } ConsumeRParen (); /* Add a jump to the switch code. This jump is usually unnecessary, * because the switch code will moved up just behind the switch * expression. However, in rare cases, there's a label at the end of * the switch expression. This label will not get moved, so the code * jumps around the switch code, and after moving the switch code, * things look really weird. If we add a jump here, we will never have * a label attached to the current code position, and the jump itself * will get removed by the optimizer if it is unnecessary. */ SwitchCodeLabel = GetLocalLabel (); g_jump (SwitchCodeLabel); /* Remember the current code position. We will move the switch code * to this position later. */ GetCodePos (&CaseCodeStart); /* Setup the control structure, save the old and activate the new one */ SwitchData.Nodes = NewCollection (); SwitchData.ExprType = UnqualifiedType (SwitchExpr.Type[0].C); SwitchData.Depth = SizeOf (SwitchExpr.Type); SwitchData.DefaultLabel = 0; OldSwitch = Switch; Switch = &SwitchData; /* Get the exit label for the switch statement */ ExitLabel = GetLocalLabel (); /* Create a loop so we may use break. */ AddLoop (ExitLabel, 0); /* Make sure a curly brace follows */ if (CurTok.Tok != TOK_LCURLY) { Error ("`{' expected"); } /* Parse the following statement, which will actually be a compound * statement because of the curly brace at the current input position */ HaveBreak = Statement (&RCurlyBrace); /* Check if we had any labels */ if (CollCount (SwitchData.Nodes) == 0 && SwitchData.DefaultLabel == 0) { Warning ("No case labels"); } /* If the last statement did not have a break, we may have an open * label (maybe from an if or similar). Emitting code and then moving * this code to the top will also move the label to the top which is * wrong. So if the last statement did not have a break (which would * carry the label), add a jump to the exit. If it is useless, the * optimizer will remove it later. */ if (!HaveBreak) { g_jump (ExitLabel); } /* Remember the current position */ GetCodePos (&SwitchCodeStart); /* Output the switch code label */ g_defcodelabel (SwitchCodeLabel); /* Generate code */ if (SwitchData.DefaultLabel == 0) { /* No default label, use switch exit */ SwitchData.DefaultLabel = ExitLabel; } g_switch (SwitchData.Nodes, SwitchData.DefaultLabel, SwitchData.Depth); /* Move the code to the front */ GetCodePos (&SwitchCodeEnd); MoveCode (&SwitchCodeStart, &SwitchCodeEnd, &CaseCodeStart); /* Define the exit label */ g_defcodelabel (ExitLabel); /* Exit the loop */ DelLoop (); /* Switch back to the enclosing switch statement if any */ Switch = OldSwitch; /* Free the case value tree */ FreeCaseNodeColl (SwitchData.Nodes); /* If the case statement was (correctly) terminated by a closing curly * brace, skip it now. */ if (RCurlyBrace) { NextToken (); } }
static void ForStatement (void) /* Handle a 'for' statement */ { ExprDesc lval1; ExprDesc lval3; int HaveIncExpr; CodeMark IncExprStart; CodeMark IncExprEnd; int PendingToken; /* Get several local labels needed later */ unsigned TestLabel = GetLocalLabel (); unsigned BreakLabel = GetLocalLabel (); unsigned IncLabel = GetLocalLabel (); unsigned BodyLabel = GetLocalLabel (); /* Skip the FOR token */ NextToken (); /* Add the loop to the loop stack. A continue jumps to the start of the ** the increment condition. */ AddLoop (BreakLabel, IncLabel); /* Skip the opening paren */ ConsumeLParen (); /* Parse the initializer expression */ if (CurTok.Tok != TOK_SEMI) { Expression0 (&lval1); } ConsumeSemi (); /* Label for the test expressions */ g_defcodelabel (TestLabel); /* Parse the test expression */ if (CurTok.Tok != TOK_SEMI) { Test (BodyLabel, 1); g_jump (BreakLabel); } else { g_jump (BodyLabel); } ConsumeSemi (); /* Remember the start of the increment expression */ GetCodePos (&IncExprStart); /* Label for the increment expression */ g_defcodelabel (IncLabel); /* Parse the increment expression */ HaveIncExpr = (CurTok.Tok != TOK_RPAREN); if (HaveIncExpr) { Expression0 (&lval3); } /* Jump to the test */ g_jump (TestLabel); /* Remember the end of the increment expression */ GetCodePos (&IncExprEnd); /* Skip the closing paren */ ConsumeRParen (); /* Loop body */ g_defcodelabel (BodyLabel); Statement (&PendingToken); /* If we had an increment expression, move the code to the bottom of ** the loop. In this case we don't need to jump there at the end of ** the loop body. */ if (HaveIncExpr) { CodeMark Here; GetCodePos (&Here); MoveCode (&IncExprStart, &IncExprEnd, &Here); } else { /* Jump back to the increment expression */ g_jump (IncLabel); } /* Skip a pending token if we have one */ SkipPending (PendingToken); /* Declare the break label */ g_defcodelabel (BreakLabel); /* Remove the loop from the loop stack */ DelLoop (); }
void ParseAttribute (Declaration* D) /* Parse an additional __attribute__ modifier */ { /* Do we have an attribute? */ if (CurTok.Tok != TOK_ATTRIBUTE) { /* No attribute, bail out */ return; } /* Skip the attribute token */ NextToken (); /* Expect two(!) open braces */ ConsumeLParen (); ConsumeLParen (); /* Read a list of attributes */ while (1) { ident AttrName; const AttrDesc* Attr = 0; /* Identifier follows */ if (CurTok.Tok != TOK_IDENT) { /* No attribute name */ Error ("Attribute name expected"); /* Skip until end of attribute */ ErrorSkip (); /* Bail out */ return; } /* Map the attribute name to its id, then skip the identifier */ strcpy (AttrName, CurTok.Ident); Attr = FindAttribute (AttrName); NextToken (); /* Did we find a valid attribute? */ if (Attr) { /* Call the handler */ Attr->Handler (D); } else { /* Attribute not known, maybe typo */ Error ("Illegal attribute: `%s'", AttrName); /* Skip until end of attribute */ ErrorSkip (); /* Bail out */ return; } /* If a comma follows, there's a next attribute. Otherwise this is the ** end of the attribute list. */ if (CurTok.Tok != TOK_COMMA) { break; } NextToken (); } /* The declaration is terminated with two closing braces */ ConsumeRParen (); ConsumeRParen (); }
void GetEA (EffAddr* A) /* Parse an effective address, return the result in A */ { unsigned long Restrictions; /* Clear the output struct */ A->AddrModeSet = 0; A->Expr = 0; /* Handle an addressing size override */ switch (CurTok.Tok) { case TOK_OVERRIDE_ZP: Restrictions = AM65_DIR | AM65_DIR_X | AM65_DIR_Y; NextTok (); break; case TOK_OVERRIDE_ABS: Restrictions = AM65_ABS | AM65_ABS_X | AM65_ABS_Y; NextTok (); break; case TOK_OVERRIDE_FAR: Restrictions = AM65_ABS_LONG | AM65_ABS_LONG_X; NextTok (); break; default: Restrictions = ~0UL; /* None */ break; } /* Parse the effective address */ if (TokIsSep (CurTok.Tok)) { A->AddrModeSet = AM65_IMPLICIT; } else if (CurTok.Tok == TOK_HASH) { /* #val */ NextTok (); A->Expr = Expression (); A->AddrModeSet = AM65_ALL_IMM; } else if (CurTok.Tok == TOK_A) { NextTok (); A->AddrModeSet = AM65_ACCU; } else if (CurTok.Tok == TOK_LBRACK) { /* [dir] or [dir],y */ NextTok (); A->Expr = Expression (); Consume (TOK_RBRACK, "']' expected"); if (CurTok.Tok == TOK_COMMA) { /* [dir],y */ NextTok (); Consume (TOK_Y, "`Y' expected"); A->AddrModeSet = AM65_DIR_IND_LONG_Y; } else { /* [dir] */ A->AddrModeSet = AM65_DIR_IND_LONG; } } else if (CurTok.Tok == TOK_LPAREN) { /* One of the indirect modes */ NextTok (); A->Expr = Expression (); if (CurTok.Tok == TOK_COMMA) { /* (expr,X) or (rel,S),y */ NextTok (); if (CurTok.Tok == TOK_X) { /* (adr,x) */ NextTok (); A->AddrModeSet = AM65_ABS_X_IND | AM65_DIR_X_IND; ConsumeRParen (); } else if (CurTok.Tok == TOK_S) { /* (rel,s),y */ NextTok (); A->AddrModeSet = AM65_STACK_REL_IND_Y; ConsumeRParen (); ConsumeComma (); Consume (TOK_Y, "`Y' expected"); } else { Error ("Syntax error"); } } else { /* (adr) or (adr),y */ ConsumeRParen (); if (CurTok.Tok == TOK_COMMA) { /* (adr),y */ NextTok (); Consume (TOK_Y, "`Y' expected"); A->AddrModeSet = AM65_DIR_IND_Y; } else { /* (adr) */ A->AddrModeSet = AM65_ABS_IND | AM65_DIR_IND; } } } else { /* Remaining stuff: * * adr * adr,x * adr,y * adr,s */ A->Expr = Expression (); if (CurTok.Tok == TOK_COMMA) { NextTok (); switch (CurTok.Tok) { case TOK_X: A->AddrModeSet = AM65_ABS_LONG_X | AM65_ABS_X | AM65_DIR_X; NextTok (); break; case TOK_Y: A->AddrModeSet = AM65_ABS_Y | AM65_DIR_Y; NextTok (); break; case TOK_S: A->AddrModeSet = AM65_STACK_REL; NextTok (); break; default: Error ("Syntax error"); } } else { A->AddrModeSet = AM65_ABS_LONG | AM65_ABS | AM65_DIR; } } /* Apply addressing mode overrides */ A->AddrModeSet &= Restrictions; }
void MacDef (unsigned Style) /* Parse a macro definition */ { Macro* M; TokNode* N; int HaveParams; /* We expect a macro name here */ if (CurTok.Tok != TOK_IDENT) { Error ("Identifier expected"); MacSkipDef (Style); return; } else if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) { /* The identifier is a name of a 6502 instruction, which is not * allowed if not explicitly enabled. */ Error ("Cannot use an instruction as macro name"); MacSkipDef (Style); return; } /* Did we already define that macro? */ if (HT_Find (&MacroTab, &CurTok.SVal) != 0) { /* Macro is already defined */ Error ("A macro named `%m%p' is already defined", &CurTok.SVal); /* Skip tokens until we reach the final .endmacro */ MacSkipDef (Style); return; } /* Define the macro */ M = NewMacro (&CurTok.SVal, Style); /* Switch to raw token mode and skip the macro name */ EnterRawTokenMode (); NextTok (); /* If we have a DEFINE style macro, we may have parameters in braces, * otherwise we may have parameters without braces. */ if (Style == MAC_STYLE_CLASSIC) { HaveParams = 1; } else { if (CurTok.Tok == TOK_LPAREN) { HaveParams = 1; NextTok (); } else { HaveParams = 0; } } /* Parse the parameter list */ if (HaveParams) { while (CurTok.Tok == TOK_IDENT) { /* Create a struct holding the identifier */ IdDesc* I = NewIdDesc (&CurTok.SVal); /* Insert the struct into the list, checking for duplicate idents */ if (M->ParamCount == 0) { M->Params = I; } else { IdDesc* List = M->Params; while (1) { if (SB_Compare (&List->Id, &CurTok.SVal) == 0) { Error ("Duplicate symbol `%m%p'", &CurTok.SVal); } if (List->Next == 0) { break; } else { List = List->Next; } } List->Next = I; } ++M->ParamCount; /* Skip the name */ NextTok (); /* Maybe there are more params... */ if (CurTok.Tok == TOK_COMMA) { NextTok (); } else { break; } } } /* For class macros, we expect a separator token, for define style macros, * we expect the closing paren. */ if (Style == MAC_STYLE_CLASSIC) { ConsumeSep (); } else if (HaveParams) { ConsumeRParen (); } /* Preparse the macro body. We will read the tokens until we reach end of * file, or a .endmacro (or end of line for DEFINE style macros) and store * them into an token list internal to the macro. For classic macros, there * the .LOCAL command is detected and removed at this time. */ while (1) { /* Check for end of macro */ if (Style == MAC_STYLE_CLASSIC) { /* In classic macros, only .endmacro is allowed */ if (CurTok.Tok == TOK_ENDMACRO) { /* Done */ break; } /* May not have end of file in a macro definition */ if (CurTok.Tok == TOK_EOF) { Error ("`.ENDMACRO' expected"); goto Done; } } else { /* Accept a newline or end of file for new style macros */ if (TokIsSep (CurTok.Tok)) { break; } } /* Check for a .LOCAL declaration */ if (CurTok.Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) { while (1) { IdDesc* I; /* Skip .local or comma */ NextTok (); /* Need an identifer */ if (CurTok.Tok != TOK_IDENT && CurTok.Tok != TOK_LOCAL_IDENT) { Error ("Identifier expected"); SkipUntilSep (); break; } /* Put the identifier into the locals list and skip it */ I = NewIdDesc (&CurTok.SVal); I->Next = M->Locals; M->Locals = I; ++M->LocalCount; NextTok (); /* Check for end of list */ if (CurTok.Tok != TOK_COMMA) { break; } } /* We need end of line after the locals */ ConsumeSep (); continue; } /* Create a token node for the current token */ N = NewTokNode (); /* If the token is an identifier, check if it is a local parameter */ if (CurTok.Tok == TOK_IDENT) { unsigned Count = 0; IdDesc* I = M->Params; while (I) { if (SB_Compare (&I->Id, &CurTok.SVal) == 0) { /* Local param name, replace it */ N->T.Tok = TOK_MACPARAM; N->T.IVal = Count; break; } ++Count; I = I->Next; } } /* Insert the new token in the list */ if (M->TokCount == 0) { /* First token */ M->TokRoot = M->TokLast = N; } else { /* We have already tokens */ M->TokLast->Next = N; M->TokLast = N; } ++M->TokCount; /* Read the next token */ NextTok (); } /* Skip the .endmacro for a classic macro */ if (Style == MAC_STYLE_CLASSIC) { NextTok (); } /* Reset the Incomplete flag now that parsing is done */ M->Incomplete = 0; Done: /* Switch out of raw token mode */ LeaveRawTokenMode (); }