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

View File

@@ -475,6 +475,7 @@ setuplex(void)
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, '0', '9');

View File

@@ -260,11 +260,7 @@ writesymbol(struct sSymbol * pSym, FILE * f)
sectid = -1;
type = SYM_IMPORT;
} 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) {
/* Symbol should be exported */

View File

@@ -223,13 +223,17 @@ GlobalLabel
AnotherGlobal:
\&.locallabel
\&.yet_a_local:
AnotherGlobal.with_another_local:
ThisWillBeExported:: ;note the two colons
ThisWillBeExported.too::
.Ed
.Pp
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.
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
Labels will normally change their value during the link process and are thus not
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 .
.It Ic RW Ar constexpr Ta Sets the preceding symbol to
.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
.Pp
Note that a colon (:) following the symbol-name is not allowed.
@@ -992,6 +998,7 @@ machine.
.It Sx PUSHS
.It Sx REPT
.It Sx RB
.It Sx RL
.It Sx ROM0
.It Sx ROMX
.It Sx RSRESET

View File

@@ -114,26 +114,16 @@ createsymbol(char *s)
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 *
findsymbol(char *s, struct sSymbol * scope)
size_t
fullSymbolName(char *output, size_t outputSize, char *localName, struct sSymbol *scope)
{
struct sSymbol **ppsym;
SLONG hash;
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);
struct sSymbol *parent = scope->pScope ? scope->pScope : scope;
return snprintf(output, outputSize, "%s%s", parent->tzName, localName);
}
/*
@@ -144,13 +134,25 @@ findpsymbol(char *s, struct sSymbol * scope)
{
struct sSymbol **ppsym;
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);
ppsym = &(tHashedSymbols[hash]);
while ((*ppsym) != NULL) {
if ((strcmp(s, (*ppsym)->tzName) == 0)
&& ((*ppsym)->pScope == scope)) {
if ((strcmp(s, (*ppsym)->tzName) == 0)) {
return (ppsym);
} else
ppsym = &((*ppsym)->pNext);
@@ -158,6 +160,16 @@ findpsymbol(char *s, struct sSymbol * scope)
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
*/
@@ -593,31 +605,17 @@ sym_AddSet(char *tzSym, SLONG value)
void
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 ((nsym = findsymbol(tzSym, pScope)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
yyerror("'%s' already defined", tzSym);
}
} else
nsym = createsymbol(tzSym);
if (nsym) {
nsym->nValue = nPC;
nsym->nType |=
SYMF_RELOC | SYMF_LOCAL | SYMF_DEFINED;
if (exportall) {
nsym->nType |= SYMF_EXPORT;
}
nsym->pScope = pScope;
nsym->pSection = pCurrentSection;
}
} else
fatalerror("Local label in main scope");
if (pScope) {
if (strlen(tzSym) + strlen(pScope->tzName) > MAXSYMLEN) {
fatalerror("Symbol too long");
}
char fullname[MAXSYMLEN + 1];
fullSymbolName(fullname, sizeof(fullname), tzSym, pScope);
sym_AddReloc(fullname);
} else {
fatalerror("Local label in main scope");
}
}
@@ -627,12 +625,32 @@ sym_AddLocalReloc(char *tzSym)
void
sym_AddReloc(char *tzSym)
{
struct sSymbol* scope = NULL;
if ((nPass == 1)
|| ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
/* only add reloc symbols in pass 1 */
struct sSymbol *nsym;
char *localPtr = 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, NULL)) != NULL) {
if ((nsym = findsymbol(tzSym, scope)) != NULL) {
if (nsym->nType & SYMF_DEFINED) {
yyerror("'%s' already defined", tzSym);
}
@@ -642,14 +660,17 @@ sym_AddReloc(char *tzSym)
if (nsym) {
nsym->nValue = nPC;
nsym->nType |= SYMF_RELOC | SYMF_DEFINED;
if (localPtr) {
nsym->nType |= SYMF_LOCAL;
}
if (exportall) {
nsym->nType |= SYMF_EXPORT;
}
nsym->pScope = NULL;
nsym->pScope = scope;
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 */
struct sSymbol *nsym;
if ((nsym = findsymbol(tzSym, 0)) == NULL)
if ((nsym = sym_FindSymbol(tzSym)) == NULL)
nsym = createsymbol(tzSym);
if (nsym)
@@ -713,7 +734,7 @@ sym_Export(char *tzSym)
} else {
struct sSymbol *nsym;
if ((nsym = findsymbol(tzSym, 0)) != NULL) {
if ((nsym = sym_FindSymbol(tzSym)) != NULL) {
if (nsym->nType & SYMF_DEFINED)
return;
}
@@ -732,7 +753,7 @@ sym_Global(char *tzSym)
/* only globalize symbols in pass 2 */
struct sSymbol *nsym;
nsym = findsymbol(tzSym, 0);
nsym = sym_FindSymbol(tzSym);
if ((nsym == NULL) || ((nsym->nType & SYMF_DEFINED) == 0)) {
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