Skip to content

Commit 702327d

Browse files
committed
Implement DITTO
1 parent a904e88 commit 702327d

File tree

5 files changed

+146
-20
lines changed

5 files changed

+146
-20
lines changed

ast.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,9 @@ static const char *astnames[] = {
888888
"static_assert",
889889

890890
"taskinit",
891+
"ditto_start",
892+
"ditto_end",
893+
"ditto_count",
891894
};
892895

893896
//

ast.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,10 @@ enum astkind {
250250
AST_STATIC_ASSERT = 180,
251251

252252
AST_TASKINIT = 181,
253+
AST_DITTO_START = 182,
254+
AST_DITTO_END = 183,
255+
AST_DITTO_COUNT = 184,
256+
253257
};
254258

255259
/* forward reference */

frontends/lexer.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
#define VT '\013'
2525

26-
#define MAX_PNUT_VERSION 48 /* maximum PNut version we understand */
26+
#define MAX_PNUT_VERSION 50 /* maximum PNut version we understand */
2727

2828
int allow_type_names = 1;
2929

@@ -720,7 +720,7 @@ parseSpinIdentifier(LexStream *L, AST **ast_ptr, const char *prefix)
720720
char *idstr;
721721
int gatherComments = 1;
722722
bool forceLower = 0; // !gl_caseSensitive;
723-
723+
724724
flexbuf_init(&fb, INCSTR);
725725
if (prefix) {
726726
flexbuf_addmem(&fb, prefix, strlen(prefix));
@@ -891,13 +891,17 @@ parseSpinIdentifier(LexStream *L, AST **ast_ptr, const char *prefix)
891891
break;
892892
case SP_END:
893893
if ( (!InDatBlock(L)) || L->colCounter - L->firstNonBlank > 4) {
894-
goto is_identifier;
895-
}
896-
if (L->if_nest > 0) {
897-
--L->if_nest;
898-
c = SP_ASM_ENDIF;
894+
// in older Spin2 we only recognize END as the first thing
895+
// on a line; after v44 or so just accept it always
896+
if (L->language_version < 44)
897+
goto is_identifier;
899898
} else {
900-
L->block_type = L->save_block;
899+
if (L->if_nest > 0) {
900+
--L->if_nest;
901+
c = SP_ASM_ENDIF;
902+
} else {
903+
L->block_type = L->save_block;
904+
}
901905
}
902906
break;
903907
case SP_ENDASM:
@@ -2043,6 +2047,12 @@ getSpinToken(LexStream *L, AST **ast_ptr)
20432047
if (c == SP_FLOATNUM)
20442048
ast->kind = AST_FLOAT;
20452049
} else if (c == '$') {
2050+
c = lexgetc(L);
2051+
if (c == '$') {
2052+
return SP_DOUBLE_DOLLAR;
2053+
} else {
2054+
lexungetc(L, c);
2055+
}
20462056
ast = NewAST(AST_INTEGER, NULL, NULL);
20472057
c = parseNumber(L, 16, &ast->d.ival);
20482058
} else if (c == '%') {
@@ -2244,7 +2254,8 @@ struct reservedword {
22442254

22452255
{ "dat", SP_DAT },
22462256
{ "%debug", SP_DEBUG },
2247-
2257+
{ "%ditto", SP_DITTO },
2258+
22482259
{ "%else", SP_ASM_ELSE },
22492260
{ "else", SP_ELSE },
22502261
{ "%elseif", SP_ASM_ELSEIF },
@@ -2269,6 +2280,7 @@ struct reservedword {
22692280
{ "lookup", SP_LOOKUP },
22702281
{ "lookupz", SP_LOOKUPZ },
22712282

2283+
{ "%namesp", SP_NAMESP },
22722284
{ "next", SP_NEXT },
22732285
{ "not", SP_NOT },
22742286

@@ -2455,7 +2467,7 @@ struct reservedword_soft {
24552467
{ "field", SP_FIELD, 0, 0 },
24562468
{ "lstring", SP_LSTRING, 42, 0 },
24572469

2458-
/* These one are weird: Chip put them
2470+
/* These ones are weird: Chip put them
24592471
in Spin v42 then took them out again,
24602472
so they're only valid in v42
24612473
*/
@@ -2479,6 +2491,10 @@ struct reservedword_soft {
24792491
{ "newtask", SP_NEWTASK, 47, 0 },
24802492
{ "thistask", SP_THISTASK, 47, 0 },
24812493
{ "taskspin", SP_TASKINIT, 47, 0 },
2494+
2495+
/* v50 keywords */
2496+
{ "ditto", SP_DITTO, 50, 0 },
2497+
24822498
};
24832499

24842500
struct reservedword basic_keywords[] = {

frontends/spin/spin.y

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
%pure-parser
8-
%expect 42
8+
%expect 43
99

1010
%{
1111
#include <stdio.h>
@@ -291,15 +291,7 @@ SpinDeclareStruct(AST *ident, AST *defs)
291291
%token SP_PUB "PUB"
292292
%token SP_PRI "PRI"
293293
%token SP_OBJ "OBJ"
294-
%token SP_INTERFACE "%INTERFACE"
295-
%token SP_ASM "ASM"
296-
%token SP_ASM_CONST "ASM_CONST"
297-
%token SP_ENDASM "ENDASM"
298294
%token SP_END "END"
299-
%token SP_ASM_IF "%IF"
300-
%token SP_ASM_ELSEIF "%ELSEIF"
301-
%token SP_ASM_ELSE "%ELSE"
302-
%token SP_ASM_ENDIF "%END"
303295
%token SP_INLINECCODE "CCODE"
304296
%token SP_BYTE "BYTE"
305297
%token SP_WORD "WORD"
@@ -374,7 +366,18 @@ SpinDeclareStruct(AST *ident, AST *defs)
374366
%token SP_STRINGPTR "STRING"
375367
%token SP_FILE "FILE"
376368

369+
/* flexspin extensions */
377370
%token SP_ANNOTATION
371+
%token SP_ASM "ASM"
372+
%token SP_ASM_CONST "ASM_CONST"
373+
%token SP_ENDASM "ENDASM"
374+
/* the lexer can generate ASM_IF family from regular IF */
375+
%token SP_ASM_IF "%IF"
376+
%token SP_ASM_ELSEIF "%ELSEIF"
377+
%token SP_ASM_ELSE "%ELSE"
378+
%token SP_ASM_ENDIF "%END"
379+
%token SP_INTERFACE "%INTERFACE"
380+
%token SP_NAMESP "%NAMESP"
378381
%token SP_VARARGS "%VARARGS"
379382

380383
/* Spin2 additions */
@@ -409,6 +412,9 @@ SpinDeclareStruct(AST *ident, AST *defs)
409412
%token SP_NEWTASK "NEWTASK"
410413
%token SP_THISTASK "THISTASK"
411414

415+
/* v50 additions */
416+
%token SP_DITTO "DITTO"
417+
412418
/* operators */
413419
%token SP_ASSIGN ":="
414420
%token SP_XOR "XOR (^^)"
@@ -495,6 +501,8 @@ SpinDeclareStruct(AST *ident, AST *defs)
495501
%token SP_DAT_LBRACK "[ in DAT"
496502
%token SP_DAT_RBRACK "] in DAT"
497503

504+
%token SP_DOUBLE_DOLLAR "$$"
505+
498506
/* operator precedence */
499507
%right SP_ASSIGN SP_SWAP_OP
500508
%left '\\'
@@ -1349,6 +1357,18 @@ basedatline:
13491357
{
13501358
SYNTAX_ERROR("ASMCLK instruction is not supported");
13511359
}
1360+
| SP_DITTO SP_END
1361+
{
1362+
AST *ast = NewAST(AST_DITTO_END, NULL, NULL);
1363+
ast = NewAST(AST_COMMENTEDNODE, ast, $1);
1364+
$$ = ast;
1365+
}
1366+
| SP_DITTO expr
1367+
{
1368+
AST *ast = NewAST(AST_DITTO_START, $2, NULL);
1369+
ast = NewAST(AST_COMMENTEDNODE, ast, $1);
1370+
$$ = ast;
1371+
}
13521372
;
13531373

13541374
objblock:
@@ -1956,6 +1976,8 @@ expr:
19561976
}
19571977
| SP_HERE
19581978
{ $$ = NewAST(AST_HERE, NULL, NULL); }
1979+
| SP_DOUBLE_DOLLAR
1980+
{ $$ = NewAST(AST_DITTO_COUNT, NULL, NULL); }
19591981
| lhs SP_INCREMENT
19601982
{ $$ = AstOperator(K_INCREMENT, $1, NULL); }
19611983
| lhs SP_DECREMENT

pasm.c

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,85 @@ IsJmpRetInstruction(AST *ast)
657657
return false;
658658
}
659659

660+
/* duplicate a ditto chain, replacing $$ with the ditto count */
661+
static AST *
662+
DupDittoChain(AST *chain, unsigned count) {
663+
static AST *ditto_count = NULL;
664+
AST *first;
665+
if (!ditto_count) {
666+
ditto_count = NewAST(AST_DITTO_COUNT, NULL, NULL);
667+
}
668+
first = DupASTWithReplace(chain, ditto_count, AstInteger(count));
669+
return first;
670+
}
671+
672+
/* first is the original holder of the DITTO node */
673+
/* last is the original holder of the DITTO END node */
674+
675+
void
676+
DupDitto(AST *first, AST *last, AST *count) {
677+
unsigned max_count = EvalPasmExpr(count);
678+
unsigned cur_count = 1;
679+
680+
AST *cur_copy;
681+
AST *chain_first = first->right;
682+
AST *chain_last = last->right;
683+
684+
/* snip the chain out */
685+
first->right = last->right;
686+
first->left = NULL;
687+
last->right = NULL;
688+
689+
while (cur_count <= max_count) {
690+
cur_copy = DupDittoChain(chain_first, cur_count);
691+
first->right = cur_copy;
692+
while (first->right) first = first->right;
693+
first->right = chain_last; // last->right;
694+
first->left = NULL;
695+
cur_count++;
696+
}
697+
698+
}
699+
700+
void
701+
ExpandDittos(AST *instrlist)
702+
{
703+
AST *top, *ast;
704+
AST *ditto_start = NULL;
705+
AST *ditto_count = NULL;
706+
AST *oldtop;
707+
top = instrlist;
708+
while (top) {
709+
ast = top->left;
710+
oldtop = top;
711+
top = top->right;
712+
while (ast && ast->kind == AST_COMMENTEDNODE) {
713+
ast = ast->left;
714+
}
715+
if (!ast) continue;
716+
if (ast->kind == AST_DITTO_START) {
717+
if (ditto_start) {
718+
ERROR(ast, "DITTO cannot be nested");
719+
}
720+
if (ast->right) {
721+
ERROR(ast, "Internal error parsing DITTO");
722+
}
723+
ditto_start = oldtop;
724+
ditto_count = ast->left;
725+
} else if (ast->kind == AST_DITTO_END) {
726+
if (!ditto_start) {
727+
ERROR(ast, "DITTO END without DITTO");
728+
continue;
729+
}
730+
if (ast->right) {
731+
ERROR(ast, "Internal error parsing DITTO END");
732+
}
733+
DupDitto(ditto_start, oldtop, ditto_count);
734+
ditto_start = ditto_count = NULL;
735+
}
736+
}
737+
}
738+
660739
void
661740
AssignAddresses(PASMAddresses *addr, SymbolTable *symtab, AST *instrlist, int startFlags)
662741
{
@@ -683,7 +762,9 @@ AssignAddresses(PASMAddresses *addr, SymbolTable *symtab, AST *instrlist, int st
683762
expect_undefined_labels = 1;
684763
unsigned asm_nest;
685764
AsmState state[MAX_ASM_NEST] = { 0 };
686-
765+
766+
ExpandDittos(instrlist);
767+
687768
again:
688769
labels_changed = 0;
689770

0 commit comments

Comments
 (0)