void ParseRepeat (void) /* Parse and handle the .REPEAT statement */ { char* Name; TokList* List; /* Repeat count follows */ long RepCount = ConstExpression (); if (RepCount < 0) { Error ("Range error"); RepCount = 0; } /* Optional there is a comma and a counter variable */ Name = 0; if (Tok == TOK_COMMA) { /* Skip the comma */ NextTok (); /* Check for an identifier */ if (Tok != TOK_IDENT) { ErrorSkip ("Identifier expected"); } else { /* Remember the name and skip it */ SB_Terminate (&SVal); Name = xstrdup (SB_GetConstBuf (&SVal)); NextTok (); } } /* Separator */ ConsumeSep (); /* Read the token list */ List = CollectRepeatTokens (); /* If we had an error, bail out */ if (List == 0) { xfree (Name); return; } /* Update the token list for replay */ List->RepMax = (unsigned) RepCount; List->Data = Name; List->Check = RepeatTokenCheck; /* If the list is empty, or repeat count zero, there is nothing * to repeat. */ if (List->Count == 0 || RepCount == 0) { FreeTokList (List); return; } /* Read input from the repeat descriptor */ PushTokList (List, ".REPEAT"); }
static void FuncString (void) /* Handle the .STRING function */ { StrBuf Buf = STATIC_STRBUF_INITIALIZER; /* Skip it */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* Accept identifiers or numeric expressions */ if (CurTok.Tok == TOK_LOCAL_IDENT) { /* Save the identifier, then skip it */ SB_Copy (&Buf, &CurTok.SVal); NextTok (); } else if (CurTok.Tok == TOK_NAMESPACE || CurTok.Tok == TOK_IDENT) { /* Parse a fully qualified symbol name. We cannot use * ParseScopedSymName here since the name may be invalid. */ int NameSpace; do { NameSpace = (CurTok.Tok == TOK_NAMESPACE); if (NameSpace) { SB_AppendStr (&Buf, "::"); } else { SB_Append (&Buf, &CurTok.SVal); } NextTok (); } while ((NameSpace != 0 && CurTok.Tok == TOK_IDENT) || (NameSpace == 0 && CurTok.Tok == TOK_NAMESPACE)); } else { /* Numeric expression */ long Val = ConstExpression (); SB_Printf (&Buf, "%ld", Val); } /* We expect a closing parenthesis, but will not skip it but replace it * by the string token just created. */ if (CurTok.Tok != TOK_RPAREN) { Error ("`)' expected"); } else { CurTok.Tok = TOK_STRCON; SB_Copy (&CurTok.SVal, &Buf); SB_Terminate (&CurTok.SVal); } /* Free string memory */ SB_Done (&Buf); }
static void FuncRight (void) /* Handle the .RIGHT function */ { long Count; TokList* List; /* Skip it */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* Count argument. Correct negative counts to zero. */ Count = ConstExpression (); if (Count < 0) { Count = 0; } ConsumeComma (); /* Read the complete token list */ List = CollectTokens (0, 9999); /* Delete tokens from the list until Count tokens are remaining */ while (List->Count > (unsigned) Count) { /* Get the first node */ TokNode* T = List->Root; /* Remove it from the list */ List->Root = List->Root->Next; /* Free the node */ FreeTokNode (T); /* Corrent the token counter */ List->Count--; } /* Since we want to insert the list before the now current token, we have * to save the current token in some way and then skip it. To do this, we * will add the current token at the end of the token list (so the list * will never be empty), push the token list, and then skip the current * token. This will replace the current token by the first token from the * list (which will be the old current token in case the list was empty). */ AddCurTok (List); /* Insert it into the scanner feed */ PushTokList (List, ".RIGHT"); /* Skip the current token */ NextTok (); }
static void FuncConcat (void) /* Handle the .CONCAT function */ { StrBuf Buf = STATIC_STRBUF_INITIALIZER; /* Skip it */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* Concatenate any number of strings */ while (1) { /* Next token must be a string */ if (!LookAtStrCon ()) { SB_Done (&Buf); return; } /* Append the string */ SB_Append (&Buf, &CurTok.SVal); /* Skip the string token */ NextTok (); /* Comma means another argument */ if (CurTok.Tok == TOK_COMMA) { NextTok (); } else { /* Done */ break; } } /* We expect a closing parenthesis, but will not skip it but replace it * by the string token just created. */ if (CurTok.Tok != TOK_RPAREN) { Error ("`)' expected"); } else { CurTok.Tok = TOK_STRCON; SB_Copy (&CurTok.SVal, &Buf); SB_Terminate (&CurTok.SVal); } /* Free the string buffer */ SB_Done (&Buf); }
static void FuncMid (void) /* Handle the .MID function */ { long Start; long Count; TokList* List; /* Skip it */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* Start argument. Since the start argument can get negative with * expressions like ".tcount(arg)-2", we correct it to zero silently. */ Start = ConstExpression (); if (Start < 0 || Start > 100) { Start = 0; } ConsumeComma (); /* Count argument. Similar as above, we will accept negative counts and * correct them to zero silently. */ Count = ConstExpression (); if (Count < 0) { Count = 0; } ConsumeComma (); /* Read the token list */ List = CollectTokens ((unsigned) Start, (unsigned) Count); /* Since we want to insert the list before the now current token, we have * to save the current token in some way and then skip it. To do this, we * will add the current token at the end of the token list (so the list * will never be empty), push the token list, and then skip the current * token. This will replace the current token by the first token from the * list (which will be the old current token in case the list was empty). */ AddCurTok (List); /* Insert it into the scanner feed */ PushTokList (List, ".MID"); /* Skip the current token */ NextTok (); }
static TokList* CollectRepeatTokens (void) /* Collect all tokens inside the .REPEAT body in a token list and return * this list. In case of errors, NULL is returned. */ { /* Create the token list */ TokList* List = NewTokList (); /* Read the token list */ unsigned Repeats = 0; while (Repeats != 0 || Tok != TOK_ENDREP) { /* Check for end of input */ if (Tok == TOK_EOF) { Error ("Unexpected end of file"); FreeTokList (List); return 0; } /* If we find a token that is equal to the repeat counter name, * replace it by a REPCOUNTER token. This way we have to do strcmps * only once for each identifier, and not for each expansion. * Note: This will fail for nested repeats using the same repeat * counter name, but */ /* Collect all tokens in the list */ AddCurTok (List); /* Check for and count nested .REPEATs */ if (Tok == TOK_REPEAT) { ++Repeats; } else if (Tok == TOK_ENDREP) { --Repeats; } /* Get the next token */ NextTok (); } /* Eat the closing .ENDREP */ NextTok (); /* Return the list of collected tokens */ return List; }
int DSNLEXER::NeedSYMBOLorNUMBER() throw( IO_ERROR ) { int tok = NextTok(); if( !IsSymbol( tok ) && tok!=DSN_NUMBER ) Expecting( "symbol|number" ); return tok; }
int DSNLEXER::NeedSYMBOL() throw( IO_ERROR ) { int tok = NextTok(); if( !IsSymbol( tok ) ) Expecting( DSN_SYMBOL ); return tok; }
void SkipUntilSep (void) /* Skip tokens until we reach a line separator or end of file */ { while (!TokIsSep (CurTok.Tok)) { NextTok (); } }
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; }
void Consume (token_t Expected, const char* ErrMsg) /* Consume Expected, print an error if we don't find it */ { if (CurTok.Tok == Expected) { NextTok (); } else { Error ("%s", ErrMsg); } }
void ConsumeSep (void) /* Consume a separator token */ { /* We expect a separator token */ ExpectSep (); /* If we are at end of line, skip it */ if (CurTok.Tok == TOK_SEP) { NextTok (); } }
int DSNLEXER::NeedNUMBER( const char* aExpectation ) throw( IO_ERROR ) { int tok = NextTok(); if( tok != DSN_NUMBER ) { wxString errText; errText.Printf( _("need a NUMBER for '%s'"), wxString::FromUTF8( aExpectation ).GetData() ); THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); } return tok; }
enum Token GetTokListTerm (enum Token Term) /* Determine if the following token list is enclosed in curly braces. This is * the case if the next token is the opening brace. If so, skip it and return * a closing brace, otherwise return Term. */ { if (Tok == TOK_LCURLY) { NextTok (); return TOK_RCURLY; } else { return Term; } }
static TokList* CollectRepeatTokens (void) /* Collect all tokens inside the .REPEAT body in a token list and return * this list. In case of errors, NULL is returned. */ { /* Create the token list */ TokList* List = NewTokList (); /* Read the token list */ unsigned Repeats = 0; while (Repeats != 0 || CurTok.Tok != TOK_ENDREP) { /* Check for end of input */ if (CurTok.Tok == TOK_EOF) { Error ("Unexpected end of file"); FreeTokList (List); return 0; } /* Collect all tokens in the list */ AddCurTok (List); /* Check for and count nested .REPEATs */ if (CurTok.Tok == TOK_REPEAT) { ++Repeats; } else if (CurTok.Tok == TOK_ENDREP) { --Repeats; } /* Get the next token */ NextTok (); } /* Eat the closing .ENDREP */ NextTok (); /* Return the list of collected tokens */ return List; }
static void FuncLeft (void) /* Handle the .LEFT function */ { long Count; TokList* List; /* Skip it */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* Count argument. Correct negative counts to zero. */ Count = ConstExpression (); if (Count < 0) { Count = 0; } ConsumeComma (); /* Read the token list */ List = CollectTokens (0, (unsigned) Count); /* Since we want to insert the list before the now current token, we have * to save the current token in some way and then skip it. To do this, we * will add the current token at the end of the token list (so the list * will never be empty), push the token list, and then skip the current * token. This will replace the current token by the first token from the * list (which will be the old current token in case the list was empty). */ AddCurTok (List); /* Insert it into the scanner feed */ PushTokList (List, ".LEFT"); /* Skip the current token */ NextTok (); }
void DbgInfoLine (void) /* Parse and handle LINE subcommand of the .dbg pseudo instruction */ { long Line; FilePos Pos = STATIC_FILEPOS_INITIALIZER; /* Any new line info terminates the last one */ if (CurLineInfo) { EndLine (CurLineInfo); CurLineInfo = 0; } /* If a parameters follow, this is actual line info. If no parameters ** follow, the last line info is terminated. */ if (CurTok.Tok == TOK_SEP) { return; } /* Parameters are separated by a comma */ ConsumeComma (); /* The name of the file follows */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } /* Get the index in the file table for the name */ Pos.Name = GetFileIndex (&CurTok.SVal); /* Skip the name */ NextTok (); /* Comma expected */ ConsumeComma (); /* Line number */ Line = ConstExpression (); if (Line < 0) { ErrorSkip ("Line number is out of valid range"); return; } Pos.Line = Line; /* Generate a new external line info */ CurLineInfo = StartLine (&Pos, LI_TYPE_EXT, 0); }
static void MacSkipDef (unsigned Style) /* Skip a macro definition */ { if (Style == MAC_STYLE_CLASSIC) { /* Skip tokens until we reach the final .endmacro */ while (CurTok.Tok != TOK_ENDMACRO && CurTok.Tok != TOK_EOF) { NextTok (); } if (CurTok.Tok != TOK_EOF) { SkipUntilSep (); } else { Error ("`.ENDMACRO' expected"); } } else { /* Skip until end of line */ SkipUntilSep (); } }
SymEntry* ParseAnySymName (SymFindAction Action) /* Parse a cheap local symbol or a a (possibly scoped) symbol name, search * for it in the symbol table and return the symbol table entry. */ { SymEntry* Sym; /* Distinguish cheap locals and other symbols */ if (CurTok.Tok == TOK_LOCAL_IDENT) { Sym = SymFindLocal (SymLast, &CurTok.SVal, Action); NextTok (); } else { Sym = ParseScopedSymName (Action); } /* Return the symbol found */ return Sym; }
void DbgInfoFile (void) /* Parse and handle FILE subcommand of the .dbg pseudo instruction */ { StrBuf Name = STATIC_STRBUF_INITIALIZER; unsigned long Size; unsigned long MTime; /* Parameters are separated by a comma */ ConsumeComma (); /* Name */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } SB_Copy (&Name, &CurTok.SVal); NextTok (); /* Comma expected */ ConsumeComma (); /* Size */ Size = ConstExpression (); /* Comma expected */ ConsumeComma (); /* MTime */ MTime = ConstExpression (); /* Insert the file into the table */ AddFile (&Name, FT_DBGINFO, Size, MTime); /* Free memory used for Name */ SB_Done (&Name); }
static void FuncIdent (void) /* Handle the .IDENT function */ { StrBuf Buf = STATIC_STRBUF_INITIALIZER; token_t Id; unsigned I; /* Skip it */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* The function expects a string argument */ if (!LookAtStrCon ()) { return; } /* Check that the string contains a valid identifier. While doing so, * determine if it is a cheap local, or global one. */ SB_Reset (&CurTok.SVal); /* Check for a cheap local symbol */ if (SB_Peek (&CurTok.SVal) == LocalStart) { SB_Skip (&CurTok.SVal); Id = TOK_LOCAL_IDENT; } else { Id = TOK_IDENT; } /* Next character must be a valid identifier start */ if (!IsIdStart (SB_Get (&CurTok.SVal))) { NoIdent (); return; } for (I = SB_GetIndex (&CurTok.SVal); I < SB_GetLen (&CurTok.SVal); ++I) { if (!IsIdChar (SB_AtUnchecked (&CurTok.SVal, I))) { NoIdent (); return; } } if (IgnoreCase) { UpcaseSVal (); } /* If anything is ok, save and skip the string. Check that the next token * is a right paren, then replace the token by an identifier token. */ SB_Copy (&Buf, &CurTok.SVal); NextTok (); if (CurTok.Tok != TOK_RPAREN) { Error ("`)' expected"); } else { CurTok.Tok = Id; SB_Copy (&CurTok.SVal, &Buf); SB_Terminate (&CurTok.SVal); } /* Free buffer memory */ SB_Done (&Buf); }
void GetEA (EffAddr* A) /* Parse an effective address, return the result in A */ { unsigned long Restrictions; token_t IndirectEnter; token_t IndirectLeave; const char* IndirectExpect; /* Choose syntax for indirection */ if (BracketAsIndirect) { IndirectEnter = TOK_LBRACK; IndirectLeave = TOK_RBRACK; IndirectExpect = "']' expected"; } else { IndirectEnter = TOK_LPAREN; IndirectLeave = TOK_RPAREN; IndirectExpect = "')' expected"; } /* 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 == IndirectEnter) { /* 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; Consume (IndirectLeave, IndirectExpect); } else if (CurTok.Tok == TOK_S) { /* (rel,s),y */ NextTok (); A->AddrModeSet = AM65_STACK_REL_IND_Y; Consume (IndirectLeave, IndirectExpect); ConsumeComma (); Consume (TOK_Y, "`Y' expected"); } else { Error ("Syntax error"); } } else { /* (adr), (adr),y or (adr),z */ Consume (IndirectLeave, IndirectExpect); if (CurTok.Tok == TOK_COMMA) { /* (adr),y */ NextTok (); switch (CurTok.Tok) { case TOK_Z: /* only set by scanner.c if in 4510-mode */ NextTok (); A->AddrModeSet = AM65_DIR_IND; break; default: Consume (TOK_Y, "`Y' expected"); A->AddrModeSet = AM65_DIR_IND_Y; break; } } else { /* (adr) */ A->AddrModeSet = (CPU == CPU_4510) ? AM65_ABS_IND : AM65_ABS_IND | AM65_ABS_IND_LONG | AM65_DIR_IND; } } } else if (CurTok.Tok == TOK_LBRACK) { /* Never executed if BracketAsIndirect feature is enabled. */ /* [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 | AM65_ABS_IND_LONG; } } 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; }
SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName) /* Parse a (possibly scoped) identifer. The scope of the name must exist and * is returned as function result, while the last part (the identifier) which * may be either a symbol or a scope depending on the context is returned in * Name. FullName is a string buffer that is used to store the full name of * the identifier including the scope. It is used internally and may be used * by the caller for error messages or similar. */ { SymTable* Scope; /* Clear both passed string buffers */ SB_Clear (Name); SB_Clear (FullName); /* Get the starting table */ if (CurTok.Tok == TOK_NAMESPACE) { /* Start from the root scope */ Scope = RootScope; } else if (CurTok.Tok == TOK_IDENT) { /* Remember the name and skip it */ SB_Copy (Name, &CurTok.SVal); NextTok (); /* If no namespace symbol follows, we're already done */ if (CurTok.Tok != TOK_NAMESPACE) { SB_Terminate (FullName); return CurrentScope; } /* Pass the scope back to the caller */ SB_Append (FullName, Name); /* The scope must exist, so search for it starting with the current * scope. */ Scope = SymFindAnyScope (CurrentScope, Name); if (Scope == 0) { /* Scope not found */ SB_Terminate (FullName); Error ("No such scope: `%m%p'", FullName); return 0; } } else { /* Invalid token */ Error ("Identifier expected"); return 0; } /* Skip the namespace token that follows */ SB_AppendStr (FullName, "::"); NextTok (); /* Resolve scopes. */ while (1) { /* Next token must be an identifier. */ if (CurTok.Tok != TOK_IDENT) { Error ("Identifier expected"); return 0; } /* Remember and skip the identifier */ SB_Copy (Name, &CurTok.SVal); NextTok (); /* If a namespace token follows, we search for another scope, otherwise * the name is a symbol and we're done. */ if (CurTok.Tok != TOK_NAMESPACE) { /* Symbol */ return Scope; } /* Pass the scope back to the caller */ SB_Append (FullName, Name); /* Search for the child scope */ Scope = SymFindScope (Scope, Name, SYM_FIND_EXISTING); if (Scope == 0) { /* Scope not found */ Error ("No such scope: `%m%p'", FullName); return 0; } /* Skip the namespace token that follows */ SB_AppendStr (FullName, "::"); NextTok (); } }
void DbgInfoSym (void) /* Parse and handle SYM subcommand of the .dbg pseudo instruction */ { static const char* const StorageKeys[] = { "AUTO", "EXTERN", "REGISTER", "STATIC", }; unsigned Name; int Type; unsigned AsmName = EMPTY_STRING_ID; unsigned Flags; int Offs = 0; HLLDbgSym* S; /* Parameters are separated by a comma */ ConsumeComma (); /* Name */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } Name = GetStrBufId (&CurTok.SVal); NextTok (); /* Comma expected */ ConsumeComma (); /* Type */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } Type = ValidateType (&CurTok.SVal); if (Type < 0) { return; } NextTok (); /* Comma expected */ ConsumeComma (); /* The storage class follows */ if (CurTok.Tok != TOK_IDENT) { ErrorSkip ("Storage class specifier expected"); return; } switch (GetSubKey (StorageKeys, sizeof (StorageKeys)/sizeof (StorageKeys[0]))) { case 0: Flags = HLL_SC_AUTO; break; case 1: Flags = HLL_SC_EXTERN; break; case 2: Flags = HLL_SC_REG; break; case 3: Flags = HLL_SC_STATIC; break; default: ErrorSkip ("Storage class specifier expected"); return; } /* Skip the storage class token and the following comma */ NextTok (); ConsumeComma (); /* The next tokens depend on the storage class */ if (Flags == HLL_SC_AUTO) { /* Auto: Stack offset follows */ Offs = ConstExpression (); } else { /* Register, extern or static: Assembler name follows */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } AsmName = GetStrBufId (&CurTok.SVal); NextTok (); /* For register, an offset follows */ if (Flags == HLL_SC_REG) { ConsumeComma (); Offs = ConstExpression (); } } /* Add the function */ S = NewHLLDbgSym (Flags | HLL_TYPE_SYM, Name, Type); S->AsmName = AsmName; S->Offs = Offs; CollAppend (&HLLDbgSyms, S); }
void DbgInfoFunc (void) /* Parse and handle func subcommand of the .dbg pseudo instruction */ { static const char* const StorageKeys[] = { "EXTERN", "STATIC", }; unsigned Name; int Type; unsigned AsmName; unsigned Flags; HLLDbgSym* S; /* Parameters are separated by a comma */ ConsumeComma (); /* Name */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } Name = GetStrBufId (&CurTok.SVal); NextTok (); /* Comma expected */ ConsumeComma (); /* Type */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } Type = ValidateType (&CurTok.SVal); if (Type < 0) { return; } NextTok (); /* Comma expected */ ConsumeComma (); /* The storage class follows */ if (CurTok.Tok != TOK_IDENT) { ErrorSkip ("Storage class specifier expected"); return; } switch (GetSubKey (StorageKeys, sizeof (StorageKeys)/sizeof (StorageKeys[0]))) { case 0: Flags = HLL_TYPE_FUNC | HLL_SC_EXTERN; break; case 1: Flags = HLL_TYPE_FUNC | HLL_SC_STATIC; break; default: ErrorSkip ("Storage class specifier expected"); return; } NextTok (); /* Comma expected */ ConsumeComma (); /* Assembler name follows */ if (CurTok.Tok != TOK_STRCON) { ErrorSkip ("String constant expected"); return; } AsmName = GetStrBufId (&CurTok.SVal); NextTok (); /* There may only be one function per scope */ if (CurrentScope == RootScope) { ErrorSkip ("Functions may not be used in the root scope"); return; } else if (CurrentScope->Type != SCOPE_SCOPE || CurrentScope->Label == 0) { ErrorSkip ("Functions can only be tagged to .PROC scopes"); return; } else if (CurrentScope->Label->HLLSym != 0) { ErrorSkip ("Only one HLL symbol per asm symbol is allowed"); return; } else if (CurrentScope->Label->Name != AsmName) { ErrorSkip ("Scope label and asm name for function must match"); return; } /* Add the function */ S = NewHLLDbgSym (Flags, Name, Type); S->Sym = CurrentScope->Label; CurrentScope->Label->HLLSym = S; CollAppend (&HLLDbgSyms, S); }
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; }
static long DoStructInternal (long Offs, unsigned Type) /* Handle the .STRUCT command */ { long Size = 0; /* Outside of other structs, we need a name. Inside another struct or ** union, the struct may be anonymous, in which case no new lexical level ** is started. */ int Anon = (CurTok.Tok != TOK_IDENT); if (!Anon) { /* Enter a new scope, then skip the name */ SymEnterLevel (&CurTok.SVal, SCOPE_STRUCT, ADDR_SIZE_ABS, 0); NextTok (); /* Start at zero offset in the new scope */ Offs = 0; } /* Test for end of line */ ConsumeSep (); /* Read until end of struct */ while (CurTok.Tok != TOK_ENDSTRUCT && CurTok.Tok != TOK_ENDUNION && CurTok.Tok != TOK_EOF) { long MemberSize; SymTable* Struct; SymEntry* Sym; /* Allow empty and comment lines */ if (CurTok.Tok == TOK_SEP) { NextTok (); continue; } /* The format is "[identifier] storage-allocator [, multiplicator]" */ Sym = 0; if (CurTok.Tok == TOK_IDENT) { /* Beware: An identifier may also be a macro, in which case we have ** to start over. */ Macro* M = FindMacro (&CurTok.SVal); if (M) { MacExpandStart (M); continue; } /* We have an identifier, generate a symbol */ Sym = SymFind (CurrentScope, &CurTok.SVal, SYM_ALLOC_NEW); /* Assign the symbol the offset of the current member */ SymDef (Sym, GenLiteralExpr (Offs), ADDR_SIZE_DEFAULT, SF_NONE); /* Skip the member name */ NextTok (); } /* Read storage allocators */ MemberSize = 0; /* In case of errors, use zero */ switch (CurTok.Tok) { case TOK_BYTE: NextTok (); MemberSize = Member (1); break; case TOK_DBYT: case TOK_WORD: case TOK_ADDR: NextTok (); MemberSize = Member (2); break; case TOK_FARADDR: NextTok (); MemberSize = Member (3); break; case TOK_DWORD: NextTok (); MemberSize = Member (4); break; case TOK_RES: NextTok (); if (CurTok.Tok == TOK_SEP) { ErrorSkip ("Size is missing"); } else { MemberSize = Member (1); } break; case TOK_TAG: NextTok (); Struct = ParseScopedSymTable (); if (Struct == 0) { ErrorSkip ("Unknown struct/union"); } else if (GetSymTabType (Struct) != SCOPE_STRUCT) { ErrorSkip ("Not a struct/union"); } else { SymEntry* SizeSym = GetSizeOfScope (Struct); if (!SymIsDef (SizeSym) || !SymIsConst (SizeSym, &MemberSize)) { ErrorSkip ("Size of struct/union is unknown"); } } MemberSize = Member (MemberSize); break; case TOK_STRUCT: NextTok (); MemberSize = DoStructInternal (Offs, STRUCT); break; case TOK_UNION: NextTok (); MemberSize = DoStructInternal (Offs, UNION); break; default: if (!CheckConditionals ()) { /* Not a conditional directive */ ErrorSkip ("Invalid storage allocator in struct/union"); } } /* Assign the size to the member if it has a name */ if (Sym) { DefSizeOfSymbol (Sym, MemberSize); } /* Next member */ if (Type == STRUCT) { /* Struct */ Offs += MemberSize; Size += MemberSize; } else { /* Union */ if (MemberSize > Size) { Size = MemberSize; } } /* Expect end of line */ ConsumeSep (); } /* If this is not a anon struct, enter a special symbol named ".size" ** into the symbol table of the struct that holds the size of the ** struct. Since the symbol starts with a dot, it cannot be accessed ** by user code. ** Leave the struct scope level. */ if (!Anon) { /* Add a symbol */ SymEntry* SizeSym = GetSizeOfScope (CurrentScope); SymDef (SizeSym, GenLiteralExpr (Size), ADDR_SIZE_DEFAULT, SF_NONE); /* Close the struct scope */ SymLeaveLevel (); } /* End of struct/union definition */ if (Type == STRUCT) { Consume (TOK_ENDSTRUCT, "'.ENDSTRUCT' expected"); } else { Consume (TOK_ENDUNION, "'.ENDUNION' expected"); } /* Return the size of the struct */ return Size; }
void DSNLEXER::NeedRIGHT() throw( IO_ERROR ) { int tok = NextTok(); if( tok != DSN_RIGHT ) Expecting( DSN_RIGHT ); }
static void FuncSPrintF (void) /* Handle the .SPRINTF function */ { StrBuf Format = STATIC_STRBUF_INITIALIZER; /* User supplied format */ StrBuf R = STATIC_STRBUF_INITIALIZER; /* Result string */ StrBuf F1 = STATIC_STRBUF_INITIALIZER; /* One format spec from F */ StrBuf R1 = STATIC_STRBUF_INITIALIZER; /* One result */ char C; int Done; long IVal; /* Integer value */ /* Skip the .SPRINTF token */ NextTok (); /* Left paren expected */ ConsumeLParen (); /* First argument is a format string. Remember and skip it */ if (!LookAtStrCon ()) { return; } SB_Copy (&Format, &CurTok.SVal); NextTok (); /* Walk over the format string, generating the function result in R */ while (1) { /* Get the next char from the format string and check for EOS */ if (SB_Peek (&Format) == '\0') { break; } /* Check for a format specifier */ if (SB_Peek (&Format) != '%') { /* No format specifier, just copy */ SB_AppendChar (&R, SB_Get (&Format)); continue; } SB_Skip (&Format); if (SB_Peek (&Format) == '%') { /* %% */ SB_AppendChar (&R, '%'); SB_Skip (&Format); continue; } if (SB_Peek (&Format) == '\0') { InvalidFormatString (); break; } /* Since a format specifier follows, we do expect anotehr argument for * the .sprintf function. */ ConsumeComma (); /* We will copy the format spec into F1 checking for the things we * support, and later use xsprintf to do the actual formatting. This * is easier than adding another printf implementation... */ SB_Clear (&F1); SB_AppendChar (&F1, '%'); /* Check for flags */ Done = 0; while ((C = SB_Peek (&Format)) != '\0' && !Done) { switch (C) { case '-': /* FALLTHROUGH */ case '+': /* FALLTHROUGH */ case ' ': /* FALLTHROUGH */ case '#': /* FALLTHROUGH */ case '0': SB_AppendChar (&F1, SB_Get (&Format)); break; default: Done = 1; break; } } /* We do only support a numerical width field */ while (IsDigit (SB_Peek (&Format))) { SB_AppendChar (&F1, SB_Get (&Format)); } /* Precision - only positive numerical fields supported */ if (SB_Peek (&Format) == '.') { SB_AppendChar (&F1, SB_Get (&Format)); while (IsDigit (SB_Peek (&Format))) { SB_AppendChar (&F1, SB_Get (&Format)); } } /* Length modifiers aren't supported, so read the conversion specs */ switch (SB_Peek (&Format)) { case 'd': case 'i': case 'o': case 'u': case 'X': case 'x': /* Our ints are actually longs, so we use the 'l' modifier when * calling xsprintf later. Terminate the format string. */ SB_AppendChar (&F1, 'l'); SB_AppendChar (&F1, SB_Get (&Format)); SB_Terminate (&F1); /* The argument must be a constant expression */ IVal = ConstExpression (); /* Format this argument according to the spec */ SB_Printf (&R1, SB_GetConstBuf (&F1), IVal); /* Append the formatted argument to the result */ SB_Append (&R, &R1); break; case 's': /* Add the format spec and terminate the format */ SB_AppendChar (&F1, SB_Get (&Format)); SB_Terminate (&F1); /* The argument must be a string constant */ if (!LookAtStrCon ()) { /* Make it one */ SB_CopyStr (&CurTok.SVal, "**undefined**"); } /* Format this argument according to the spec */ SB_Printf (&R1, SB_GetConstBuf (&F1), SB_GetConstBuf (&CurTok.SVal)); /* Skip the string constant */ NextTok (); /* Append the formatted argument to the result */ SB_Append (&R, &R1); break; case 'c': /* Add the format spec and terminate the format */ SB_AppendChar (&F1, SB_Get (&Format)); SB_Terminate (&F1); /* The argument must be a constant expression */ IVal = ConstExpression (); /* Check for a valid character range */ if (IVal <= 0 || IVal > 255) { Error ("Char argument out of range"); IVal = ' '; } /* Format this argument according to the spec. Be sure to pass * an int as the char value. */ SB_Printf (&R1, SB_GetConstBuf (&F1), (int) IVal); /* Append the formatted argument to the result */ SB_Append (&R, &R1); break; default: Error ("Invalid format string"); SB_Skip (&Format); break; } } /* Terminate the result string */ SB_Terminate (&R); /* We expect a closing parenthesis, but will not skip it but replace it * by the string token just created. */ if (CurTok.Tok != TOK_RPAREN) { Error ("`)' expected"); } else { CurTok.Tok = TOK_STRCON; SB_Copy (&CurTok.SVal, &R); SB_Terminate (&CurTok.SVal); } /* Delete the string buffers */ SB_Done (&Format); SB_Done (&R); SB_Done (&F1); SB_Done (&R1); }
void DoConditionals (void) /* Catch all for conditional directives */ { IfDesc* D; do { switch (CurTok.Tok) { case TOK_ELSE: D = GetCurrentIf (); /* Allow an .ELSE */ ElseClause (D, ".ELSE"); /* Remember the data for the .ELSE */ if (D) { ReleaseFullLineInfo (&D->LineInfos); GetFullLineInfo (&D->LineInfos); D->Name = ".ELSE"; } /* Calculate the new overall condition */ CalcOverallIfCond (); /* Skip .ELSE */ NextTok (); ExpectSep (); break; case TOK_ELSEIF: D = GetCurrentIf (); /* Handle as if there was an .ELSE first */ ElseClause (D, ".ELSEIF"); /* Calculate the new overall if condition */ CalcOverallIfCond (); /* Allocate and prepare a new descriptor */ D = AllocIf (".ELSEIF", 0); NextTok (); /* Ignore the new condition if we are inside a false .ELSE ** branch. This way we won't get any errors about undefined ** symbols or similar... */ if (IfCond) { SetIfCond (D, ConstExpression ()); ExpectSep (); } /* Get the new overall condition */ CalcOverallIfCond (); break; case TOK_ENDIF: /* We're done with this .IF.. - remove the descriptor(s) */ FreeIf (); /* Be sure not to read the next token until the .IF stack ** has been cleanup up, since we may be at end of file. */ NextTok (); ExpectSep (); /* Get the new overall condition */ CalcOverallIfCond (); break; case TOK_IF: D = AllocIf (".IF", 1); NextTok (); if (IfCond) { SetIfCond (D, ConstExpression ()); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFBLANK: D = AllocIf (".IFBLANK", 1); NextTok (); if (IfCond) { if (TokIsSep (CurTok.Tok)) { SetIfCond (D, 1); } else { SetIfCond (D, 0); SkipUntilSep (); } } CalcOverallIfCond (); break; case TOK_IFCONST: D = AllocIf (".IFCONST", 1); NextTok (); if (IfCond) { ExprNode* Expr = Expression(); SetIfCond (D, IsConstExpr (Expr, 0)); FreeExpr (Expr); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFDEF: D = AllocIf (".IFDEF", 1); NextTok (); if (IfCond) { SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING); SetIfCond (D, Sym != 0 && SymIsDef (Sym)); } CalcOverallIfCond (); break; case TOK_IFNBLANK: D = AllocIf (".IFNBLANK", 1); NextTok (); if (IfCond) { if (TokIsSep (CurTok.Tok)) { SetIfCond (D, 0); } else { SetIfCond (D, 1); SkipUntilSep (); } } CalcOverallIfCond (); break; case TOK_IFNCONST: D = AllocIf (".IFNCONST", 1); NextTok (); if (IfCond) { ExprNode* Expr = Expression(); SetIfCond (D, !IsConstExpr (Expr, 0)); FreeExpr (Expr); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFNDEF: D = AllocIf (".IFNDEF", 1); NextTok (); if (IfCond) { SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING); SetIfCond (D, Sym == 0 || !SymIsDef (Sym)); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFNREF: D = AllocIf (".IFNREF", 1); NextTok (); if (IfCond) { SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING); SetIfCond (D, Sym == 0 || !SymIsRef (Sym)); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFP02: D = AllocIf (".IFP02", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_6502); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFP4510: D = AllocIf (".IFP4510", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_4510); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFP816: D = AllocIf (".IFP816", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_65816); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFPC02: D = AllocIf (".IFPC02", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_65C02); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFPSC02: D = AllocIf (".IFPSC02", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_65SC02); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFREF: D = AllocIf (".IFREF", 1); NextTok (); if (IfCond) { SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING); SetIfCond (D, Sym != 0 && SymIsRef (Sym)); ExpectSep (); } CalcOverallIfCond (); break; default: /* Skip tokens */ NextTok (); } } while (IfCond == 0 && CurTok.Tok != TOK_EOF); }