git @ Cat's Eye Technologies SixtyPical / 2e2e806
Forbid nested `with interrupts` blocks, and more refactoring. Chris Pressey 2 years ago
19 changed file(s) with 469 addition(s) and 177 deletion(s). Raw diff Collapse all Expand all
1111 * Local locations need no longer be static. If they are not
1212 static, they are considered uninitialized until assigned,
1313 and they can be declared with an explicit fixed address.
14 * Along with `goto`, `call` and `with interrupts off` are
15 now forbidden inside a `with interrupts off` block.
16 * More tests to assure that using `call` inside a `point into`
17 block or inside a `for` block does not cause trouble,
18 particularly when the routine being called also uses the
19 variable named in that block.
1420 * Fixed a bug where two local statics could be declared with
1521 the same name.
16 * Split context off from analyzer and put it in its own module.
17 * Split the SixtyPical Analysis tests across three files.
22 * Split analysis context support off from analyzer, and
23 symbol table support from parse, and it their own modules.
24 * Split the SixtyPical Analysis tests across three files,
25 and placed test appliances for `sixtypical` in own file.
1826
1927 0.19
2028 ----
66
77 -----------------------------------------------------------------------------
88
9 Copyright (c)2014-2018 Chris Pressey, Cat's Eye Technologies.
9 Copyright (c)2014-2019 Chris Pressey, Cat's Eye Technologies.
1010
1111 The authors intend this Report to belong to the entire SixtyPical
1212 community, and so we grant permission to copy and distribute it for
2323
2424 -----------------------------------------------------------------------------
2525
26 Copyright (c)2014-2018, Chris Pressey, Cat's Eye Technologies.
26 Copyright (c)2014-2019, Chris Pressey, Cat's Eye Technologies.
2727 All rights reserved.
2828
2929 Redistribution and use in source and binary forms, with or without
00 SixtyPical
11 ==========
22
3 _Version 0.19. Work-in-progress, everything is subject to change._
3 _Version 0.20. Work-in-progress, everything is subject to change._
44
55 **SixtyPical** is a [low-level](#low-level) programming language
66 supporting a sophisticated [static analysis](#static-analysis).
108108
109109 * [SixtyPical specification](doc/SixtyPical.md)
110110 * [Literate test suite for SixtyPical syntax](tests/SixtyPical%20Syntax.md)
111 * [Literate test suite for SixtyPical analysis](tests/SixtyPical%20Analysis.md)
111 * [Literate test suite for SixtyPical analysis (operations)](tests/SixtyPical%20Analysis.md)
112 * [Literate test suite for SixtyPical analysis (storage)](tests/SixtyPical%20Storage.md)
113 * [Literate test suite for SixtyPical analysis (control flow)](tests/SixtyPical%20Control%20Flow.md)
112114 * [Literate test suite for SixtyPical compilation](tests/SixtyPical%20Compilation.md)
113115 * [Literate test suite for SixtyPical fallthru optimization](tests/SixtyPical%20Fallthru.md)
114116
00 TODO for SixtyPical
11 ===================
2
3 Language
4 --------
25
36 ### Save values to other-than-the-stack
47
811 ...
912 }
1013
11 Which uses some other storage location instead of the stack. A local static
12 would be a good candidate for such.
14 Which uses some other storage location instead of the stack. A local non-static
15 would be a good candidate for such. At any rate, the location must not
16 be writeable by anything that is called from within the block. So, probably
17 just restrict this to local non-statics.
1318
14 ### Analyze `call` within blocks?
19 ### Copy byte to/from table
1520
16 What happens if you call another routine from inside a `with interrupts off` block?
21 Do we want a `copy bytevar, table + x` instruction? We don't currently have one.
22 You have to `ld a`, `st a`. I think maybe we should have one.
1723
18 What happens if you call another routine from inside a `save` block?
24 ### Character literals
1925
20 What happens if you call another routine from inside a `point into` block?
26 For goodness sake, let the programmer say `'A'` instead of `65`.
2127
22 What happens if you call another routine from inside a `for` block?
28 ### Character set mapping
2329
24 Remember that any of these may have a `goto` ... and they may have a second
25 instance of the same block (e.g. `with interrupts off` nested within
26 `with interrupts off` shouldn't be allowed to turn them back on after the
27 inner block has finished -- even if there is no `call`.)
30 Not all computers think `'A'` should be `65`. Allow the character set to be
31 mapped. Probably copy what Ophis does.
2832
29 These holes need to be plugged.
33 ### "Include" directives
34
35 Search a searchlist of include paths. And use them to make libraries of routines.
36
37 One such library routine might be an `interrupt routine` type for various architectures.
38 Since "the supervisor" has stored values on the stack, we should be able to trash them
39 with impunity, in such a routine.
40
41 ### Pointers into non-byte tables
42
43 Right now you cannot get a pointer into a non-byte (for instance, word or vector) table.
44
45 Word and vector tables are stored as two byte tables in memory. This is useful for
46 indexed access, but makes pointer access more difficult.
47
48 Laying them out for pointer access would make indexed access more difficult.
49
50 ### Saving non-byte values
51
52 Right now you cannot save a word value.
53
54 There doesn't seem to be a hugely pressing reason why not.
55
56 Analysis
57 --------
58
59 ### Forbid recursion
60
61 What happens if a routine calls itself, directly or indirectly? Many
62 constraints might be violated in this case. We should probably disallow
63 recursion by default. (Which means assembling the callgraph in all cases.)
64
65 ### Analyze memory usage
66
67 If you define two variables that occupy the same address, an analysis error ought
68 to be raised. (But there should also be a way to annotate this as intentional.
69 Intentionally making two tables overlap could be valuable. However, the analysis
70 will probably completely miss this fact.)
71
72 Optimization
73 ------------
74
75 ### Space optimization of local non-statics
76
77 If there are two routines A and B, and A never calls B (even indirectly), and
78 B never calls A (even indirectly), then their non-static locals can
79 be allocated at the same space.
80
81 This is not just an impressive trick -- in the presence of local pointers, which
82 use up a word in zero-page, which we consider a precious resource, it allow those
83 zero-page locations to be re-used.
84
85 ### Tail-call optimization
86
87 If a block ends in a `call` can that be converted to end in a `goto`? Why not? I think it can,
88 if the block is in tail position. The constraints should iron out the same both ways.
89
90 As long as the routine has consistent type context every place it exits, that should be fine.
91
92 ### Branch optimization in `if`
93
94 Currently the `if` generator is not smart enough to avoid generating silly
95 jump instructions. (See the Fallthru tests.) Improve it.
96
97 ### Dead code removal
98
99 Once we have a call graph we can omit routines that we're sure aren't called.
100
101 This would let us use include-files and standard-libraries nicely: any
102 routines they define, but that you don't use, don't get included.
103
104 Analyzing the set of possible routines that a vector can take on would help
105 this immensely.
106
107 Implementation
108 --------------
109
110 ### Line numbers in analysis error messages
111
112 For analysis errors, there is a line number, but it's the line of the routine
113 after the routine in which the analysis error occurred. Fix this.
114
115 Blue-skying
116 -----------
30117
31118 ### Pointers associated globally with a table(?)
32119
44131
45132 These can co-exist with general, non-specific-table-linked `pointer` variables.
46133
47 ### Space optimization of local non-statics
48
49 If there are two routines A and B, and A never calls B (even indirectly), and
50 B never calls A (even indirectly), then their non-static locals can
51 be allocated at the same space.
52
53 This is more an impressive trick than a really useful feature, but still.
54 Impressive tricks are impressive.
55
56 ### Copy byte to/from table
57
58 Do we want a `copy bytevar, table + x` instruction? We don't currently have one.
59 You have to `ld a`, `st a`. I think maybe we should have one.
60
61 ### Analyze memory usage
62
63 If you define two variables that occupy the same address, an analysis error ought
64 to be raised. (But there should also be a way to annotate this as intentional.
65 Intentionally making two tables overlap could be valuable. However, the analysis
66 will probably completely miss this fact.)
67
68 ### Character literals
69
70 For goodness sake, let the programmer say `'A'` instead of `65`.
71
72 ### Character set mapping
73
74 Not all computers think `'A'` should be `65`. Allow the character set to be
75 mapped. Probably copy what Ophis does.
76
77 ### Tail-call optimization
78
79 If a block ends in a `call` can that be converted to end in a `goto`? Why not? I think it can,
80 if the block is in tail position. The constraints should iron out the same both ways.
81
82 As long as the routine has consistent type context every place it exits, that should be fine.
83
84 ### "Include" directives
85
86 Search a searchlist of include paths. And use them to make libraries of routines.
87
88 One such library routine might be an `interrupt routine` type for various architectures.
89 Since "the supervisor" has stored values on the stack, we should be able to trash them
90 with impunity, in such a routine.
91
92 ### Line numbers in analysis error messages
93
94 For analysis errors, there is a line number, but it's the line of the routine
95 after the routine in which the analysis error occurred. Fix this.
134 If we have local pointers and space optimization for local non-statics, though,
135 these don't add as much.
1515 from tempfile import NamedTemporaryFile
1616 import traceback
1717
18 from sixtypical.parser import Parser, SymbolTable, merge_programs
18 from sixtypical.symtab import SymbolTable
19 from sixtypical.parser import Parser, merge_programs
1920 from sixtypical.analyzer import Analyzer
2021 from sixtypical.outputter import outputter_class_for
2122 from sixtypical.compiler import Compiler
183184 argparser.add_argument(
184185 "--version",
185186 action="version",
186 version="%(prog)s 0.19"
187 version="%(prog)s 0.20"
187188 )
188189
189190 options, unknown = argparser.parse_known_args(sys.argv[1:])
00 SixtyPical
11 ==========
22
3 This document describes the SixtyPical programming language version 0.19,
3 This document describes the SixtyPical programming language version 0.20,
44 both its static semantics (the capabilities and limits of the static
55 analyses it defines) and its runtime semantics (with reference to the
66 semantics of 6502 machine code.)
195195 There are extended instruction modes for using these types of memory location.
196196 See `copy` below, but here is some illustrative example code:
197197
198 point ptr into buf { // this is the only way to initialize a pointer
198 point ptr into buf { // this associates this pointer with this table
199 reset ptr 0 // this is the only way to initialize a pointer
199200 add ptr, 4 // note, this is unchecked against table's size!
200201 ld y, 0 // you must set this to something yourself
201202 copy [ptr] + y, byt // read memory through pointer, into byte
657658 | "repeat" Block ("until" ["not"] LocExpr | "forever")
658659 | "for" LocExpr ("up"|"down") "to" Const Block
659660 | "with" "interrupts" LitBit Block
661 | "point" LocExpr "into" LocExpr Block
662 | "reset" LocExpr Const
660663 .
268268 st off, c
269269 add ptr, new_pos
270270 ld y, 0
271
271272 // check collision.
272273 ld a, [ptr] + y
273 }
274
275 // if "collision" is with your own self, treat it as if it's blank space!
276 cmp a, 81
277 if z {
278 ld a, 32
279 }
280 cmp a, 32
281 if z {
282 point ptr into screen {
274
275 // if "collision" is with your own self, treat it as if it's blank space!
276 cmp a, 81
277 if z {
278 ld a, 32
279 }
280 cmp a, 32
281 if z {
283282 reset ptr 0
284283 st off, c
285284 add ptr, pos
286285 copy 32, [ptr] + y
287 }
288
289 copy new_pos, pos
290
291 point ptr into screen {
286
287 copy new_pos, pos
288
292289 reset ptr 0
293290 st off, c
294291 add ptr, pos
295292 copy 81, [ptr] + y
296293 }
297 } else {
298 ld a, 1
299 st a, player_died
300 }
294 }
295 } else {
296 ld a, 1
297 st a, player_died
301298 }
302299 }
303300
313310 st off, c
314311 add ptr, new_pos
315312 ld y, 0
313
316314 // check collision.
317315 ld a, [ptr] + y
318 }
319 // if "collision" is with your own self, treat it as if it's blank space!
320 cmp a, 82
321 if z {
322 ld a, 32
323 }
324 cmp a, 32
325 if z {
326 point ptr into screen {
316
317 // if "collision" is with your own self, treat it as if it's blank space!
318 cmp a, 82
319 if z {
320 ld a, 32
321 }
322 cmp a, 32
323 if z {
327324 reset ptr 0
328325 st off, c
329326 add ptr, pos
330327 copy 32, [ptr] + y
331 }
332
333 copy new_pos, pos
334
335 point ptr into screen {
328
329 copy new_pos, pos
330
336331 reset ptr 0
337332 st off, c
338333 add ptr, pos
0 // Include `support/${PLATFORM}.60p` before this source
1 // Should print H (being ASCII 72 = 8 * 9)
2
3 // Increase y by 7, circuitously
4 //
5 define foo routine
6 inputs y
7 outputs y, n, z
8 trashes a, c
9 {
10 save x {
11 ld x, 0
12 for x up to 6 {
13 inc y
14 }
15 }
16 }
17
18 // Each iteration increases y by 8; there are 9 iterations
19 //
20 define main routine
21 outputs x, y, n, z
22 trashes a, c
23 {
24 ld x, 0
25 ld y, 0
26 for x up to 8 {
27 inc y
28 call foo
29 }
30 ld a, y
31 call chrout
32 }
229229 elif isinstance(instr, For):
230230 self.analyze_for(instr, context)
231231 elif isinstance(instr, WithInterruptsOff):
232 self.analyze_block(instr.block, context)
233 if context.encountered_gotos():
234 raise IllegalJumpError(instr, instr)
232 self.analyze_with_interrupts_off(instr, context)
235233 elif isinstance(instr, Save):
236234 self.analyze_save(instr, context)
237235 elif isinstance(instr, PointInto):
289287 target = context.get_assoc(dest.ref)
290288 if not target:
291289 raise ForbiddenWriteError(instr, dest.ref)
292 context.set_touched(target)
293290 context.set_written(target)
294291
295292 elif self.get_type(src) != self.get_type(dest):
464461 target = context.get_assoc(dest.ref)
465462 if not target:
466463 raise ForbiddenWriteError(instr, dest.ref)
467 context.assert_writeable(target)
468 context.set_touched(target)
469464 context.set_written(target)
470465
471466 elif isinstance(src, IndirectRef) and isinstance(dest, LocationRef):
476471 raise UnmeaningfulReadError(instr, src.ref)
477472 context.assert_meaningful(origin)
478473
479 context.assert_writeable(dest)
480 context.set_touched(dest)
481474 context.set_written(dest)
475
482476 elif isinstance(src, IndirectRef) and isinstance(dest, IndirectRef):
483477 context.assert_meaningful(src.ref, dest.ref, REG_Y)
484478
490484 target = context.get_assoc(dest.ref)
491485 if not target:
492486 raise ForbiddenWriteError(instr, dest.ref)
493 context.assert_writeable(target)
494 context.set_touched(target)
495487 context.set_written(target)
496488
497489 elif isinstance(src, LocationRef) and isinstance(dest, IndexedRef):
502494 context.set_written(dest.ref)
503495 elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef):
504496 context.assert_meaningful(src.ref, src.index)
505 context.set_touched(dest)
506497 context.set_written(dest)
507498 else:
508499 context.assert_meaningful(src)
568559 exit_context = context.clone()
569560
570561 for ref in type_.outputs:
571 exit_context.set_touched(ref) # ?
572562 exit_context.set_written(ref)
573563
574564 for ref in type_.trashes:
676666 context.set_range(instr.dest, instr.final, instr.final)
677667 context.set_writeable(instr.dest)
678668
669 def analyze_with_interrupts_off(self, instr, context):
670 block = instr.block
671 for instr in block.instrs:
672 if isinstance(instr, (Call, GoTo, WithInterruptsOff)):
673 raise IllegalJumpError(instr, instr)
674 self.analyze_instr(instr, context)
675
679676 def analyze_save(self, instr, context):
680677 batons = []
681678 for location in instr.locations:
55 from sixtypical.model import (
66 TYPE_BIT, TYPE_BYTE, TYPE_WORD,
77 RoutineType, VectorType, TableType, PointerType,
8 LocationRef, ConstantRef, IndirectRef, IndexedRef,
8 ConstantRef, IndirectRef, IndexedRef,
99 )
1010 from sixtypical.scanner import Scanner
11
12
13 class SymEntry(object):
14 def __init__(self, ast_node, type_):
15 self.ast_node = ast_node
16 self.type_ = type_
17
18 def __repr__(self):
19 return "%s(%r, %r)" % (self.__class__.__name__, self.ast_node, self.type_)
11 from sixtypical.symtab import SymEntry
2012
2113
2214 class ForwardReference(object):
2517
2618 def __repr__(self):
2719 return "%s(%r)" % (self.__class__.__name__, self.name)
28
29
30 class SymbolTable(object):
31 def __init__(self):
32 self.symbols = {} # symbol name -> SymEntry
33 self.locals = {} # routine name -> (symbol name -> SymEntry)
34 self.typedefs = {} # type name -> Type AST
35 self.consts = {} # const name -> ConstantRef
36
37 for name in ('a', 'x', 'y'):
38 self.symbols[name] = SymEntry(None, TYPE_BYTE)
39 for name in ('c', 'z', 'n', 'v'):
40 self.symbols[name] = SymEntry(None, TYPE_BIT)
41
42 def __str__(self):
43 return "Symbols: {}\nLocals: {}\nTypedefs: {}\nConsts: {}".format(self.symbols, self.locals, self.typedefs, self.consts)
44
45 def has_local(self, routine_name, name):
46 return name in self.locals.get(routine_name, {})
47
48 def fetch_global_type(self, name):
49 return self.symbols[name].type_
50
51 def fetch_local_type(self, routine_name, name):
52 return self.locals[routine_name][name].type_
53
54 def fetch_global_ref(self, name):
55 if name in self.symbols:
56 return LocationRef(name)
57 return None
58
59 def fetch_local_ref(self, routine_name, name):
60 routine_locals = self.locals.get(routine_name, {})
61 if name in routine_locals:
62 return LocationRef(name)
63 return None
6420
6521
6622 class Parser(object):
0 # encoding: UTF-8
1
2 from sixtypical.model import (
3 TYPE_BIT, TYPE_BYTE, LocationRef,
4 )
5
6
7 class SymEntry(object):
8 def __init__(self, ast_node, type_):
9 self.ast_node = ast_node
10 self.type_ = type_
11
12 def __repr__(self):
13 return "%s(%r, %r)" % (self.__class__.__name__, self.ast_node, self.type_)
14
15
16 class SymbolTable(object):
17 def __init__(self):
18 self.symbols = {} # symbol name -> SymEntry
19 self.locals = {} # routine name -> (symbol name -> SymEntry)
20 self.typedefs = {} # type name -> Type AST
21 self.consts = {} # const name -> ConstantRef
22
23 for name in ('a', 'x', 'y'):
24 self.symbols[name] = SymEntry(None, TYPE_BYTE)
25 for name in ('c', 'z', 'n', 'v'):
26 self.symbols[name] = SymEntry(None, TYPE_BIT)
27
28 def __str__(self):
29 return "Symbols: {}\nLocals: {}\nTypedefs: {}\nConsts: {}".format(self.symbols, self.locals, self.typedefs, self.consts)
30
31 def has_local(self, routine_name, name):
32 return name in self.locals.get(routine_name, {})
33
34 def fetch_global_type(self, name):
35 return self.symbols[name].type_
36
37 def fetch_local_type(self, routine_name, name):
38 return self.locals[routine_name][name].type_
39
40 def fetch_global_ref(self, name):
41 if name in self.symbols:
42 return LocationRef(name)
43 return None
44
45 def fetch_local_ref(self, routine_name, name):
46 routine_locals = self.locals.get(routine_name, {})
47 if name in routine_locals:
48 return LocationRef(name)
49 return None
00 #!/bin/sh
11
2 # This currently represents a lot of tests! If you only want to run a subset,
3 # it's probably best to run `falderal` manually on the file(s) you want to test.
4
25 falderal --substring-error \
6 "tests/appliances/sixtypical.md" \
37 "tests/SixtyPical Syntax.md" \
48 "tests/SixtyPical Analysis.md" \
59 "tests/SixtyPical Storage.md" \
88 For control flow, see [SixtyPical Control Flow](SixtyPical%20Control%20Flow.md).
99
1010 [Falderal]: http://catseye.tc/node/Falderal
11
12 -> Functionality "Analyze SixtyPical program" is implemented by
13 -> shell command "bin/sixtypical --analyze-only --traceback %(test-body-file) && echo ok"
1411
1512 -> Tests for functionality "Analyze SixtyPical program"
1613
753750 | }
754751 ? IllegalJumpError
755752
753 A `call` cannot appear within a `with interrupts` block.
754
755 | vector routine
756 | inputs x
757 | outputs x
758 | trashes z, n
759 | bar
760 |
761 | define foo routine
762 | inputs x
763 | outputs x
764 | trashes z, n
765 | {
766 | inc x
767 | }
768 |
769 | define other routine
770 | trashes bar, a, n, z
771 | {
772 | ld a, 0
773 | }
774 |
775 | define main routine
776 | trashes bar, a, n, z
777 | {
778 | with interrupts off {
779 | copy foo, bar
780 | call other
781 | }
782 | }
783 ? IllegalJumpError
784
785 A `with interrupts` block cannot appear within a `with interrupts` block.
786
787 | vector routine
788 | inputs x
789 | outputs x
790 | trashes z, n
791 | bar
792 |
793 | define foo routine
794 | inputs x
795 | outputs x
796 | trashes z, n
797 | {
798 | inc x
799 | }
800 |
801 | define main routine
802 | trashes bar, a, n, z
803 | {
804 | with interrupts off {
805 | copy foo, bar
806 | with interrupts off {
807 | copy foo, bar
808 | }
809 | }
810 | }
811 ? IllegalJumpError
812
756813 ### typedef ###
757814
758815 A typedef is a more-readable alias for a type. "Alias" means
44 SixtyPical to 6502 machine code.
55
66 [Falderal]: http://catseye.tc/node/Falderal
7
8 -> Functionality "Compile SixtyPical program" is implemented by
9 -> shell command "bin/sixtypical --output-format=c64-basic-prg --traceback %(test-body-file) --output /tmp/foo && tests/appliances/bin/dcc6502-adapter </tmp/foo"
107
118 -> Tests for functionality "Compile SixtyPical program"
129
703703 | }
704704 ? UnmeaningfulReadError: y
705705
706 And in particular, you can't uninitialize the loop variable, in the loop.
707
708 | define foo routine
709 | trashes x
710 | {
711 | }
712 |
713 | define main routine
714 | outputs x, y, n, z
715 | trashes c
716 | {
717 | ld x, 0
718 | ld y, 15
719 | for x up to 15 {
720 | inc y
721 | call foo
722 | }
723 | }
724 ? ForbiddenWriteError: x
725
726 So, if you call a routine from inside the loop, it better not also
727 loop on the same variable.
728
729 | define foo routine
730 | inputs y
731 | outputs x, y, n, z
732 | trashes c
733 | {
734 | ld x, 0
735 | for x up to 15 {
736 | inc y
737 | }
738 | }
739 |
740 | define main routine
741 | outputs x, y, n, z
742 | trashes c
743 | {
744 | ld x, 0
745 | ld y, 15
746 | for x up to 15 {
747 | inc y
748 | call foo
749 | }
750 | }
751 ? ForbiddenWriteError: x
752
753 But if you take care to save and restore the loop variable in the
754 called routine, it will be okay.
755
756 | define foo routine
757 | inputs y
758 | outputs y, n, z
759 | trashes a, c
760 | {
761 | save x {
762 | ld x, 0
763 | for x up to 15 {
764 | inc y
765 | }
766 | }
767 | }
768 |
769 | define main routine
770 | outputs x, y, n, z
771 | trashes a, c
772 | {
773 | ld x, 0
774 | ld y, 15
775 | for x up to 15 {
776 | inc y
777 | call foo
778 | }
779 | }
780 = ok
781
706782 The "for" loop does not preserve the `z` or `n` registers.
707783
708784 | define foo routine trashes x {
5959 to pass these tests to be considered an implementation of SixtyPical.
6060
6161 [Falderal]: http://catseye.tc/node/Falderal
62
63 -> Functionality "Dump fallthru info for SixtyPical program" is implemented by
64 -> shell command "bin/sixtypical --optimize-fallthru --dump-fallthru-info --analyze-only --traceback %(test-body-file)"
65
66 -> Functionality "Compile SixtyPical program with fallthru optimization" is implemented by
67 -> shell command "bin/sixtypical --output-format=c64-basic-prg --optimize-fallthru --traceback %(test-body-file) --output /tmp/foo && tests/appliances/bin/dcc6502-adapter </tmp/foo"
6862
6963 -> Tests for functionality "Dump fallthru info for SixtyPical program"
7064
15881588 | }
15891589 ? RangeExceededError
15901590
1591 ### dynamic recurrence of `point ... into` blocks
1592
1593 You cannot call a routine which trashes the pointer from inside a
1594 `point ... into` block. Remember that `point ... into` by
1595 itself doesn't change anything, so doesn't trash anything.
1596
1597 | byte table[256] tab
1598 | byte table[256] other
1599 | pointer ptr
1600 |
1601 | define sub routine
1602 | inputs other
1603 | outputs other
1604 | {
1605 | point ptr into other {
1606 | }
1607 | }
1608 |
1609 | define main routine
1610 | inputs tab, other
1611 | outputs tab, other
1612 | trashes a, y, c, z, n, v, ptr
1613 | {
1614 | ld y, 0
1615 | point ptr into tab {
1616 | reset ptr 0
1617 | copy 123, [ptr] + y
1618 | call sub
1619 | copy 123, [ptr] + y
1620 | }
1621 | }
1622 = ok
1623
1624 | byte table[256] tab
1625 | byte table[256] other
1626 | pointer ptr
1627 |
1628 | define sub routine
1629 | inputs other
1630 | outputs other
1631 | trashes ptr
1632 | {
1633 | point ptr into other {
1634 | reset ptr 0
1635 | }
1636 | }
1637 |
1638 | define main routine
1639 | inputs tab, other
1640 | outputs tab, other
1641 | trashes a, y, c, z, n, v, ptr
1642 | {
1643 | ld y, 0
1644 | point ptr into tab {
1645 | reset ptr 0
1646 | copy 123, [ptr] + y
1647 | call sub
1648 | copy 123, [ptr] + y
1649 | }
1650 | }
1651 ? UnmeaningfulReadError
1652
15911653 ### locals ###
15921654
15931655 When memory locations are defined static to a routine, they cannot be
77 but not necessarily sensible programs.
88
99 [Falderal]: http://catseye.tc/node/Falderal
10
11 -> Functionality "Check syntax of SixtyPical program" is implemented by
12 -> shell command "bin/sixtypical --parse-only --traceback %(test-body-file) && echo ok"
1310
1411 -> Tests for functionality "Check syntax of SixtyPical program"
1512
0 This file contains only the [Falderal][] directives that define the different
1 functionalities tested by the test suite, assuming that it's the reference
2 implementation, `sixtypical`, that is going to implement these functionalities.
3
4 [Falderal]: http://catseye.tc/node/Falderal
5
6 -> Functionality "Check syntax of SixtyPical program" is implemented by
7 -> shell command "bin/sixtypical --parse-only --traceback %(test-body-file) && echo ok"
8
9 -> Functionality "Analyze SixtyPical program" is implemented by
10 -> shell command "bin/sixtypical --analyze-only --traceback %(test-body-file) && echo ok"
11
12 -> Functionality "Compile SixtyPical program" is implemented by
13 -> shell command "bin/sixtypical --output-format=c64-basic-prg --traceback %(test-body-file) --output /tmp/foo && tests/appliances/bin/dcc6502-adapter </tmp/foo"
14
15 -> Functionality "Dump fallthru info for SixtyPical program" is implemented by
16 -> shell command "bin/sixtypical --optimize-fallthru --dump-fallthru-info --analyze-only --traceback %(test-body-file)"
17
18 -> Functionality "Compile SixtyPical program with fallthru optimization" is implemented by
19 -> shell command "bin/sixtypical --output-format=c64-basic-prg --optimize-fallthru --traceback %(test-body-file) --output /tmp/foo && tests/appliances/bin/dcc6502-adapter </tmp/foo"