mirror of
https://github.com/ksherlock/x65.git
synced 2024-12-26 22:30:50 +00:00
fixed IFDEF/IFNDEF, added partial support for CA65 style SCOPE, fixed -endm style macro parsing.
This commit is contained in:
parent
6e4be1504d
commit
66bdac5079
@ -23,32 +23,32 @@
|
||||
<ProjectGuid>{57EFF4A4-7BF2-43F0-AD62-A79092DA67D1}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>dump_x65</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
|
@ -29,26 +29,26 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
|
@ -278,7 +278,7 @@ TestOpcodes:
|
||||
mvp $21,$20
|
||||
mvn $21,$20
|
||||
pea $2120
|
||||
pei ($21)
|
||||
pei $21
|
||||
per $2120
|
||||
rep $21
|
||||
rep #$21
|
||||
|
62
test/ca65directive.s
Normal file
62
test/ca65directive.s
Normal file
@ -0,0 +1,62 @@
|
||||
; TEST CODE FROM EXOMIZER
|
||||
|
||||
.org $2000
|
||||
|
||||
zp_len_lo = $a7
|
||||
zp_len_hi = $a8
|
||||
|
||||
zp_src_lo = $ae
|
||||
zp_src_hi = zp_src_lo + 1
|
||||
|
||||
zp_bits_hi = $fc
|
||||
|
||||
zp_bitbuf = $fd
|
||||
zp_dest_lo = zp_bitbuf + 1 ; dest addr lo
|
||||
zp_dest_hi = zp_bitbuf + 2 ; dest addr hi
|
||||
|
||||
.MACRO mac_refill_bits
|
||||
pha
|
||||
jsr get_crunched_byte
|
||||
rol
|
||||
sta zp_bitbuf
|
||||
pla
|
||||
.ENDMACRO
|
||||
.MACRO mac_get_bits
|
||||
.SCOPE
|
||||
adc #$80 ; needs c=0, affects v
|
||||
asl
|
||||
bpl gb_skip
|
||||
gb_next:
|
||||
asl zp_bitbuf
|
||||
bne gb_ok
|
||||
mac_refill_bits
|
||||
gb_ok:
|
||||
rol
|
||||
bmi gb_next
|
||||
gb_skip:
|
||||
bvc skip
|
||||
gb_get_hi:
|
||||
sec
|
||||
sta zp_bits_hi
|
||||
jsr get_crunched_byte
|
||||
skip:
|
||||
.ENDSCOPE
|
||||
.ENDMACRO
|
||||
|
||||
|
||||
.ifdef UNDEFINED_SYMBOL
|
||||
dc.b -1 ; should not be assembled
|
||||
error 1
|
||||
.else
|
||||
dc.b 1 ; should be assembled
|
||||
.endif
|
||||
|
||||
const CONSTANT = 32
|
||||
|
||||
.eval CONSTANT
|
||||
|
||||
mac_get_bits
|
||||
mac_get_bits
|
||||
|
||||
get_crunched_byte:
|
||||
rts
|
@ -85,6 +85,16 @@ echo Merlin LUP test failed
|
||||
goto exit
|
||||
:merlup_pass
|
||||
|
||||
echo CA65 directives Test >>results\unittest.txt
|
||||
..\bin\x64\x65.exe ca65directive.s -lst -endm >>results\unittest.txt
|
||||
if %errorlevel% GTR 0 goto ca65_fail
|
||||
rem check data here when relevant
|
||||
if %errorlevel% EQU 0 goto ca65_pass
|
||||
:ca65_fail
|
||||
echo CA65 directives failed
|
||||
goto exit
|
||||
:ca65_pass
|
||||
|
||||
rem REVIEW MACROS!
|
||||
rem echo x65macro.i Test >>results\unittest.txt
|
||||
rem echo --------------- >>results\unittest.txt
|
||||
|
274
x65.cpp
274
x65.cpp
@ -40,6 +40,29 @@
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Command line arguments
|
||||
static const strref cmdarg_listing("lst"); // -lst / -lst=(file.lst) : generate disassembly text from result(file or stdout)
|
||||
static const strref cmdarg_tass_listing("tsl"); // -tsl=(file) : generate listing file in TASS style
|
||||
static const strref cmdarg_tass_labels("tl"); // -tl=(file) : generate labels in TASS style
|
||||
static const strref cmdarg_allinstr("opcodes"); // -opcodes / -opcodes=(file.s) : dump all available opcodes(file or stdout)
|
||||
static const strref cmdarg_endmacro("endm"); // -endm : macros end with endm or endmacro instead of scoped('{' - '}')
|
||||
static const strref cmdarg_cpu("cpu"); // declare CPU type, use with argument: -cpu=6502/65c02/65c02wdc/65816
|
||||
static const strref cmdarg_acc("acc"); // [65816] -acc=8/16: set the accumulator mode for 65816 at start, default is 8 bits
|
||||
static const strref cmdarg_xy("xy"); // [65816] -xy=8/16: set the index register mode for 65816 at start, default is 8 bits
|
||||
static const strref cmdarg_org("org"); // -org = $2000 or - org = 4096: force fixed address code at address
|
||||
static const strref cmdarg_kickasm("kickasm"); // -kickasm: use Kick Assembler syntax
|
||||
static const strref cmdarg_merlin("merlin"); // -merlin: use Merlin syntax
|
||||
static const strref cmdarg_c64("c64"); // -c64 : Include load address(default)
|
||||
static const strref cmdarg_a2b("a2b"); // -a2b : Apple II Dos 3.3 Binary
|
||||
static const strref cmdarg_bin("bin"); // -bin : Produce raw binary\n"
|
||||
static const strref cmdarg_a2p("a2p"); // -a2p : Apple II ProDos Binary
|
||||
static const strref cmdarg_a2o("a2o"); // -a2o : Apple II GS OS executable (relocatable)
|
||||
static const strref cmdarg_mrg("mrg"); // -mrg : Force merge all sections (use with -a2o)
|
||||
static const strref cmdarg_sect("sect"); // -sect: display sections loaded and built
|
||||
static const strref cmdarg_sym("sym"); // -sym (file.sym) : generate symbol file
|
||||
static const strref cmdarg_obj("obj"); // -obj (file.x65) : generate object file for later linking
|
||||
static const strref cmdarg_vice("vice"); // -vice (file.vs) : export a vice symbol file
|
||||
|
||||
// if the number of resolved labels exceed this in one late eval then skip
|
||||
// checking for relevance and just eval all unresolved expressions.
|
||||
#define MAX_LABELS_EVAL_ALL 16
|
||||
@ -153,72 +176,72 @@ enum StatusCode {
|
||||
|
||||
// The following strings are in the same order as StatusCode
|
||||
const char *aStatusStrings[STATUSCODE_COUNT] = {
|
||||
"ok",
|
||||
"relative section",
|
||||
"not ready",
|
||||
"XREF dependent result",
|
||||
"name is not a struct",
|
||||
"Exporting binary without code or data section",
|
||||
"Undefined code",
|
||||
"Unexpected character in expression",
|
||||
"Too many values in expression",
|
||||
"Too many operators in expression",
|
||||
"Unbalanced right parenthesis in expression",
|
||||
"Expression operation",
|
||||
"Expression missing values",
|
||||
"Instruction can not be zero page",
|
||||
"Invalid addressing mode for instruction",
|
||||
"Branch out of range",
|
||||
"Internal label organization mishap",
|
||||
"Bad addressing mode",
|
||||
"Unexpected character in addressing mode",
|
||||
"Unexpected label assignment format",
|
||||
"Changing value of label that is constant",
|
||||
"Out of labels in pool",
|
||||
"Internal label pool release confusion",
|
||||
"Label pool range evaluation failed",
|
||||
"Label pool was redeclared within its scope",
|
||||
"Pool label already defined",
|
||||
"Struct already defined",
|
||||
"Referenced struct not found",
|
||||
"Declare constant type not recognized (dc.?)",
|
||||
"rept count expression could not be evaluated",
|
||||
"hex must be followed by an even number of hex numbers",
|
||||
"DS directive failed to evaluate immediately",
|
||||
"File is not a valid x65 object file",
|
||||
"Failed to read include file",
|
||||
"User invoked error",
|
||||
"ok", // STATUS_OK, // everything is fine
|
||||
"relative section", // STATUS_RELATIVE_SECTION, // value is relative to a single section
|
||||
"not ready", // STATUS_NOT_READY, // label could not be evaluated at this time
|
||||
"XREF dependent result", // STATUS_XREF_DEPENDENT, // evaluated but relied on an XREF label to do so
|
||||
"name is not a struct", // STATUS_NOT_STRUCT, // return is not a struct.
|
||||
"Exporting binary without code or data section", // STATUS_EXPORT_NO_CODE_OR_DATA_SECTION,
|
||||
"Undefined code", // ERROR_UNDEFINED_CODE = FIRST_ERROR,
|
||||
"Unexpected character in expression", // ERROR_UNEXPECTED_CHARACTER_IN_EXPRESSION,
|
||||
"Too many values in expression", // ERROR_TOO_MANY_VALUES_IN_EXPRESSION,
|
||||
"Too many operators in expression", // ERROR_TOO_MANY_OPERATORS_IN_EXPRESSION,
|
||||
"Unbalanced right parenthesis in expression", // ERROR_UNBALANCED_RIGHT_PARENTHESIS,
|
||||
"Expression operation", // ERROR_EXPRESSION_OPERATION,
|
||||
"Expression missing values", // ERROR_EXPRESSION_MISSING_VALUES,
|
||||
"Instruction can not be zero page", // ERROR_INSTRUCTION_NOT_ZP,
|
||||
"Invalid addressing mode for instruction", // ERROR_INVALID_ADDRESSING_MODE,
|
||||
"Internal label organization mishap", // ERROR_LABEL_MISPLACED_INTERNAL,
|
||||
"Bad addressing mode", // ERROR_BAD_ADDRESSING_MODE,
|
||||
"Unexpected character in addressing mode", // ERROR_UNEXPECTED_CHARACTER_IN_ADDRESSING_MODE,
|
||||
"Unexpected label assignment format", // ERROR_UNEXPECTED_LABEL_ASSIGMENT_FORMAT,
|
||||
"Changing value of label that is constant", // ERROR_MODIFYING_CONST_LABEL,
|
||||
"Out of labels in pool", // ERROR_OUT_OF_LABELS_IN_POOL,
|
||||
"Internal label pool release confusion", // ERROR_INTERNAL_LABEL_POOL_ERROR,
|
||||
"Label pool range evaluation failed", // ERROR_POOL_RANGE_EXPRESSION_EVAL,
|
||||
"Label pool was redeclared within its scope", // ERROR_LABEL_POOL_REDECLARATION,
|
||||
"Pool label already defined", // ERROR_POOL_LABEL_ALREADY_DEFINED,
|
||||
"Struct already defined", // ERROR_STRUCT_ALREADY_DEFINED,
|
||||
"Referenced struct not found", // ERROR_REFERENCED_STRUCT_NOT_FOUND,
|
||||
"Declare constant type not recognized (dc.?)", // ERROR_BAD_TYPE_FOR_DECLARE_CONSTANT,
|
||||
"rept count expression could not be evaluated", // ERROR_REPT_COUNT_EXPRESSION,
|
||||
"hex must be followed by an even number of hex numbers", // ERROR_HEX_WITH_ODD_NIBBLE_COUNT,
|
||||
"DS directive failed to evaluate immediately", // ERROR_DS_MUST_EVALUATE_IMMEDIATELY,
|
||||
"File is not a valid x65 object file", // ERROR_NOT_AN_X65_OBJECT_FILE,
|
||||
"Failed to read include file", // ERROR_COULD_NOT_INCLUDE_FILE,
|
||||
"User invoked error", // ERROR_USER,
|
||||
|
||||
"Errors after this point will stop execution",
|
||||
"Errors after this point will stop execution", // ERROR_STOP_PROCESSING_ON_HIGHER, // errors greater than this will stop execution
|
||||
|
||||
"Target address must evaluate immediately for this operation",
|
||||
"Scoping is too deep",
|
||||
"Unbalanced scope closure",
|
||||
"Unexpected macro formatting",
|
||||
"Align must evaluate immediately",
|
||||
"Out of memory for macro expansion",
|
||||
"Problem with macro argument",
|
||||
"Conditional could not be resolved",
|
||||
"#endif encountered outside conditional block",
|
||||
"#else or #elif outside conditional block",
|
||||
"Struct can not be assembled as is",
|
||||
"Enum can not be assembled as is",
|
||||
"Conditional assembly (#if/#ifdef) was not terminated in file or macro",
|
||||
"rept is missing a scope ('{ ... }')",
|
||||
"Link can only be used in a fixed address section",
|
||||
"Link can not be used in dummy sections",
|
||||
"Can not process this line",
|
||||
"Unexpected target offset for reloc or late evaluation",
|
||||
"CPU is not supported",
|
||||
"Can't append sections",
|
||||
"Zero page / Direct page section out of range",
|
||||
"Attempting to assign an address to a non-existent section",
|
||||
"Attempting to assign an address to a fixed address section",
|
||||
"Can not link a zero page section with a non-zp section",
|
||||
"Out of memory while building",
|
||||
"Can not write to file",
|
||||
"Assembly aborted",
|
||||
"Condition too deeply nested",
|
||||
"Branch is out of range", // ERROR_BRANCH_OUT_OF_RANGE,
|
||||
"Target address must evaluate immediately for this operation", // ERROR_TARGET_ADDRESS_MUST_EVALUATE_IMMEDIATELY,
|
||||
"Scoping is too deep", // ERROR_TOO_DEEP_SCOPE,
|
||||
"Unbalanced scope closure", // ERROR_UNBALANCED_SCOPE_CLOSURE,
|
||||
"Unexpected macro formatting", // ERROR_BAD_MACRO_FORMAT,
|
||||
"Align must evaluate immediately", // ERROR_ALIGN_MUST_EVALUATE_IMMEDIATELY,
|
||||
"Out of memory for macro expansion", // ERROR_OUT_OF_MEMORY_FOR_MACRO_EXPANSION,
|
||||
"Problem with macro argument", // ERROR_MACRO_ARGUMENT,
|
||||
"Conditional could not be resolved", // ERROR_CONDITION_COULD_NOT_BE_RESOLVED,
|
||||
"#endif encountered outside conditional block", // ERROR_ENDIF_WITHOUT_CONDITION,
|
||||
"#else or #elif outside conditional block", // ERROR_ELSE_WITHOUT_IF,
|
||||
"Struct can not be assembled as is", // ERROR_STRUCT_CANT_BE_ASSEMBLED,
|
||||
"Enum can not be assembled as is", // ERROR_ENUM_CANT_BE_ASSEMBLED,
|
||||
"Conditional assembly (#if/#ifdef) was not terminated in file or macro", // ERROR_UNTERMINATED_CONDITION,
|
||||
"rept is missing a scope ('{ ... }')", // ERROR_REPT_MISSING_SCOPE,
|
||||
"Link can only be used in a fixed address section", // ERROR_LINKER_MUST_BE_IN_FIXED_ADDRESS_SECTION,
|
||||
"Link can not be used in dummy sections", // ERROR_LINKER_CANT_LINK_TO_DUMMY_SECTION,
|
||||
"Can not process this line", // ERROR_UNABLE_TO_PROCESS,
|
||||
"Unexpected target offset for reloc or late evaluation", // ERROR_SECTION_TARGET_OFFSET_OUT_OF_RANGE,
|
||||
"CPU is not supported", // ERROR_CPU_NOT_SUPPORTED,
|
||||
"Can't append sections", // ERROR_CANT_APPEND_SECTION_TO_TARGET,
|
||||
"Zero page / Direct page section out of range", // ERROR_ZEROPAGE_SECTION_OUT_OF_RANGE,
|
||||
"Attempting to assign an address to a non-existent section", // ERROR_NOT_A_SECTION,
|
||||
"Attempting to assign an address to a fixed address section", // ERROR_CANT_REASSIGN_FIXED_SECTION,
|
||||
"Can not link a zero page section with a non-zp section", // ERROR_CANT_LINK_ZP_AND_NON_ZP,
|
||||
"Out of memory while building", // ERROR_OUT_OF_MEMORY,
|
||||
"Can not write to file", // ERROR_CANT_WRITE_TO_FILE,
|
||||
"Assembly aborted", // ERROR_ABORTED,
|
||||
"Condition too deeply nested", // ERROR_CONDITION_TOO_NESTED,
|
||||
};
|
||||
|
||||
// Assembler directives
|
||||
@ -251,6 +274,7 @@ enum AssemblerDirective {
|
||||
AD_LABPOOL, // POOL: Create a pool of addresses to assign as labels dynamically
|
||||
AD_IF, // #IF: Conditional assembly follows based on expression
|
||||
AD_IFDEF, // #IFDEF: Conditional assembly follows based on label defined or not
|
||||
AD_IFNDEF, // #IFNDEF: Conditional assembly inverted from IFDEF
|
||||
AD_ELSE, // #ELSE: Otherwise assembly
|
||||
AD_ELIF, // #ELIF: Otherwise conditional assembly follows
|
||||
AD_ENDIF, // #ENDIF: End a block of #IF/#IFDEF
|
||||
@ -268,6 +292,8 @@ enum AssemblerDirective {
|
||||
AD_LST, // LST: Controls symbol listing
|
||||
AD_DUMMY, // DUM: Start a dummy section (increment address but don't write anything???)
|
||||
AD_DUMMY_END, // DEND: End a dummy section
|
||||
AD_SCOPE, // SCOPE: Begin ca65 style scope
|
||||
AD_ENDSCOPE, // ENDSCOPR: End ca65 style scope
|
||||
AD_DS, // DS: Define section, zero out # bytes or rewind the address if negative
|
||||
AD_USR, // USR: MERLIN user defined pseudo op, runs some code at a hard coded address on apple II, on PC does nothing.
|
||||
AD_SAV, // SAV: MERLIN version of export but contains full filename, not an appendable name
|
||||
@ -964,6 +990,7 @@ DirectiveName aDirectiveNames[] {
|
||||
{ "POOL", AD_LABPOOL },
|
||||
{ "IF", AD_IF },
|
||||
{ "IFDEF", AD_IFDEF },
|
||||
{ "IFNDEF", AD_IFNDEF },
|
||||
{ "ELSE", AD_ELSE },
|
||||
{ "ELIF", AD_ELIF },
|
||||
{ "ENDIF", AD_ENDIF },
|
||||
@ -980,6 +1007,8 @@ DirectiveName aDirectiveNames[] {
|
||||
{ "I8", AD_XY8 }, // I8: Set 8 bit index register mode
|
||||
{ "DUMMY", AD_DUMMY },
|
||||
{ "DUMMY_END", AD_DUMMY_END },
|
||||
{ "SCOPE", AD_SCOPE }, // SCOPE: Begin ca65 style scope
|
||||
{ "ENDSCOPE", AD_ENDSCOPE },// ENDSCOPR: End ca65 style scope
|
||||
{ "DS", AD_DS }, // Define space
|
||||
{ "ABORT", AD_ABORT },
|
||||
{ "ERR", AD_ABORT }, // DASM version of ABORT
|
||||
@ -1195,7 +1224,6 @@ public:
|
||||
strovl string_value; // string contents if modified, initialized to null string
|
||||
|
||||
StatusCode Append(strref append);
|
||||
StatusCode ParseLine(strref line);
|
||||
|
||||
strref get() { return string_value.valid() ? string_value.get_strref() : string_const; }
|
||||
void clear() {
|
||||
@ -1513,13 +1541,17 @@ public:
|
||||
int scope_depth;
|
||||
int brace_depth; // scope depth defined only by braces, not files
|
||||
|
||||
strref export_base_name; // binary output name if available
|
||||
strref last_label; // most recently defined label for Merlin macro
|
||||
|
||||
// ca65 style scope (for now treat global symbols as local symbols, no outside name lookup)
|
||||
int directive_scope_depth;
|
||||
|
||||
// Eval relative result (only valid if EvalExpression returns STATUS_RELATIVE_SECTION)
|
||||
int lastEvalSection;
|
||||
int lastEvalValue;
|
||||
int8_t lastEvalShift;
|
||||
|
||||
strref export_base_name; // binary output name if available
|
||||
strref last_label; // most recently defined label for Merlin macro
|
||||
int8_t list_flags; // listing flags accumulating for each line
|
||||
bool accumulator_16bit; // 65816 specific software dependent immediate mode
|
||||
bool index_reg_16bit; // -"-
|
||||
@ -1737,6 +1769,7 @@ void Asm::Cleanup() {
|
||||
conditional_depth = 0;
|
||||
conditional_nesting[0] = 0;
|
||||
conditional_consumed[0] = false;
|
||||
directive_scope_depth = 0;
|
||||
error_encountered = false;
|
||||
list_assembly = false;
|
||||
end_macro_directive = false;
|
||||
@ -1865,7 +1898,7 @@ char* Asm::LoadBinary(strref filename, size_t &size) {
|
||||
if (file.get_last()!='/' && file.get_last()!='\\')
|
||||
file.append('/');
|
||||
file.append(filename);
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
file.replace('/', '\\');
|
||||
#endif
|
||||
++i;
|
||||
@ -2792,8 +2825,9 @@ StatusCode Asm::AddMacro(strref macro, strref source_name, strref source_file, s
|
||||
} else { return ERROR_BAD_MACRO_FORMAT; }
|
||||
} else {
|
||||
name = macro.split_range(label_end_char_range);
|
||||
macro.skip_whitespace();
|
||||
while (macro.get_first() == ' ' || macro.get_first() == '\t') { ++macro; }
|
||||
strref left_line = macro.get_line();
|
||||
if (left_line.get_first() == ';' || left_line.has_prefix("//")) { left_line.clear(); }
|
||||
left_line.skip_whitespace();
|
||||
left_line = left_line.before_or_full(';').before_or_full(c_comment);
|
||||
if (left_line && left_line[0]!='(' && left_line[0]!='{') {
|
||||
@ -2837,7 +2871,10 @@ StatusCode Asm::AddMacro(strref macro, strref source_name, strref source_file, s
|
||||
for (;;) {
|
||||
f = macro.find(endm, f+1);
|
||||
if (f<0) { return ERROR_BAD_MACRO_FORMAT; }
|
||||
if (f==0||strref::is_ws(macro[f-1])) { break; }
|
||||
if (f == 0 || strref::is_ws(macro[f - 1]) || macro[f - 1] == '.') {
|
||||
if (f && macro[f - 1] == '.') { --f; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
pMacro->macro = macro.get_substr(0, f);
|
||||
macro += f;
|
||||
@ -4125,7 +4162,7 @@ StatusCode Asm::AddressLabel(strref label)
|
||||
pLabel->constant = constLabel;
|
||||
last_label = label;
|
||||
bool local = label[0]=='.' || label[0]=='@' || label[0]=='!' || label[0]==':' || label.get_last()=='$';
|
||||
LabelAdded(pLabel, local);
|
||||
LabelAdded(pLabel, local || directive_scope_depth>0); // TODO: in named scopes the label can still be referenced outside the scope directive
|
||||
if (local) { MarkLabelLocal(label); }
|
||||
status = CheckLateEval(label);
|
||||
if (!local && label[0]!=']') { // MERLIN: Variable label does not invalidate local labels
|
||||
@ -4214,7 +4251,7 @@ StringSymbol *Asm::AddString(strref string_name, strref string_value)
|
||||
}
|
||||
|
||||
// append a string to another string
|
||||
StatusCode StringSymbol::Append(strref append)
|
||||
StatusCode sStringSymbols::Append(strref append)
|
||||
{
|
||||
if (!append)
|
||||
return STATUS_OK;
|
||||
@ -5215,16 +5252,27 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
|
||||
case AD_IFDEF:
|
||||
if (NewConditional()) { // Start new conditional block
|
||||
CheckConditionalDepth(); // Check if nesting
|
||||
bool conditional_result;
|
||||
error = EvalStatement(line, conditional_result);
|
||||
strref name = line.get_trimmed_ws();
|
||||
if (GetLabel(name) != nullptr || GetString(name) != nullptr)
|
||||
// ifdef doesn't need to evaluate the value, just determine if it exists or not
|
||||
strref label = line.split_range_trim(label_end_char_range);
|
||||
if( GetLabel(label, etx.file_ref) )
|
||||
ConsumeConditional();
|
||||
else
|
||||
SetConditional();
|
||||
}
|
||||
break;
|
||||
|
||||
case AD_IFNDEF:
|
||||
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 = line.split_range_trim(label_end_char_range);
|
||||
if (!GetLabel(label, etx.file_ref))
|
||||
ConsumeConditional();
|
||||
else
|
||||
SetConditional();
|
||||
}
|
||||
break;
|
||||
|
||||
case AD_ELSE:
|
||||
if (ConditionalAsm()) {
|
||||
if (ConditionalConsumed())
|
||||
@ -5327,7 +5375,15 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case AD_SCOPE:
|
||||
directive_scope_depth++;
|
||||
break;
|
||||
|
||||
case AD_ENDSCOPE:
|
||||
directive_scope_depth--;
|
||||
break;
|
||||
|
||||
case AD_DS:
|
||||
return Directive_DS(line);
|
||||
}
|
||||
@ -5893,15 +5949,13 @@ StatusCode Asm::BuildLine(strref line) {
|
||||
error = AssignLabel(label, line);
|
||||
line.clear();
|
||||
list_flags |= ListLine::KEYWORD;
|
||||
}
|
||||
else if (keyword_equ.is_prefix_word(line)) {
|
||||
} else if (keyword_equ.is_prefix_word(line)) {
|
||||
line += keyword_equ.get_len();
|
||||
line.skip_whitespace();
|
||||
error = AssignLabel(label, line);
|
||||
line.clear();
|
||||
list_flags |= ListLine::KEYWORD;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
uint32_t nameHash = label.fnv1a();
|
||||
uint32_t macro = FindLabelIndex(nameHash, macros.getKeys(), macros.count());
|
||||
bool gotConstruct = false;
|
||||
@ -7187,15 +7241,7 @@ StatusCode Asm::WriteA2GS_OMF(strref filename, bool full_collapse) {
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const strref listing("lst");
|
||||
const strref tass_listing( "tsl" );
|
||||
const strref tass_labels( "tl" );
|
||||
const strref allinstr("opcodes");
|
||||
const strref endmacro("endm");
|
||||
const strref cpu("cpu");
|
||||
const strref acc("acc");
|
||||
const strref xy("xy");
|
||||
const strref org("org");
|
||||
|
||||
int return_value = 0;
|
||||
bool load_header = true;
|
||||
bool size_header = false;
|
||||
@ -7210,15 +7256,15 @@ int main(int argc, char **argv) {
|
||||
|
||||
const char *source_filename = nullptr, *obj_out_file = nullptr;
|
||||
const char *binary_out_name = nullptr;
|
||||
const char *sym_file = nullptr, *vs_file = nullptr, *tass_labels_file = nullptr;
|
||||
const char *sym_file = nullptr, *vs_file = nullptr, *cmdarg_tass_labels_file = nullptr;
|
||||
strref list_file, allinstr_file;
|
||||
strref tass_list_file;
|
||||
for (int a = 1; a<argc; a++) {
|
||||
if (argv[a][0]=='-') {
|
||||
strref arg(argv[a]+1);
|
||||
if (arg.get_first()=='i') { assembler.AddIncludeFolder(arg+1); }
|
||||
else if (arg.same_str("kickasm") ) { assembler.syntax = SYNTAX_KICKASM; }
|
||||
else if (arg.same_str("merlin")) { assembler.syntax = SYNTAX_MERLIN; }
|
||||
else if (arg.same_str(cmdarg_kickasm) ) { assembler.syntax = SYNTAX_KICKASM; }
|
||||
else if (arg.same_str(cmdarg_merlin)) { assembler.syntax = SYNTAX_MERLIN; }
|
||||
else if (arg.get_first()=='D'||arg.get_first()=='d') {
|
||||
++arg;
|
||||
if (arg.find('=')>0) {
|
||||
@ -7226,51 +7272,51 @@ int main(int argc, char **argv) {
|
||||
} else {
|
||||
assembler.AssignLabel(arg, "1");
|
||||
}
|
||||
} else if (arg.same_str("c64")) {
|
||||
} else if (arg.same_str(cmdarg_c64)) {
|
||||
load_header = true;
|
||||
size_header = false;
|
||||
} else if (arg.same_str("a2b")) {
|
||||
} else if (arg.same_str(cmdarg_a2b)) {
|
||||
assembler.default_org = 0x0803;
|
||||
load_header = true;
|
||||
size_header = true;
|
||||
} else if (arg.same_str("bin")) {
|
||||
} else if (arg.same_str(cmdarg_bin)) {
|
||||
load_header = false;
|
||||
size_header = false;
|
||||
} else if (arg.same_str("a2p")) {
|
||||
} else if (arg.same_str(cmdarg_a2p)) {
|
||||
assembler.default_org = 0x2000;
|
||||
load_header = false;
|
||||
size_header = false;
|
||||
} else if (arg.same_str("a2o")) {
|
||||
} else if (arg.same_str(cmdarg_a2o)) {
|
||||
gs_os_reloc = true;
|
||||
} else if (arg.same_str("mrg")) {
|
||||
} else if (arg.same_str(cmdarg_mrg)) {
|
||||
force_merge_sections = true;
|
||||
} else if (arg.same_str("sect")) {
|
||||
} else if (arg.same_str(cmdarg_sect)) {
|
||||
info = true;
|
||||
} else if (arg.same_str(endmacro)) {
|
||||
} else if (arg.same_str(cmdarg_endmacro)) {
|
||||
assembler.end_macro_directive = true;
|
||||
} else if (arg.has_prefix(listing)&&(arg.get_len()==listing.get_len()||arg[listing.get_len()]=='=')) {
|
||||
} else if (arg.has_prefix(cmdarg_listing)&&(arg.get_len()==cmdarg_listing.get_len()||arg[cmdarg_listing.get_len()]=='=')) {
|
||||
assembler.list_assembly = true;
|
||||
list_output = true;
|
||||
list_file = arg.after( '=' );
|
||||
} else if (arg.has_prefix(tass_listing)&&(arg.get_len()==listing.get_len()||arg[listing.get_len()]=='=')) {
|
||||
} else if (arg.has_prefix(cmdarg_tass_listing)&&(arg.get_len()==cmdarg_listing.get_len()||arg[cmdarg_listing.get_len()]=='=')) {
|
||||
assembler.list_assembly = true;
|
||||
tass_list_output = true;
|
||||
tass_list_file = arg.after( '=' );
|
||||
} else if (arg.has_prefix(allinstr)&&(arg.get_len()==allinstr.get_len()||arg[allinstr.get_len()]=='=')) {
|
||||
} else if (arg.has_prefix(cmdarg_allinstr)&&(arg.get_len()==cmdarg_allinstr.get_len()||arg[cmdarg_allinstr.get_len()]=='=')) {
|
||||
gen_allinstr = true;
|
||||
allinstr_file = arg.after('=');
|
||||
} else if (arg.has_prefix(org)) {
|
||||
} else if (arg.has_prefix(cmdarg_org)) {
|
||||
arg = arg.after('=');
|
||||
if (arg && arg.get_first()=='$' && arg.get_len()>1) {
|
||||
assembler.default_org = (int)(arg+1).ahextoui();
|
||||
} else if (arg.is_number()) { assembler.default_org = (int)arg.atoi(); }
|
||||
// force the current section to be org'd
|
||||
assembler.AssignAddressToSection(assembler.SectionId(), assembler.default_org);
|
||||
} else if (arg.has_prefix(acc)&&arg[acc.get_len()]=='=') {
|
||||
} else if (arg.has_prefix(cmdarg_acc)&&arg[cmdarg_acc.get_len()]=='=') {
|
||||
assembler.accumulator_16bit = arg.after('=').atoi()==16;
|
||||
} else if (arg.has_prefix(xy)&&arg[xy.get_len()]=='=') {
|
||||
} else if (arg.has_prefix(cmdarg_xy)&&arg[cmdarg_xy.get_len()]=='=') {
|
||||
assembler.index_reg_16bit = arg.after('=').atoi()==16;
|
||||
} else if (arg.has_prefix(cpu)&&(arg.get_len()==cpu.get_len()||arg[cpu.get_len()]=='=')) {
|
||||
} else if (arg.has_prefix(cmdarg_cpu)&&(arg.get_len()==cmdarg_cpu.get_len()||arg[cmdarg_cpu.get_len()]=='=')) {
|
||||
arg.split_token_trim('=');
|
||||
bool found = false;
|
||||
for (int c = 0; c<nCPUs; c++) {
|
||||
@ -7287,14 +7333,14 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
if (!arg) { return 0; }
|
||||
} else if (arg.same_str("sym")&&(a+1)<argc) {
|
||||
} else if (arg.same_str(cmdarg_sym)&&(a+1)<argc) {
|
||||
sym_file = argv[++a];
|
||||
} else if (arg.same_str("obj")&&(a+1)<argc) {
|
||||
} else if (arg.same_str(cmdarg_obj)&&(a+1)<argc) {
|
||||
obj_out_file = argv[++a];
|
||||
} else if (arg.same_str("vice")&&(a+1)<argc) {
|
||||
} else if (arg.same_str(cmdarg_vice)&&(a+1)<argc) {
|
||||
vs_file = argv[++a];
|
||||
} else if (arg.same_str(tass_labels)&&(a+1)<argc) {
|
||||
tass_labels_file = argv[++a];
|
||||
} else if (arg.same_str(cmdarg_tass_labels)&&(a+1)<argc) {
|
||||
cmdarg_tass_labels_file = argv[++a];
|
||||
} else { printf("Unexpected option " STRREF_FMT "\n", STRREF_ARG(arg)); }
|
||||
} else if (!source_filename) { source_filename = argv[a]; }
|
||||
else if (!binary_out_name) { binary_out_name = argv[a]; }
|
||||
@ -7446,8 +7492,8 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
// export tass labels
|
||||
if( tass_labels_file && !srcname.same_str( tass_labels_file ) && !assembler.map.empty() ) {
|
||||
if( FILE *f = fopen( tass_labels_file, "w" ) ) {
|
||||
if( cmdarg_tass_labels_file && !srcname.same_str( cmdarg_tass_labels_file ) && !assembler.map.empty() ) {
|
||||
if( FILE *f = fopen( cmdarg_tass_labels_file, "w" ) ) {
|
||||
for( MapSymbolArray::iterator i = assembler.map.begin(); i != assembler.map.end(); ++i ) {
|
||||
uint32_t value = ( uint32_t )i->value;
|
||||
if( size_t( i->section ) < assembler.allSections.size() ) { value += assembler.allSections[ i->section ].start_address; }
|
||||
|
Loading…
Reference in New Issue
Block a user