mirror of
https://github.com/cc65/cc65.git
synced 2024-12-26 08:32:00 +00:00
Added/finished .MID, .LEFT, .RIGHT
git-svn-id: svn://svn.cc65.org/cc65/trunk@136 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
0c85406f52
commit
fbe694bca3
@ -290,6 +290,9 @@ void MacDef (unsigned Style)
|
|||||||
|
|
||||||
/* Define the macro */
|
/* Define the macro */
|
||||||
M = NewMacro (SVal, HashVal, Style);
|
M = NewMacro (SVal, HashVal, Style);
|
||||||
|
|
||||||
|
/* Switch to raw token mode and skip the macro name */
|
||||||
|
EnterRawTokenMode ();
|
||||||
NextTok ();
|
NextTok ();
|
||||||
|
|
||||||
/* If we have a DEFINE style macro, we may have parameters in braces,
|
/* If we have a DEFINE style macro, we may have parameters in braces,
|
||||||
@ -371,7 +374,7 @@ void MacDef (unsigned Style)
|
|||||||
/* May not have end of file in a macro definition */
|
/* May not have end of file in a macro definition */
|
||||||
if (Tok == TOK_EOF) {
|
if (Tok == TOK_EOF) {
|
||||||
Error (ERR_ENDMACRO_EXPECTED);
|
Error (ERR_ENDMACRO_EXPECTED);
|
||||||
return;
|
goto Done;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Accept a newline or end of file for new style macros */
|
/* Accept a newline or end of file for new style macros */
|
||||||
@ -454,6 +457,10 @@ void MacDef (unsigned Style)
|
|||||||
if (Style == MAC_STYLE_CLASSIC) {
|
if (Style == MAC_STYLE_CLASSIC) {
|
||||||
NextTok ();
|
NextTok ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Done:
|
||||||
|
/* Switch out of raw token mode */
|
||||||
|
LeaveRawTokenMode ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -330,9 +330,7 @@ static void OneLine (void)
|
|||||||
if (Tok == TOK_EQ) {
|
if (Tok == TOK_EQ) {
|
||||||
/* Skip the '=' */
|
/* Skip the '=' */
|
||||||
NextTok ();
|
NextTok ();
|
||||||
/* Define the symbol with the expression following the
|
/* Define the symbol with the expression following the '=' */
|
||||||
* '='
|
|
||||||
*/
|
|
||||||
SymDef (Ident, Expression (), 0);
|
SymDef (Ident, Expression (), 0);
|
||||||
/* Don't allow anything after a symbol definition */
|
/* Don't allow anything after a symbol definition */
|
||||||
Done = 1;
|
Done = 1;
|
||||||
|
@ -43,6 +43,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Data */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned RawMode = 0; /* Raw token mode flag/counter */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Code */
|
/* Code */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -165,6 +175,47 @@ static void FuncConcat (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void FuncLeft (void)
|
||||||
|
/* Handle the .LEFT function */
|
||||||
|
{
|
||||||
|
long Count;
|
||||||
|
TokList* List;
|
||||||
|
|
||||||
|
/* Skip it */
|
||||||
|
NextTok ();
|
||||||
|
|
||||||
|
/* Left paren expected */
|
||||||
|
ConsumeLParen ();
|
||||||
|
|
||||||
|
/* Count argument */
|
||||||
|
Count = ConstExpression ();
|
||||||
|
if (Count < 0 || Count > 100) {
|
||||||
|
Error (ERR_RANGE);
|
||||||
|
Count = 1;
|
||||||
|
}
|
||||||
|
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 ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void FuncMid (void)
|
static void FuncMid (void)
|
||||||
/* Handle the .MID function */
|
/* Handle the .MID function */
|
||||||
{
|
{
|
||||||
@ -197,8 +248,76 @@ static void FuncMid (void)
|
|||||||
/* Read the token list */
|
/* Read the token list */
|
||||||
List = CollectTokens ((unsigned) Start, (unsigned) Count);
|
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 */
|
/* Insert it into the scanner feed */
|
||||||
PushTokList (List, ".MID");
|
PushTokList (List, ".MID");
|
||||||
|
|
||||||
|
/* Skip the current token */
|
||||||
|
NextTok ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void FuncRight (void)
|
||||||
|
/* Handle the .RIGHT function */
|
||||||
|
{
|
||||||
|
long Count;
|
||||||
|
TokList* List;
|
||||||
|
|
||||||
|
/* Skip it */
|
||||||
|
NextTok ();
|
||||||
|
|
||||||
|
/* Left paren expected */
|
||||||
|
ConsumeLParen ();
|
||||||
|
|
||||||
|
/* Count argument */
|
||||||
|
Count = ConstExpression ();
|
||||||
|
if (Count < 0 || Count > 100) {
|
||||||
|
Error (ERR_RANGE);
|
||||||
|
Count = 1;
|
||||||
|
}
|
||||||
|
ConsumeComma ();
|
||||||
|
|
||||||
|
/* Read the complete token list */
|
||||||
|
List = CollectTokens (0, 9999);
|
||||||
|
|
||||||
|
/* Delete tokens from the list until Count tokens are remaining */
|
||||||
|
while (List->Count > 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 ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -244,17 +363,28 @@ void NextTok (void)
|
|||||||
/* Get the next raw token */
|
/* Get the next raw token */
|
||||||
NextRawTok ();
|
NextRawTok ();
|
||||||
|
|
||||||
/* Check for token handling functions */
|
/* In raw mode, pass the token unchanged */
|
||||||
|
if (RawMode == 0) {
|
||||||
|
|
||||||
|
/* Execute token handling functions */
|
||||||
switch (Tok) {
|
switch (Tok) {
|
||||||
|
|
||||||
case TOK_CONCAT:
|
case TOK_CONCAT:
|
||||||
FuncConcat ();
|
FuncConcat ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOK_LEFT:
|
||||||
|
FuncLeft ();
|
||||||
|
break;
|
||||||
|
|
||||||
case TOK_MID:
|
case TOK_MID:
|
||||||
FuncMid ();
|
FuncMid ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOK_RIGHT:
|
||||||
|
FuncRight ();
|
||||||
|
break;
|
||||||
|
|
||||||
case TOK_STRING:
|
case TOK_STRING:
|
||||||
FuncString ();
|
FuncString ();
|
||||||
break;
|
break;
|
||||||
@ -265,6 +395,7 @@ void NextTok (void)
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -321,7 +452,7 @@ void ConsumeComma (void)
|
|||||||
|
|
||||||
|
|
||||||
void SkipUntilSep (void)
|
void SkipUntilSep (void)
|
||||||
/* Skip tokens until we reach a line separator */
|
/* Skip tokens until we reach a line separator or end of file */
|
||||||
{
|
{
|
||||||
while (Tok != TOK_SEP && Tok != TOK_EOF) {
|
while (Tok != TOK_SEP && Tok != TOK_EOF) {
|
||||||
NextTok ();
|
NextTok ();
|
||||||
@ -330,3 +461,25 @@ void SkipUntilSep (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void EnterRawTokenMode (void)
|
||||||
|
/* Enter raw token mode. In raw mode, token handling functions are not
|
||||||
|
* executed, but the function tokens are passed untouched to the upper
|
||||||
|
* layer. Raw token mode is used when storing macro tokens for later
|
||||||
|
* use.
|
||||||
|
* Calls to EnterRawTokenMode and LeaveRawTokenMode may be nested.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
++RawMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void LeaveRawTokenMode (void)
|
||||||
|
/* Leave raw token mode. */
|
||||||
|
{
|
||||||
|
PRECONDITION (RawMode > 0);
|
||||||
|
--RawMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,7 +67,18 @@ void ConsumeComma (void);
|
|||||||
/* Consume a comma */
|
/* Consume a comma */
|
||||||
|
|
||||||
void SkipUntilSep (void);
|
void SkipUntilSep (void);
|
||||||
/* Skip tokens until we reach a line separator */
|
/* Skip tokens until we reach a line separator or end of file */
|
||||||
|
|
||||||
|
void EnterRawTokenMode (void);
|
||||||
|
/* Enter raw token mode. In raw mode, token handling functions are not
|
||||||
|
* executed, but the function tokens are passed untouched to the upper
|
||||||
|
* layer. Raw token mode is used when storing macro tokens for later
|
||||||
|
* use.
|
||||||
|
* Calls to EnterRawTokenMode and LeaveRawTokenMode may be nested.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void LeaveRawTokenMode (void);
|
||||||
|
/* Leave raw token mode. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,6 +75,16 @@ static char Keyword [sizeof (SVal)+1] = ".";
|
|||||||
|
|
||||||
|
|
||||||
static void DoUnexpected (void);
|
static void DoUnexpected (void);
|
||||||
|
/* Got an unexpected keyword */
|
||||||
|
|
||||||
|
static void DoInvalid (void);
|
||||||
|
/* Handle a token that is invalid here, since it should have been handled on
|
||||||
|
* a much lower level of the expression hierarchy. Getting this sort of token
|
||||||
|
* means that the lower level code has bugs.
|
||||||
|
* This function differs to DoUnexpected in that the latter may be triggered
|
||||||
|
* by the user by using keywords in the wrong location. DoUnexpected is not
|
||||||
|
* an error in the assembler itself, while DoInvalid is.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -696,6 +706,20 @@ static void DoInclude (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void DoInvalid (void)
|
||||||
|
/* Handle a token that is invalid here, since it should have been handled on
|
||||||
|
* a much lower level of the expression hierarchy. Getting this sort of token
|
||||||
|
* means that the lower level code has bugs.
|
||||||
|
* This function differs to DoUnexpected in that the latter may be triggered
|
||||||
|
* by the user by using keywords in the wrong location. DoUnexpected is not
|
||||||
|
* an error in the assembler itself, while DoInvalid is.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Internal ("Unexpected token: %s", Keyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void DoLineCont (void)
|
static void DoLineCont (void)
|
||||||
/* Switch the use of line continuations */
|
/* Switch the use of line continuations */
|
||||||
{
|
{
|
||||||
@ -788,16 +812,6 @@ static void DoMacro (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void DoMid (void)
|
|
||||||
/* Handle .MID - this should never happen, since the keyword is actually
|
|
||||||
* handled on a much lower level of the expression hierarchy.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
Internal ("Unexpected token: .MID");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void DoNull (void)
|
static void DoNull (void)
|
||||||
/* Switch to the NULL segment */
|
/* Switch to the NULL segment */
|
||||||
{
|
{
|
||||||
@ -1121,6 +1135,7 @@ static CtrlDesc CtrlCmdTab [] = {
|
|||||||
{ ccNone, DoImportZP },
|
{ ccNone, DoImportZP },
|
||||||
{ ccNone, DoIncBin },
|
{ ccNone, DoIncBin },
|
||||||
{ ccNone, DoInclude },
|
{ ccNone, DoInclude },
|
||||||
|
{ ccNone, DoInvalid }, /* .LEFT */
|
||||||
{ ccNone, DoLineCont },
|
{ ccNone, DoLineCont },
|
||||||
{ ccNone, DoList },
|
{ ccNone, DoList },
|
||||||
{ ccNone, DoListBytes },
|
{ ccNone, DoListBytes },
|
||||||
@ -1129,7 +1144,7 @@ static CtrlDesc CtrlCmdTab [] = {
|
|||||||
{ ccNone, DoMacPack },
|
{ ccNone, DoMacPack },
|
||||||
{ ccNone, DoMacro },
|
{ ccNone, DoMacro },
|
||||||
{ ccNone, DoUnexpected }, /* .MATCH */
|
{ ccNone, DoUnexpected }, /* .MATCH */
|
||||||
{ ccNone, DoMid },
|
{ ccNone, DoInvalid }, /* .MID */
|
||||||
{ ccNone, DoNull },
|
{ ccNone, DoNull },
|
||||||
{ ccNone, DoOrg },
|
{ ccNone, DoOrg },
|
||||||
{ ccNone, DoOut },
|
{ ccNone, DoOut },
|
||||||
@ -1143,6 +1158,7 @@ static CtrlDesc CtrlCmdTab [] = {
|
|||||||
{ ccNone, DoReloc },
|
{ ccNone, DoReloc },
|
||||||
{ ccNone, DoRepeat },
|
{ ccNone, DoRepeat },
|
||||||
{ ccNone, DoRes },
|
{ ccNone, DoRes },
|
||||||
|
{ ccNone, DoInvalid }, /* .RIGHT */
|
||||||
{ ccNone, DoROData },
|
{ ccNone, DoROData },
|
||||||
{ ccNone, DoSegment },
|
{ ccNone, DoSegment },
|
||||||
{ ccNone, DoSmart },
|
{ ccNone, DoSmart },
|
||||||
|
@ -184,6 +184,7 @@ struct DotKeyword {
|
|||||||
{ "IMPORTZP", TOK_IMPORTZP },
|
{ "IMPORTZP", TOK_IMPORTZP },
|
||||||
{ "INCBIN", TOK_INCBIN },
|
{ "INCBIN", TOK_INCBIN },
|
||||||
{ "INCLUDE", TOK_INCLUDE },
|
{ "INCLUDE", TOK_INCLUDE },
|
||||||
|
{ "LEFT", TOK_LEFT },
|
||||||
{ "LINECONT", TOK_LINECONT },
|
{ "LINECONT", TOK_LINECONT },
|
||||||
{ "LIST", TOK_LIST },
|
{ "LIST", TOK_LIST },
|
||||||
{ "LISTBYTES", TOK_LISTBYTES },
|
{ "LISTBYTES", TOK_LISTBYTES },
|
||||||
@ -212,6 +213,7 @@ struct DotKeyword {
|
|||||||
{ "RELOC", TOK_RELOC },
|
{ "RELOC", TOK_RELOC },
|
||||||
{ "REPEAT", TOK_REPEAT },
|
{ "REPEAT", TOK_REPEAT },
|
||||||
{ "RES", TOK_RES },
|
{ "RES", TOK_RES },
|
||||||
|
{ "RIGHT", TOK_RIGHT },
|
||||||
{ "RODATA", TOK_RODATA },
|
{ "RODATA", TOK_RODATA },
|
||||||
{ "SEGMENT", TOK_SEGMENT },
|
{ "SEGMENT", TOK_SEGMENT },
|
||||||
{ "SHL", TOK_SHL },
|
{ "SHL", TOK_SHL },
|
||||||
|
@ -161,6 +161,7 @@ enum Token {
|
|||||||
TOK_IMPORTZP,
|
TOK_IMPORTZP,
|
||||||
TOK_INCBIN,
|
TOK_INCBIN,
|
||||||
TOK_INCLUDE,
|
TOK_INCLUDE,
|
||||||
|
TOK_LEFT,
|
||||||
TOK_LINECONT,
|
TOK_LINECONT,
|
||||||
TOK_LIST,
|
TOK_LIST,
|
||||||
TOK_LISTBYTES,
|
TOK_LISTBYTES,
|
||||||
@ -183,6 +184,7 @@ enum Token {
|
|||||||
TOK_RELOC,
|
TOK_RELOC,
|
||||||
TOK_REPEAT,
|
TOK_REPEAT,
|
||||||
TOK_RES,
|
TOK_RES,
|
||||||
|
TOK_RIGHT,
|
||||||
TOK_RODATA,
|
TOK_RODATA,
|
||||||
TOK_SEGMENT,
|
TOK_SEGMENT,
|
||||||
TOK_SMART,
|
TOK_SMART,
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
#include "../common/xmalloc.h"
|
#include "../common/xmalloc.h"
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
#include "istack.h"
|
#include "istack.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "toklist.h"
|
#include "toklist.h"
|
||||||
@ -191,9 +192,15 @@ static int ReplayTokList (void* List)
|
|||||||
/* Cast the generic pointer to an actual list */
|
/* Cast the generic pointer to an actual list */
|
||||||
TokList* L = List;
|
TokList* L = List;
|
||||||
|
|
||||||
|
/* Last may never be a NULL pointer, otherwise there's a bug in the code */
|
||||||
|
CHECK (L->Last != 0);
|
||||||
|
|
||||||
/* Set the next token from the list */
|
/* Set the next token from the list */
|
||||||
TokSet (L->Last);
|
TokSet (L->Last);
|
||||||
|
|
||||||
|
/* Set the pointer to the next token */
|
||||||
|
L->Last = L->Last->Next;
|
||||||
|
|
||||||
/* If this was the last token, decrement the repeat counter. If it goes
|
/* If this was the last token, decrement the repeat counter. If it goes
|
||||||
* zero, delete the list and remove the function from the stack.
|
* zero, delete the list and remove the function from the stack.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user