Compare commits

...

8 Commits

Author SHA1 Message Date
Antonio Niño Díaz
fe65e07cb6 Fail when using negative constants if not allowed
Some commands, such as `DS`, `BANK[n]`, etc, don't allow the use of
negative constants, but there wasn't any check to prohibit the code from
trying to do so.

This patch adds the `uconst` type to the parser to use when a constant
is expected, but it mustn't be negative.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-01 14:31:58 +01:00
Antonio Niño Díaz
bb12806da1 Fix indentation
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-01 14:31:58 +01:00
Antonio Niño Díaz
fa36042131 Add missing documentation of RL command
Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-07-01 14:31:39 +01:00
Antonio Niño Díaz
efaad99f25 Update manpage documentation about labels
- Local labels can now be exported.
- Local labels can be declared as Scope.Label in addition of .Label.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-06-13 20:16:42 +01:00
Antonio Niño Díaz
62d820c261 Merge pull request #181 from Ben10do/reference-local-symbols
Allow local labels to be referenced (and exported)

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-06-12 21:46:32 +01:00
Ben10do
a53d795361 Add tests for explicit definitions of local labels
These check that “Parent.child” may be used in place of “.child”, and that “WrongParent.child” may not be used in the scope of “Parent”.
2017-06-12 19:50:02 +01:00
Sanqui
2e60c4dd2e Add tests for remote local symbols 2017-06-12 19:36:52 +01:00
Ben10do
ce8a13a562 Allow local symbols to be referenced
Local symbols can now be referenced outside the scope of their parent, by using the syntax “Parent.Chlid”.

- Local symbol names are now stored internally as “Parent.Child”.
- The symbol’s scope field no longer forms a linked list of the prior local symbols; it will now always contain the parent.
- Add the ability use EXPORT and GLOBAL with local symbols.
- Reduce duplication between findsymbol() and findpsymbol(), as well as between sym_AddLocalReloc() and sym_AddReloc().
2017-06-12 19:36:46 +01:00
13 changed files with 153 additions and 81 deletions

View File

@@ -439,6 +439,7 @@ void if_skip_to_endc( void )
%type <sVal> relocconst %type <sVal> relocconst
%type <nConstValue> const %type <nConstValue> const
%type <nConstValue> uconst
%type <nConstValue> const_3bit %type <nConstValue> const_3bit
%type <sVal> const_8bit %type <sVal> const_8bit
%type <sVal> const_16bit %type <sVal> const_16bit
@@ -587,7 +588,11 @@ label : /* empty */
else else
sym_AddReloc($1); sym_AddReloc($1);
} | T_LABEL ':' ':' { } | T_LABEL ':' ':' {
if ($1[0] == '.') {
sym_AddLocalReloc($1);
} else {
sym_AddReloc($1); sym_AddReloc($1);
}
sym_Export($1); sym_Export($1);
}; };
@@ -688,7 +693,7 @@ shift : T_POP_SHIFT
{ sym_ShiftCurrentMacroArgs(); } { sym_ShiftCurrentMacroArgs(); }
; ;
rept : T_POP_REPT const rept : T_POP_REPT uconst
{ {
copyrept(); copyrept();
fstk_RunRept( $2 ); fstk_RunRept( $2 );
@@ -706,7 +711,7 @@ equs : T_LABEL T_POP_EQUS string
{ sym_AddString( $1, $3 ); } { sym_AddString( $1, $3 ); }
; ;
rsset : T_POP_RSSET const rsset : T_POP_RSSET uconst
{ sym_AddSet( "_RS", $2 ); } { sym_AddSet( "_RS", $2 ); }
; ;
@@ -714,28 +719,28 @@ rsreset : T_POP_RSRESET
{ sym_AddSet( "_RS", 0 ); } { sym_AddSet( "_RS", 0 ); }
; ;
rl : T_LABEL T_POP_RL const rl : T_LABEL T_POP_RL uconst
{ {
sym_AddEqu( $1, sym_GetConstantValue("_RS") ); sym_AddEqu( $1, sym_GetConstantValue("_RS") );
sym_AddSet( "_RS", sym_GetConstantValue("_RS")+4*$3 ); sym_AddSet( "_RS", sym_GetConstantValue("_RS")+4*$3 );
} }
; ;
rw : T_LABEL T_POP_RW const rw : T_LABEL T_POP_RW uconst
{ {
sym_AddEqu( $1, sym_GetConstantValue("_RS") ); sym_AddEqu( $1, sym_GetConstantValue("_RS") );
sym_AddSet( "_RS", sym_GetConstantValue("_RS")+2*$3 ); sym_AddSet( "_RS", sym_GetConstantValue("_RS")+2*$3 );
} }
; ;
rb : T_LABEL T_POP_RB const rb : T_LABEL T_POP_RB uconst
{ {
sym_AddEqu( $1, sym_GetConstantValue("_RS") ); sym_AddEqu( $1, sym_GetConstantValue("_RS") );
sym_AddSet( "_RS", sym_GetConstantValue("_RS")+$3 ); sym_AddSet( "_RS", sym_GetConstantValue("_RS")+$3 );
} }
; ;
ds : T_POP_DS const ds : T_POP_DS uconst
{ out_Skip( $2 ); } { out_Skip( $2 ); }
; ;
@@ -817,7 +822,7 @@ include : T_POP_INCLUDE string
incbin : T_POP_INCBIN string incbin : T_POP_INCBIN string
{ out_BinaryFile( $2 ); } { out_BinaryFile( $2 ); }
| T_POP_INCBIN string ',' const ',' const | T_POP_INCBIN string ',' uconst ',' uconst
{ {
out_BinaryFileSlice( $2, $4, $6 ); out_BinaryFileSlice( $2, $4, $6 );
} }
@@ -1038,6 +1043,14 @@ relocconst : T_ID
{ $$ = $2; } { $$ = $2; }
; ;
uconst : const
{
if($1 < 0)
fatalerror("Constant mustn't be negative: %d", $1);
$$=$1;
}
;
const : T_ID { $$ = sym_GetConstantValue($1); } const : T_ID { $$ = sym_GetConstantValue($1); }
| T_NUMBER { $$ = $1; } | T_NUMBER { $$ = $1; }
| string { $$ = str2int($1); } | string { $$ = str2int($1); }
@@ -1064,12 +1077,14 @@ const : T_ID { $$ = sym_GetConstantValue($1); }
| const T_OP_SHL const { $$ = $1 << $3; } | const T_OP_SHL const { $$ = $1 << $3; }
| const T_OP_SHR const { $$ = $1 >> $3; } | const T_OP_SHR const { $$ = $1 >> $3; }
| const T_OP_MUL const { $$ = $1 * $3; } | const T_OP_MUL const { $$ = $1 * $3; }
| const T_OP_DIV const { | const T_OP_DIV const
{
if ($3 == 0) if ($3 == 0)
fatalerror("division by zero"); fatalerror("division by zero");
$$ = $1 / $3; $$ = $1 / $3;
} }
| const T_OP_MOD const { | const T_OP_MOD const
{
if ($3 == 0) if ($3 == 0)
fatalerror("division by zero"); fatalerror("division by zero");
$$ = $1 % $3; $$ = $1 % $3;
@@ -1109,7 +1124,7 @@ const : T_ID { $$ = sym_GetConstantValue($1); }
string : T_STRING string : T_STRING
{ strcpy($$,$1); } { strcpy($$,$1); }
| T_OP_STRSUB '(' string ',' const ',' const ')' | T_OP_STRSUB '(' string ',' uconst ',' uconst ')'
{ strncpy($$,$3+$5-1,$7); $$[$7]=0; } { strncpy($$,$3+$5-1,$7); $$[$7]=0; }
| T_OP_STRCAT '(' string ',' string ')' | T_OP_STRCAT '(' string ',' string ')'
{ strcpy($$,$3); strcat($$,$5); } { strcpy($$,$3); strcat($$,$5); }
@@ -1123,33 +1138,33 @@ section:
{ {
out_NewSection($2,$4); out_NewSection($2,$4);
} }
| T_POP_SECTION string ',' sectiontype '[' const ']' | T_POP_SECTION string ',' sectiontype '[' uconst ']'
{ {
if( $6>=0 && $6<0x10000 ) if( $6>=0 && $6<0x10000 )
out_NewAbsSection($2,$4,$6,-1); out_NewAbsSection($2,$4,$6,-1);
else else
yyerror("Address $%x not 16-bit", $6); yyerror("Address $%x not 16-bit", $6);
} }
| T_POP_SECTION string ',' sectiontype ',' T_OP_ALIGN '[' const ']' | T_POP_SECTION string ',' sectiontype ',' T_OP_ALIGN '[' uconst ']'
{ {
out_NewAlignedSection($2, $4, $8, -1); out_NewAlignedSection($2, $4, $8, -1);
} }
| T_POP_SECTION string ',' sectiontype ',' T_OP_BANK '[' const ']' | T_POP_SECTION string ',' sectiontype ',' T_OP_BANK '[' uconst ']'
{ {
bankrangecheck($2, $4, -1, $8); bankrangecheck($2, $4, -1, $8);
} }
| T_POP_SECTION string ',' sectiontype '[' const ']' ',' T_OP_BANK '[' const ']' | T_POP_SECTION string ',' sectiontype '[' uconst ']' ',' T_OP_BANK '[' uconst ']'
{ {
if ($6 < 0 || $6 > 0x10000) { if ($6 < 0 || $6 > 0x10000) {
yyerror("Address $%x not 16-bit", $6); yyerror("Address $%x not 16-bit", $6);
} }
bankrangecheck($2, $4, $6, $11); bankrangecheck($2, $4, $6, $11);
} }
| T_POP_SECTION string ',' sectiontype ',' T_OP_ALIGN '[' const ']' ',' T_OP_BANK '[' const ']' | T_POP_SECTION string ',' sectiontype ',' T_OP_ALIGN '[' uconst ']' ',' T_OP_BANK '[' uconst ']'
{ {
out_NewAlignedSection($2, $4, $8, $13); out_NewAlignedSection($2, $4, $8, $13);
} }
| T_POP_SECTION string ',' sectiontype ',' T_OP_BANK '[' const ']' ',' T_OP_ALIGN '[' const ']' | T_POP_SECTION string ',' sectiontype ',' T_OP_BANK '[' uconst ']' ',' T_OP_ALIGN '[' uconst ']'
{ {
out_NewAlignedSection($2, $4, $13, $8); out_NewAlignedSection($2, $4, $13, $8);
} }

View File

@@ -475,6 +475,7 @@ setuplex(void)
lex_FloatAddSecondRange(id, '\\', '\\'); lex_FloatAddSecondRange(id, '\\', '\\');
lex_FloatAddSecondRange(id, '@', '@'); lex_FloatAddSecondRange(id, '@', '@');
lex_FloatAddSecondRange(id, '#', '#'); lex_FloatAddSecondRange(id, '#', '#');
lex_FloatAddRange(id, '.', '.');
lex_FloatAddRange(id, 'a', 'z'); lex_FloatAddRange(id, 'a', 'z');
lex_FloatAddRange(id, 'A', 'Z'); lex_FloatAddRange(id, 'A', 'Z');
lex_FloatAddRange(id, '0', '9'); lex_FloatAddRange(id, '0', '9');

View File

@@ -260,10 +260,6 @@ writesymbol(struct sSymbol * pSym, FILE * f)
sectid = -1; sectid = -1;
type = SYM_IMPORT; type = SYM_IMPORT;
} else { } else {
if (pSym->nType & SYMF_LOCAL) {
strcpy(symname, pSym->pScope->tzName);
strcat(symname, pSym->tzName);
} else
strcpy(symname, pSym->tzName); strcpy(symname, pSym->tzName);
if (pSym->nType & SYMF_EXPORT) { if (pSym->nType & SYMF_EXPORT) {

View File

@@ -223,13 +223,17 @@ GlobalLabel
AnotherGlobal: AnotherGlobal:
\&.locallabel \&.locallabel
\&.yet_a_local: \&.yet_a_local:
AnotherGlobal.with_another_local:
ThisWillBeExported:: ;note the two colons ThisWillBeExported:: ;note the two colons
ThisWillBeExported.too::
.Ed .Ed
.Pp .Pp
In the line where a label is defined there musn't be any whitespace before it. In the line where a label is defined there musn't be any whitespace before it.
Local labels are only accessible within the scope they are defined. Local labels are only accessible within the scope they are defined.
A scope starts after a global label and ends at the next global label. A scope starts after a global label and ends at the next global label.
Declaring a normal label with :: does an EXPORT at the same time. Declaring a label (global or local) with :: does an EXPORT at the same time.
Local labels can be declared as scope.local or simply as as .local.
If the former notation is used, the scope must be the actual current scope.
.Pp .Pp
Labels will normally change their value during the link process and are thus not Labels will normally change their value during the link process and are thus not
constant. constant.
@@ -303,6 +307,8 @@ There are four commands in the RS group of commands:
.Ic _RS No and adds Ar constexpr No to Ic _RS . .Ic _RS No and adds Ar constexpr No to Ic _RS .
.It Ic RW Ar constexpr Ta Sets the preceding symbol to .It Ic RW Ar constexpr Ta Sets the preceding symbol to
.Ic _RS No and adds Ar constexpr No * 2 to Ic _RS. .Ic _RS No and adds Ar constexpr No * 2 to Ic _RS.
.It Ic RL Ar constexpr Ta Sets the preceding symbol to
.Ic _RS No and adds Ar constexpr No * 4 to Ic _RS.
.El .El
.Pp .Pp
Note that a colon (:) following the symbol-name is not allowed. Note that a colon (:) following the symbol-name is not allowed.
@@ -992,6 +998,7 @@ machine.
.It Sx PUSHS .It Sx PUSHS
.It Sx REPT .It Sx REPT
.It Sx RB .It Sx RB
.It Sx RL
.It Sx ROM0 .It Sx ROM0
.It Sx ROMX .It Sx ROMX
.It Sx RSRESET .It Sx RSRESET

View File

@@ -114,26 +114,16 @@ createsymbol(char *s)
return (NULL); return (NULL);
} }
} }
/* /*
* Find a symbol by name and scope * Creates the full name of a local symbol in a given scope, by prepending
* the name with the parent symbol's name.
*/ */
struct sSymbol * size_t
findsymbol(char *s, struct sSymbol * scope) fullSymbolName(char *output, size_t outputSize, char *localName, struct sSymbol *scope)
{ {
struct sSymbol **ppsym; struct sSymbol *parent = scope->pScope ? scope->pScope : scope;
SLONG hash; return snprintf(output, outputSize, "%s%s", parent->tzName, localName);
hash = calchash(s);
ppsym = &(tHashedSymbols[hash]);
while ((*ppsym) != NULL) {
if ((strcmp(s, (*ppsym)->tzName) == 0)
&& ((*ppsym)->pScope == scope)) {
return (*ppsym);
} else
ppsym = &((*ppsym)->pNext);
}
return (NULL);
} }
/* /*
@@ -144,13 +134,25 @@ findpsymbol(char *s, struct sSymbol * scope)
{ {
struct sSymbol **ppsym; struct sSymbol **ppsym;
SLONG hash; SLONG hash;
char fullname[MAXSYMLEN + 1];
if (s[0] == '.' && scope) {
fullSymbolName(fullname, sizeof(fullname), s, scope);
s = fullname;
}
char *seperator;
if ((seperator = strchr(s, '.'))) {
if (strchr(seperator + 1, '.')) {
fatalerror("'%s' is a nonsensical reference to a nested local symbol", s);
}
}
hash = calchash(s); hash = calchash(s);
ppsym = &(tHashedSymbols[hash]); ppsym = &(tHashedSymbols[hash]);
while ((*ppsym) != NULL) { while ((*ppsym) != NULL) {
if ((strcmp(s, (*ppsym)->tzName) == 0) if ((strcmp(s, (*ppsym)->tzName) == 0)) {
&& ((*ppsym)->pScope == scope)) {
return (ppsym); return (ppsym);
} else } else
ppsym = &((*ppsym)->pNext); ppsym = &((*ppsym)->pNext);
@@ -158,6 +160,16 @@ findpsymbol(char *s, struct sSymbol * scope)
return (NULL); return (NULL);
} }
/*
* Find a symbol by name and scope
*/
struct sSymbol *
findsymbol(char *s, struct sSymbol * scope)
{
struct sSymbol **ppsym = findpsymbol(s, scope);
return ppsym ? *ppsym : NULL;
}
/* /*
* Find a symbol by name and scope * Find a symbol by name and scope
*/ */
@@ -593,30 +605,16 @@ sym_AddSet(char *tzSym, SLONG value)
void void
sym_AddLocalReloc(char *tzSym) sym_AddLocalReloc(char *tzSym)
{ {
if ((nPass == 1)
|| ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
/* only add local reloc symbols in pass 1 */
struct sSymbol *nsym;
if (pScope) { if (pScope) {
if ((nsym = findsymbol(tzSym, pScope)) != NULL) { if (strlen(tzSym) + strlen(pScope->tzName) > MAXSYMLEN) {
if (nsym->nType & SYMF_DEFINED) { fatalerror("Symbol too long");
yyerror("'%s' already defined", tzSym);
} }
} else
nsym = createsymbol(tzSym);
if (nsym) { char fullname[MAXSYMLEN + 1];
nsym->nValue = nPC; fullSymbolName(fullname, sizeof(fullname), tzSym, pScope);
nsym->nType |= sym_AddReloc(fullname);
SYMF_RELOC | SYMF_LOCAL | SYMF_DEFINED;
if (exportall) { } else {
nsym->nType |= SYMF_EXPORT;
}
nsym->pScope = pScope;
nsym->pSection = pCurrentSection;
}
} else
fatalerror("Local label in main scope"); fatalerror("Local label in main scope");
} }
} }
@@ -627,12 +625,32 @@ sym_AddLocalReloc(char *tzSym)
void void
sym_AddReloc(char *tzSym) sym_AddReloc(char *tzSym)
{ {
struct sSymbol* scope = NULL;
if ((nPass == 1) if ((nPass == 1)
|| ((nPass == 2) && (sym_isDefined(tzSym) == 0))) { || ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
/* only add reloc symbols in pass 1 */ /* only add reloc symbols in pass 1 */
struct sSymbol *nsym; struct sSymbol *nsym;
char *localPtr = NULL;
if ((nsym = findsymbol(tzSym, NULL)) != NULL) { if ((localPtr = strchr(tzSym, '.')) != NULL) {
if (!pScope) {
fatalerror("Local label in main scope");
}
struct sSymbol *parent = pScope->pScope ? pScope->pScope : pScope;
int parentLen = localPtr - tzSym;
if (strchr(localPtr + 1, '.') != NULL) {
fatalerror("'%s' is a nonsensical reference to a nested local symbol", tzSym);
} else if (strlen(parent->tzName) != parentLen || strncmp(tzSym, parent->tzName, parentLen) != 0) {
yyerror("Not currently in the scope of '%.*s'", parentLen, tzSym);
}
scope = parent;
}
if ((nsym = findsymbol(tzSym, scope)) != NULL) {
if (nsym->nType & SYMF_DEFINED) { if (nsym->nType & SYMF_DEFINED) {
yyerror("'%s' already defined", tzSym); yyerror("'%s' already defined", tzSym);
} }
@@ -642,14 +660,17 @@ sym_AddReloc(char *tzSym)
if (nsym) { if (nsym) {
nsym->nValue = nPC; nsym->nValue = nPC;
nsym->nType |= SYMF_RELOC | SYMF_DEFINED; nsym->nType |= SYMF_RELOC | SYMF_DEFINED;
if (localPtr) {
nsym->nType |= SYMF_LOCAL;
}
if (exportall) { if (exportall) {
nsym->nType |= SYMF_EXPORT; nsym->nType |= SYMF_EXPORT;
} }
nsym->pScope = NULL; nsym->pScope = scope;
nsym->pSection = pCurrentSection; nsym->pSection = pCurrentSection;
} }
} }
pScope = findsymbol(tzSym, NULL); pScope = findsymbol(tzSym, scope);
} }
/* /*
@@ -705,7 +726,7 @@ sym_Export(char *tzSym)
/* only export symbols in pass 1 */ /* only export symbols in pass 1 */
struct sSymbol *nsym; struct sSymbol *nsym;
if ((nsym = findsymbol(tzSym, 0)) == NULL) if ((nsym = sym_FindSymbol(tzSym)) == NULL)
nsym = createsymbol(tzSym); nsym = createsymbol(tzSym);
if (nsym) if (nsym)
@@ -713,7 +734,7 @@ sym_Export(char *tzSym)
} else { } else {
struct sSymbol *nsym; struct sSymbol *nsym;
if ((nsym = findsymbol(tzSym, 0)) != NULL) { if ((nsym = sym_FindSymbol(tzSym)) != NULL) {
if (nsym->nType & SYMF_DEFINED) if (nsym->nType & SYMF_DEFINED)
return; return;
} }
@@ -732,7 +753,7 @@ sym_Global(char *tzSym)
/* only globalize symbols in pass 2 */ /* only globalize symbols in pass 2 */
struct sSymbol *nsym; struct sSymbol *nsym;
nsym = findsymbol(tzSym, 0); nsym = sym_FindSymbol(tzSym);
if ((nsym == NULL) || ((nsym->nType & SYMF_DEFINED) == 0)) { if ((nsym == NULL) || ((nsym->nType & SYMF_DEFINED) == 0)) {
if (nsym == NULL) if (nsym == NULL)

View File

@@ -0,0 +1,6 @@
SECTION "sec", ROM0
Parent:
db 0
WrongParent.child
db 0

View File

@@ -0,0 +1,3 @@
ERROR: local-wrong-parent.asm(5):
Not currently in the scope of 'WrongParent'
error: Assembly aborted in pass 1 (1 errors)!

View File

@@ -0,0 +1,7 @@
SECTION "sec", ROM0
Parent:
Parent.child::
db 0
NotParent:
dw Parent.child

View File

View File

@@ -0,0 +1,7 @@
SECTION "sec", ROM0
Parent:
.child:
db 0
NotParent:
dw Parent.child.fail

View File

@@ -0,0 +1,2 @@
ERROR: remote-local-noexist.asm(7):
'Parent.child.fail' is a nonsensical reference to a nested local symbol

View File

@@ -0,0 +1,7 @@
SECTION "sec", ROM0
Parent:
.child:
db 0
NotParent:
dw Parent.child

View File