mirror of
https://github.com/ksherlock/x65.git
synced 2025-01-15 17:31:19 +00:00
commit
4b7e679b20
@ -6,12 +6,32 @@
|
|||||||
dc.b rept
|
dc.b rept
|
||||||
.ENDR
|
.ENDR
|
||||||
|
|
||||||
|
eval Checking defined function, Should be 0: .defined(test_stack)
|
||||||
test_stack = 0
|
test_stack = 0
|
||||||
|
eval Checking referenced function, Should be 0: .referenced(test_stack)
|
||||||
|
eval Checking defined function, Should be 1: .defined(test_stack)
|
||||||
PUSH test_stack
|
PUSH test_stack
|
||||||
|
eval Checking referenced function, Should be 1: .referenced(test_stack)
|
||||||
test_stack = 10
|
test_stack = 10
|
||||||
eval test_stack
|
eval Push Before Pull: test_stack
|
||||||
PULL test_stack
|
PULL test_stack
|
||||||
eval test_stack
|
eval Pull original: test_stack
|
||||||
|
|
||||||
|
eval Checking symbol is not const (0): .const(test_stack)
|
||||||
|
const ConstAddress = $1000
|
||||||
|
eval Checking symbol is const (0): .const(ConstAddress)
|
||||||
|
|
||||||
|
eval This should be blank (1): .blank()
|
||||||
|
eval This should be blank (1): .blank({})
|
||||||
|
eval This should be not be blank (0): .blank({monkeys})
|
||||||
|
|
||||||
|
.ifconst test_stack
|
||||||
|
eval Checking ifconst with non-const symbol, should not print:
|
||||||
|
.endif
|
||||||
|
|
||||||
|
.ifconst ConstAddress
|
||||||
|
eval Checking ifconst with const symbol, this should print:
|
||||||
|
.endif
|
||||||
|
|
||||||
zp_len_lo = $a7
|
zp_len_lo = $a7
|
||||||
zp_len_hi = $a8
|
zp_len_hi = $a8
|
||||||
|
141
x65.cpp
141
x65.cpp
@ -279,6 +279,9 @@ enum AssemblerDirective {
|
|||||||
AD_IF, // #IF: Conditional assembly follows based on expression
|
AD_IF, // #IF: Conditional assembly follows based on expression
|
||||||
AD_IFDEF, // #IFDEF: Conditional assembly follows based on label defined or not
|
AD_IFDEF, // #IFDEF: Conditional assembly follows based on label defined or not
|
||||||
AD_IFNDEF, // #IFNDEF: Conditional assembly inverted from IFDEF
|
AD_IFNDEF, // #IFNDEF: Conditional assembly inverted from IFDEF
|
||||||
|
AD_IFCONST, // #IFCONST: Conditional assembly follows based on label being const
|
||||||
|
AD_IFBLANK, // #IFBLANK: Conditional assembly follows based on rest of line empty
|
||||||
|
AD_IFNBLANK, // #IFNBLANK: Conditional assembly follows based on rest of line not empty
|
||||||
AD_ELSE, // #ELSE: Otherwise assembly
|
AD_ELSE, // #ELSE: Otherwise assembly
|
||||||
AD_ELIF, // #ELIF: Otherwise conditional assembly follows
|
AD_ELIF, // #ELIF: Otherwise conditional assembly follows
|
||||||
AD_ENDIF, // #ENDIF: End a block of #IF/#IFDEF
|
AD_ENDIF, // #ENDIF: End a block of #IF/#IFDEF
|
||||||
@ -314,6 +317,15 @@ enum AssemblerDirective {
|
|||||||
AD_ERROR,
|
AD_ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// evaluation functions
|
||||||
|
enum EvalFuncs {
|
||||||
|
EF_DEFINED, // DEFINED(label) 1 if label is defined
|
||||||
|
EF_REFERENCED, // REFERENCED(label) 1 if label has been referenced in this file
|
||||||
|
EF_BLANK, // BLANK() 1 if the contents within the parenthesis is empty
|
||||||
|
EF_CONST, // CONST(label) 1 if label is a const label
|
||||||
|
EF_SIN, // SIN(index, period, amplitude)
|
||||||
|
};
|
||||||
|
|
||||||
// Operators are either instructions or directives
|
// Operators are either instructions or directives
|
||||||
enum OperationType {
|
enum OperationType {
|
||||||
OT_NONE,
|
OT_NONE,
|
||||||
@ -997,6 +1009,9 @@ DirectiveName aDirectiveNames[] {
|
|||||||
{ "IF", AD_IF },
|
{ "IF", AD_IF },
|
||||||
{ "IFDEF", AD_IFDEF },
|
{ "IFDEF", AD_IFDEF },
|
||||||
{ "IFNDEF", AD_IFNDEF },
|
{ "IFNDEF", AD_IFNDEF },
|
||||||
|
{ "IFCONST", AD_IFCONST },
|
||||||
|
{ "IFBLANK", AD_IFBLANK }, // #IFBLANK: Conditional assembly follows based on rest of line empty
|
||||||
|
{ "IFNBLANK", AD_IFNBLANK }, // #IFDEF: Conditional assembly follows based on rest of line not empty
|
||||||
{ "ELSE", AD_ELSE },
|
{ "ELSE", AD_ELSE },
|
||||||
{ "ELIF", AD_ELIF },
|
{ "ELIF", AD_ELIF },
|
||||||
{ "ENDIF", AD_ENDIF },
|
{ "ENDIF", AD_ENDIF },
|
||||||
@ -1058,8 +1073,23 @@ DirectiveName aDirectiveNamesMerlin[] {
|
|||||||
{ "CYC", AD_CYC }, // MERLIN: Start and stop cycle counter
|
{ "CYC", AD_CYC }, // MERLIN: Start and stop cycle counter
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct EvalFuncNames {
|
||||||
|
const char* name;
|
||||||
|
EvalFuncs function;
|
||||||
|
};
|
||||||
|
|
||||||
|
EvalFuncNames aEvalFunctions[] = {
|
||||||
|
{ "DEFINED", EF_DEFINED }, // DEFINED(label) 1 if label is defined
|
||||||
|
{ "DEF", EF_DEFINED }, // DEFINED(label) 1 if label is defined
|
||||||
|
{ "REFERENCED", EF_REFERENCED }, // REFERENCED(label) 1 if label has been referenced in this file
|
||||||
|
{ "BLANK", EF_BLANK }, // BLANK() 1 if the contents within the parenthesis is empty
|
||||||
|
{ "CONST", EF_CONST }, // CONST(label) 1 if label is a const label
|
||||||
|
{ "TRIGSIN", EF_SIN }, // TRIGSIN(index, period, amplitude)
|
||||||
|
};
|
||||||
|
|
||||||
static const int nDirectiveNames = sizeof(aDirectiveNames) / sizeof(aDirectiveNames[0]);
|
static const int nDirectiveNames = sizeof(aDirectiveNames) / sizeof(aDirectiveNames[0]);
|
||||||
static const int nDirectiveNamesMerlin = sizeof(aDirectiveNamesMerlin) / sizeof(aDirectiveNamesMerlin[0]);
|
static const int nDirectiveNamesMerlin = sizeof(aDirectiveNamesMerlin) / sizeof(aDirectiveNamesMerlin[0]);
|
||||||
|
static const int nEvalFuncs = sizeof(aEvalFunctions) / sizeof(aEvalFunctions[0]);
|
||||||
|
|
||||||
// Binary search over an array of unsigned integers, may contain multiple instances of same key
|
// Binary search over an array of unsigned integers, may contain multiple instances of same key
|
||||||
uint32_t FindLabelIndex(uint32_t hash, uint32_t *table, uint32_t count)
|
uint32_t FindLabelIndex(uint32_t hash, uint32_t *table, uint32_t count)
|
||||||
@ -1533,6 +1563,7 @@ public:
|
|||||||
bool constant; // the value of this label can not change
|
bool constant; // the value of this label can not change
|
||||||
bool external; // this label is globally accessible
|
bool external; // this label is globally accessible
|
||||||
bool reference; // this label is accessed from external and can't be used for evaluation locally
|
bool reference; // this label is accessed from external and can't be used for evaluation locally
|
||||||
|
bool referenced; // this label has been found via GetLabel and can be assumed to be referenced for some purpose
|
||||||
} Label;
|
} Label;
|
||||||
|
|
||||||
|
|
||||||
@ -1819,6 +1850,9 @@ public:
|
|||||||
StatusCode EvalStruct(strref name, int &value);
|
StatusCode EvalStruct(strref name, int &value);
|
||||||
StatusCode BuildEnum(strref name, strref declaration);
|
StatusCode BuildEnum(strref name, strref declaration);
|
||||||
|
|
||||||
|
// Check if function is a valid function and if so evaluate the expression
|
||||||
|
bool EvalFunction(strref function, strref &expression, int &value);
|
||||||
|
|
||||||
// Calculate a value based on an expression.
|
// Calculate a value based on an expression.
|
||||||
EvalOperator RPNToken_Merlin(strref &expression, const struct EvalContext &etx,
|
EvalOperator RPNToken_Merlin(strref &expression, const struct EvalContext &etx,
|
||||||
EvalOperator prev_op, int16_t §ion, int &value);
|
EvalOperator prev_op, int16_t §ion, int &value);
|
||||||
@ -1830,7 +1864,7 @@ public:
|
|||||||
int ReptCnt() const;
|
int ReptCnt() const;
|
||||||
|
|
||||||
// Access labels
|
// Access labels
|
||||||
Label* GetLabel(strref label);
|
Label * GetLabel(strref label, bool reference_check = false);
|
||||||
Label* GetLabel(strref label, int file_ref);
|
Label* GetLabel(strref label, int file_ref);
|
||||||
Label* AddLabel(uint32_t hash);
|
Label* AddLabel(uint32_t hash);
|
||||||
bool MatchXDEF(strref label);
|
bool MatchXDEF(strref label);
|
||||||
@ -1974,7 +2008,7 @@ StatusCode SymbolStackTable::PullSymbol(StringSymbol* string)
|
|||||||
} else {
|
} else {
|
||||||
if (string->string_value.empty() || string->string_value.cap() < (strlen(str) + 1)) {
|
if (string->string_value.empty() || string->string_value.cap() < (strlen(str) + 1)) {
|
||||||
if (string->string_value.charstr()) { free(string->string_value.charstr()); }
|
if (string->string_value.charstr()) { free(string->string_value.charstr()); }
|
||||||
string->string_value.set_overlay((char*)malloc(strlen(str) + 1), strlen(str) + 1);
|
string->string_value.set_overlay((char*)malloc(strlen(str) + 1), (strl_t)strlen(str) + 1);
|
||||||
}
|
}
|
||||||
string->string_value.copy(str);
|
string->string_value.copy(str);
|
||||||
free(str);
|
free(str);
|
||||||
@ -3415,6 +3449,56 @@ StatusCode Asm::EvalStruct(strref name, int &value) {
|
|||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// EVAL FUNCTIONS
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
bool Asm::EvalFunction(strref function, strref& expression, int &value)
|
||||||
|
{
|
||||||
|
// all eval functions take a parenthesis with arguments
|
||||||
|
if (expression.get_first() != '(') { return false; }
|
||||||
|
|
||||||
|
strref expRet = expression;
|
||||||
|
strref params = expRet.scoped_block_comment_skip();
|
||||||
|
params.trim_whitespace();
|
||||||
|
if (function.get_first() == '.') { ++function; }
|
||||||
|
for (int i = 0; i < nEvalFuncs; ++i) {
|
||||||
|
if (function.same_str(aEvalFunctions[i].name)) {
|
||||||
|
switch (aEvalFunctions[i].function) {
|
||||||
|
case EF_DEFINED:
|
||||||
|
expression = expRet;
|
||||||
|
value = GetLabel(params, true) != nullptr ? 1 : 0;
|
||||||
|
return true;
|
||||||
|
case EF_REFERENCED:
|
||||||
|
expression = expRet;
|
||||||
|
if (Label* label = GetLabel(params, true)) { value = label->referenced; return true; }
|
||||||
|
return false;
|
||||||
|
case EF_BLANK:
|
||||||
|
expression = expRet;
|
||||||
|
if (params.get_first() == '{') { params = params.scoped_block_comment_skip(); }
|
||||||
|
params.trim_whitespace();
|
||||||
|
value = params.is_empty();
|
||||||
|
return true;
|
||||||
|
case EF_CONST:
|
||||||
|
expression = expRet;
|
||||||
|
if (Label* label = GetLabel(params, true)) {
|
||||||
|
return label->constant;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case EF_SIN:
|
||||||
|
expression = expRet;
|
||||||
|
value = 0; // TODO: implement trigsin
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// EXPRESSIONS AND LATE EVALUATION
|
// EXPRESSIONS AND LATE EVALUATION
|
||||||
@ -3556,6 +3640,7 @@ EvalOperator Asm::RPNToken(strref &exp, const struct EvalContext &etx, EvalOpera
|
|||||||
}
|
}
|
||||||
if (!pLabel && label.same_str("rept")) { value = etx.rept_cnt; return EVOP_VAL; }
|
if (!pLabel && label.same_str("rept")) { value = etx.rept_cnt; return EVOP_VAL; }
|
||||||
if (!pLabel) { if (StringSymbol *pStr = GetString(label)) { subexp = pStr->get(); return EVOP_EXP; } }
|
if (!pLabel) { if (StringSymbol *pStr = GetString(label)) { subexp = pStr->get(); return EVOP_EXP; } }
|
||||||
|
if (!pLabel) { if (EvalFunction(label, exp, value)) { return EVOP_VAL; } }
|
||||||
if (!pLabel || !pLabel->evaluated) return EVOP_NRY; // this label could not be found (yet)
|
if (!pLabel || !pLabel->evaluated) return EVOP_NRY; // this label could not be found (yet)
|
||||||
value = pLabel->value; section = int16_t(pLabel->section); return pLabel->reference ? EVOP_XRF : EVOP_VAL;
|
value = pLabel->value; section = int16_t(pLabel->section); return pLabel->reference ? EVOP_XRF : EVOP_VAL;
|
||||||
}
|
}
|
||||||
@ -4097,12 +4182,14 @@ StatusCode Asm::CheckLateEval(strref added_label, int scope_end, bool print_miss
|
|||||||
//
|
//
|
||||||
|
|
||||||
// Get a label record if it exists
|
// Get a label record if it exists
|
||||||
Label *Asm::GetLabel(strref label) {
|
Label *Asm::GetLabel(strref label, bool reference_check) {
|
||||||
uint32_t label_hash = label.fnv1a();
|
uint32_t label_hash = label.fnv1a();
|
||||||
uint32_t index = FindLabelIndex(label_hash, labels.getKeys(), labels.count());
|
uint32_t index = FindLabelIndex(label_hash, labels.getKeys(), labels.count());
|
||||||
while (index < labels.count() && label_hash == labels.getKey(index)) {
|
while (index < labels.count() && label_hash == labels.getKey(index)) {
|
||||||
if (label.same_str(labels.getValue(index).label_name)) {
|
if (label.same_str(labels.getValue(index).label_name)) {
|
||||||
return labels.getValues()+index;
|
Label *label = labels.getValues() + index;
|
||||||
|
if (!reference_check) { label->referenced = true; }
|
||||||
|
return label;
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -4117,7 +4204,9 @@ Label *Asm::GetLabel(strref label, int file_ref) {
|
|||||||
uint32_t index = FindLabelIndex(label_hash, labs.labels.getKeys(), labs.labels.count());
|
uint32_t index = FindLabelIndex(label_hash, labs.labels.getKeys(), labs.labels.count());
|
||||||
while (index < labs.labels.count() && label_hash == labs.labels.getKey(index)) {
|
while (index < labs.labels.count() && label_hash == labs.labels.getKey(index)) {
|
||||||
if (label.same_str(labs.labels.getValue(index).label_name)) {
|
if (label.same_str(labs.labels.getValue(index).label_name)) {
|
||||||
return labs.labels.getValues()+index;
|
Label *label = labs.labels.getValues()+index;
|
||||||
|
label->referenced = true;
|
||||||
|
return label;
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -4311,6 +4400,7 @@ StatusCode Asm::AssignPoolLabel(LabelPool &pool, strref label) {
|
|||||||
pLabel->constant = true;
|
pLabel->constant = true;
|
||||||
pLabel->external = false;
|
pLabel->external = false;
|
||||||
pLabel->reference = false;
|
pLabel->reference = false;
|
||||||
|
pLabel->referenced = false;
|
||||||
bool local = false;
|
bool local = false;
|
||||||
|
|
||||||
if (label[ 0 ] == '.' || label[ 0 ] == '@' || label[ 0 ] == '!' || label[ 0 ] == ':' || label.get_last() == '$') {
|
if (label[ 0 ] == '.' || label[ 0 ] == '@' || label[ 0 ] == '!' || label[ 0 ] == ':' || label.get_last() == '$') {
|
||||||
@ -4367,7 +4457,7 @@ StatusCode Asm::AssignLabel(strref label, strref expression, bool make_constant)
|
|||||||
if (pLabel->constant && pLabel->evaluated && val!=pLabel->value) {
|
if (pLabel->constant && pLabel->evaluated && val!=pLabel->value) {
|
||||||
return (status==STATUS_NOT_READY) ? STATUS_OK : ERROR_MODIFYING_CONST_LABEL;
|
return (status==STATUS_NOT_READY) ? STATUS_OK : ERROR_MODIFYING_CONST_LABEL;
|
||||||
}
|
}
|
||||||
} else { pLabel = AddLabel(label.fnv1a()); }
|
} else { pLabel = AddLabel(label.fnv1a()); pLabel->referenced = false; }
|
||||||
|
|
||||||
pLabel->label_name = label;
|
pLabel->label_name = label;
|
||||||
pLabel->pool_name.clear();
|
pLabel->pool_name.clear();
|
||||||
@ -4399,6 +4489,7 @@ StatusCode Asm::AddressLabel(strref label)
|
|||||||
bool constLabel = false;
|
bool constLabel = false;
|
||||||
if (!pLabel) {
|
if (!pLabel) {
|
||||||
pLabel = AddLabel(label.fnv1a());
|
pLabel = AddLabel(label.fnv1a());
|
||||||
|
pLabel->referenced = false; // if this label already exists but is changed then it may already have been referenced
|
||||||
} else if (pLabel->constant && pLabel->value!=CurrSection().GetPC()) {
|
} else if (pLabel->constant && pLabel->value!=CurrSection().GetPC()) {
|
||||||
return ERROR_MODIFYING_CONST_LABEL;
|
return ERROR_MODIFYING_CONST_LABEL;
|
||||||
} else { constLabel = pLabel->constant; }
|
} else { constLabel = pLabel->constant; }
|
||||||
@ -5093,6 +5184,7 @@ StatusCode Asm::Directive_XREF(strref label)
|
|||||||
pLabelXREF->external = true;
|
pLabelXREF->external = true;
|
||||||
pLabelXREF->constant = false;
|
pLabelXREF->constant = false;
|
||||||
pLabelXREF->reference = true;
|
pLabelXREF->reference = true;
|
||||||
|
pLabelXREF->referenced = false; // referenced is only within the current object file
|
||||||
}
|
}
|
||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
}
|
}
|
||||||
@ -5528,6 +5620,41 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AD_IFCONST:
|
||||||
|
if (NewConditional()) { // Start new conditional block
|
||||||
|
CheckConditionalDepth(); // Check if nesting
|
||||||
|
// ifdef doesn't need to evaluate the value, just determine if it exists or not
|
||||||
|
strref label_name = line.split_range_trim(label_end_char_range);
|
||||||
|
if (Label* label = GetLabel(label_name, etx.file_ref)) {
|
||||||
|
if (label->constant) { ConsumeConditional(); }
|
||||||
|
else { SetConditional(); }
|
||||||
|
}
|
||||||
|
else { SetConditional(); }
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AD_IFBLANK:
|
||||||
|
if (NewConditional()) { // Start new conditional block
|
||||||
|
CheckConditionalDepth(); // Check if nesting
|
||||||
|
line.trim_whitespace();
|
||||||
|
if (line.is_empty())
|
||||||
|
ConsumeConditional();
|
||||||
|
else
|
||||||
|
SetConditional();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AD_IFNBLANK:
|
||||||
|
if (NewConditional()) { // Start new conditional block
|
||||||
|
CheckConditionalDepth(); // Check if nesting
|
||||||
|
line.trim_whitespace();
|
||||||
|
if (!line.is_empty())
|
||||||
|
ConsumeConditional();
|
||||||
|
else
|
||||||
|
SetConditional();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case AD_ELSE:
|
case AD_ELSE:
|
||||||
if (ConditionalAsm()) {
|
if (ConditionalAsm()) {
|
||||||
if (ConditionalConsumed())
|
if (ConditionalConsumed())
|
||||||
@ -7194,7 +7321,7 @@ StatusCode Asm::ReadObjectFile(strref filename, int link_to_section)
|
|||||||
int16_t f = (int16_t)l.flags;
|
int16_t f = (int16_t)l.flags;
|
||||||
int external = f & ObjFileLabel::OFL_XDEF;
|
int external = f & ObjFileLabel::OFL_XDEF;
|
||||||
if (external == ObjFileLabel::OFL_XDEF) {
|
if (external == ObjFileLabel::OFL_XDEF) {
|
||||||
if (!lbl) { lbl = AddLabel(name.fnv1a()); } // insert shared label
|
if (!lbl) { lbl = AddLabel(name.fnv1a()); lbl->referenced = false; } // insert shared label
|
||||||
else if (!lbl->reference) { continue; }
|
else if (!lbl->reference) { continue; }
|
||||||
} else { // insert protected label
|
} else { // insert protected label
|
||||||
while ((file_index + external) >= (int)externals.size()) {
|
while ((file_index + external) >= (int)externals.size()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user