1
0
mirror of https://github.com/ksherlock/x65.git synced 2024-06-11 01:29:26 +00:00

Added REPT directive

This commit is contained in:
Carl-Henrik Skårstedt 2015-10-04 16:06:45 -07:00
parent 9af85f3a8a
commit 00b149a23d
2 changed files with 102 additions and 22 deletions

View File

@ -103,8 +103,9 @@ Directives are assembler commands that control the code generation but that does
* [**LABEL**](#label) Decorative directive to assign an expression to a label
* [**INCSYM**](#incsym) Include a symbol file with an optional set of wanted symbols.
* [**POOL**](#pool) Add a label pool for temporary address labels
* [**#IF/#ELSE/#IFDEF/#ELIF/#ENDIF**](#conditional) Conditional assembly
* [**#IF / #ELSE / #IFDEF / #ELIF / #ENDIF**](#conditional) Conditional assembly
* [**STRUCT**](#struct) Hierarchical data structures (dot separated sub structures)
* [**REPT**](#rept) Repeat a scoped block of code a number of times.
<a name="org">**ORG**
@ -260,7 +261,7 @@ Function_Name: {
rts
```
<a name="conditional">**#IF/#ELSE/#IFDEF/#ELIF/#ENDIF**
<a name="conditional">**#IF / #ELSE / #IFDEF / #ELIF / #ENDIF**
Conditional code parsing is very similar to C directive conditional compilation.
@ -317,6 +318,40 @@ EVAL(28): "Mixed.things.thing_two.pointer" = $6
EVAL(29): "Mixed.things.thing_one.count" = $2
```
<a name="rept">**REPT**
Repeat a scoped block of code a number of times. The syntax is rept \<count\> { \<code\> }.
Example:
```
columns = 40
rows = 25
screen_col = $400
height_buf = $1000
rept columns {
screen_addr = screen_col
ldx height_buf
dest = screen_addr
remainder = 3
rept (rows+remainder)/4 {
stx dest
dest = dest + 4*40
}
rept 3 {
inx
remainder = remainder-1
screen_addr = screen_addr + 40
dest = screen_addr
rept (rows+remainder)/4 {
stx dest
dest = dest + 4*40
}
}
screen_col = screen_col+1
height_buf = height_buf+1
}
```
## <a name="expressions">Expression syntax
@ -330,6 +365,13 @@ Expressions contain values, such as labels or raw numbers and operators includin
* $: Preceeds hexadecimal value
* %: If immediately followed by '0' or '1' this is a binary value and not scope closure address
Example:
```
lda #(((>SCREEN_MATRIX)&$3c)*4)+8
sta $d018
```
## Macros
A macro can be defined by the using the directive macro and includes the line within the following scope:
@ -405,9 +447,10 @@ Currently the assembler is in the first public revision and while features are t
**TODO**
* Macro parameters should replace only whole words instead of any substring
* Add 'import' directive as a catch-all include/incbin/etc. alternative
* rept / irp macro helpers (repeat, indefinite repeat)
* irp (indefinite repeat)
**FIXED**
* [REPT](#rept)
* fixed a flaw in expressions that ignored the next operator after raw hex values if no whitespace
* expressions now handles high byte/low byte (\>, \<) as RPN tokens and not special cased.
* structs
@ -420,9 +463,10 @@ Currently the assembler is in the first public revision and while features are t
* TEXT directive converts ascii to petscii (respect uppercase or lowercase petscii) (simplistic)
Revisions:
* 2015-10-04 Added STRUCT directive, sorted functions by grouping a bit more, bug fixes
* 2015-10-04 Added [REPT](#rept) directive
* 2015-10-04 Added [STRUCT](#struct) directive, sorted functions by grouping a bit more, bug fixes
* 2015-10-02 Cleanup hid an error (#else without #if), exit with nonzero if error was encountered
* 2015-10-02 General cleanup, wrapping conditional assembly in functions
* 2015-10-01 Added Label Pools and conditional assembly
* 2015-10-02 General cleanup, wrapping [conditional assembly](#conditional) in functions
* 2015-10-01 Added [Label Pools](#pool) and conditional assembly
* 2015-09-29 Moved Asm6502 out of Struse Samples.
* 2015-09-28 First commit

View File

@ -84,6 +84,7 @@ enum StatusCode {
ERROR_STRUCT_ALREADY_DEFINED,
ERROR_REFERENCED_STRUCT_NOT_FOUND,
ERROR_BAD_TYPE_FOR_DECLARE_CONSTANT,
ERROR_REPT_COUNT_EXPRESSION,
ERROR_STOP_PROCESSING_ON_HIGHER, // errors greater than this will stop execution
@ -98,6 +99,7 @@ enum StatusCode {
ERROR_ELSE_WITHOUT_IF,
ERROR_STRUCT_CANT_BE_ASSEMBLED,
ERROR_UNTERMINATED_CONDITION,
ERROR_REPT_MISSING_SCOPE,
STATUSCODE_COUNT
};
@ -129,9 +131,10 @@ const char *aStatusStrings[STATUSCODE_COUNT] = {
"Struct already defined",
"Referenced struct not found",
"Declare constant type not recognized (dc.?)",
"rept count expression could not be evaluated",
"Errors after this point will stop execution",
"Target address must evaluate immediately for this operation",
"Scoping is too deep",
"Unbalanced scope closure",
@ -143,6 +146,7 @@ const char *aStatusStrings[STATUSCODE_COUNT] = {
"#else or #elif outside conditional block",
"Struct can not be assembled as is",
"Conditional assembly (#if/#ifdef) was not terminated in file or macro",
"rept is missing a scope ('{ ... }')",
};
// Assembler directives
@ -168,6 +172,7 @@ enum AssemblerDirective {
AD_ELIF, // #ELIF: Otherwise conditional assembly follows
AD_ENDIF, // #ENDIF: End a block of #IF/#IFDEF
AD_STRUCT, // STRUCT: Declare a set of labels offset from a base address
AD_REPT, // REPT: Repeat the assembly of the bracketed code a number of times
};
// Operators are either instructions or directives
@ -465,15 +470,6 @@ typedef struct {
strref source_file; // entire source file (req. for line #)
} Macro;
// Source context is current file (include file, etc.) or current macro.
typedef struct {
strref source_name; // source file name (error output)
strref source_file; // entire source file (req. for line #)
strref code_segment; // the segment of the file for this context
strref read_source; // current position/length in source file
strref next_source; // next position/length in source file
} SourceContext;
// All local labels are removed when a global label is defined but some when a scope ends
typedef struct {
strref label;
@ -508,6 +504,18 @@ typedef struct {
unsigned short size;
} LabelStruct;
// Source context is current file (include file, etc.) or current macro.
typedef struct {
strref source_name; // source file name (error output)
strref source_file; // entire source file (req. for line #)
strref code_segment; // the segment of the file for this context
strref read_source; // current position/length in source file
strref next_source; // next position/length in source file
int repeat; // how many times to repeat this code segment
void restart() { read_source = code_segment; }
bool complete() { repeat--; return repeat <= 0; }
} SourceContext;
// Context stack is a stack of currently processing text
class ContextStack {
private:
@ -516,7 +524,7 @@ private:
public:
ContextStack() : currContext(nullptr) { stack.reserve(32); }
SourceContext& curr() { return *currContext; }
void push(strref src_name, strref src_file, strref code_seg) {
void push(strref src_name, strref src_file, strref code_seg, int rept=1) {
if (currContext)
currContext->read_source = currContext->next_source;
SourceContext context;
@ -525,6 +533,7 @@ public:
context.code_segment = code_seg;
context.read_source = code_seg;
context.next_source = code_seg;
context.repeat = rept;
stack.push_back(context);
currContext = &stack[stack.size()-1];
}
@ -1724,6 +1733,7 @@ DirectiveName aDirectiveNames[] {
{ "#ELIF", AD_ELIF },
{ "#ENDIF", AD_ENDIF },
{ "STRUCT", AD_STRUCT },
{ "REPT", AD_REPT },
};
static const int nDirectiveNames = sizeof(aDirectiveNames) / sizeof(aDirectiveNames[0]);
@ -2021,13 +2031,36 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
error = ERROR_STRUCT_CANT_BE_ASSEMBLED;
break;
}
case AD_REPT: {
SourceContext &ctx = contextStack.curr();
strref read_source = ctx.read_source;
if (read_source.is_substr(line.get())) {
read_source.skip(strl_t(line.get() - read_source.get()));
int block = read_source.find('{');
if (block<0) {
error = ERROR_REPT_MISSING_SCOPE;
break;
}
strref expression = read_source.get_substr(0, block);
read_source += block;
read_source.skip_whitespace();
expression.trim_whitespace();
int count;
if (STATUS_OK != EvalExpression(expression, address,
scope_address[scope_depth], -1, count)) {
error = ERROR_REPT_COUNT_EXPRESSION;
break;
}
strref recur = read_source.scoped_block_skip();
ctx.next_source = read_source;
contextStack.push(ctx.source_name, ctx.source_file, recur, count);
}
break;
}
}
return error;
}
int sortHashLookup(const void *A, const void *B) {
const OP_ID *_A = (const OP_ID*)A;
const OP_ID *_B = (const OP_ID*)B;
@ -2472,7 +2505,10 @@ void Asm::Assemble(strref source, strref filename)
scope_address[scope_depth] = address;
while (contextStack.has_work()) {
error = BuildSegment(pInstr, numInstructions);
contextStack.pop();
if (contextStack.curr().complete())
contextStack.pop();
else
contextStack.curr().restart();
}
if (error == STATUS_OK) {
error = CheckLateEval();