mirror of
https://github.com/badvision/lawless-legends.git
synced 2024-07-13 09:29:17 +00:00
Merge branch 'master' of https://github.com/badvision/lawless-legends
This commit is contained in:
commit
8c1da53987
@ -845,7 +845,7 @@ public class ApplicationUIControllerImpl extends ApplicationUIController {
|
||||
UIAction.editScript(event.getSource().getItems().get(event.getIndex()));
|
||||
}
|
||||
});
|
||||
final DragDropHelper<Script> scriptDragDrop = new DragDropHelper<>(Script.class);
|
||||
final TransferHelper<Script> scriptDragDrop = new TransferHelper<>(Script.class);
|
||||
mapScriptsList.setCellFactory(new Callback<ListView<Script>, ListCell<Script>>() {
|
||||
@Override
|
||||
public ListCell<Script> call(ListView<Script> param) {
|
||||
|
@ -0,0 +1,96 @@
|
||||
package org.badvision.outlaweditor;
|
||||
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import org.badvision.outlaweditor.data.xml.Image;
|
||||
|
||||
/**
|
||||
* Details about part of an image
|
||||
* @author blurry
|
||||
* @param <T> Represents the image renderer that can produce this image
|
||||
*/
|
||||
public class ImageClip<T extends ImageRenderer> {
|
||||
private final int clipId;
|
||||
private Rectangle bounds;
|
||||
private Image source;
|
||||
private ImageRenderer renderer;
|
||||
private Platform platform;
|
||||
private boolean allSelected;
|
||||
public ImageClip(Image src, boolean all, ImageRenderer r, Platform p) {
|
||||
source = src;
|
||||
renderer = r;
|
||||
platform = p;
|
||||
clipId = (int) (Math.random() * (double) Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public ImageClip(Image src, int x1, int y1, int x2, int y2, ImageRenderer r, Platform p) {
|
||||
this(src, false, r, p);
|
||||
bounds = new Rectangle(
|
||||
Math.min(x1,x2),
|
||||
Math.min(y1,y2),
|
||||
Math.abs(x2-x1),
|
||||
Math.abs(y2-y1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clipId
|
||||
*/
|
||||
public int getClipId() {
|
||||
return clipId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bounds
|
||||
*/
|
||||
public Rectangle getBounds() {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bounds the bounds to set
|
||||
*/
|
||||
public void setBounds(Rectangle bounds) {
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source
|
||||
*/
|
||||
public Image getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param source the source to set
|
||||
*/
|
||||
public void setSource(Image source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the renderer
|
||||
*/
|
||||
public ImageRenderer getRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param renderer the renderer to set
|
||||
*/
|
||||
public void setRenderer(ImageRenderer renderer) {
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the platform
|
||||
*/
|
||||
public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param platform the platform to set
|
||||
*/
|
||||
public void setPlatform(Platform platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import javafx.stage.Stage;
|
||||
import static org.badvision.outlaweditor.Application.currentPlatform;
|
||||
import org.badvision.outlaweditor.DragDropHelper.DropEventHandler;
|
||||
import org.badvision.outlaweditor.TransferHelper.DropEventHandler;
|
||||
import org.badvision.outlaweditor.data.TileMap;
|
||||
import org.badvision.outlaweditor.data.TileUtils;
|
||||
import org.badvision.outlaweditor.data.xml.Map;
|
||||
@ -53,7 +53,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
|
||||
TileMap currentMap;
|
||||
double tileWidth = currentPlatform.tileRenderer.getWidth() * zoom;
|
||||
double tileHeight = currentPlatform.tileRenderer.getHeight() * zoom;
|
||||
public static DragDropHelper<Script> scriptDragDrop = new DragDropHelper<>(Script.class);
|
||||
public static TransferHelper<Script> scriptDragDrop = new TransferHelper<>(Script.class);
|
||||
|
||||
@Override
|
||||
public void setEntity(Map t) {
|
||||
|
@ -18,7 +18,7 @@ import javafx.scene.input.TransferMode;
|
||||
* @author blurry
|
||||
* @param <T> Type of object being passed
|
||||
*/
|
||||
public class DragDropHelper<T> {
|
||||
public class TransferHelper<T> {
|
||||
|
||||
Class type;
|
||||
DataFormat format;
|
||||
@ -30,15 +30,19 @@ public class DragDropHelper<T> {
|
||||
public void handle(T object, double x, double y);
|
||||
}
|
||||
|
||||
private DragDropHelper() {
|
||||
private TransferHelper() {
|
||||
}
|
||||
|
||||
public DragDropHelper(Class<T> clazz) {
|
||||
public TransferHelper(Class<T> clazz) {
|
||||
type = clazz;
|
||||
format = getDataFormat(clazz);
|
||||
}
|
||||
|
||||
public static DataFormat getDataFormat(Class clazz) {
|
||||
if (!dataFormats.containsKey(clazz.getName())) {
|
||||
dataFormats.put(clazz.getName(), new DataFormat(clazz.getName()));
|
||||
}
|
||||
format = dataFormats.get(clazz.getName());
|
||||
return dataFormats.get(clazz.getName());
|
||||
}
|
||||
|
||||
public void registerDragSupport(final Node source, final T object) {
|
370
PLASMA/README.md
Normal file
370
PLASMA/README.md
Normal file
@ -0,0 +1,370 @@
|
||||
#PLASMA
|
||||
##Introduction
|
||||
|
||||
PLASMA is a combination of virtual machine and assembler/compiler matched closely to the 6502 architecture. It is an attempt to satisfy a few challenges surrounding code size, efficient execution, small runtime and fast just-in-time compilation. By architecting a unique bytecode that maps nearly one-to-one to the higher level representation, the compiler/assembler can be very simple and execute quickly on the Apple II for a self-hosted environment. A modular approach provides for incremental development and code reuse. Different projects have led to the architecture of PLASMA, most notably Apple Pascal, FORTH, and my own Java VM for the 6502, VM02. Each has tried to map a generic VM to the 6502 with varying levels of success. Apple Pascal, based on the USCD Pascal using the p-code interpreter, was a very powerful system and ran fast enough on the Apple II to be interactive but didn't win any speed contests. FORTH was the poster child for efficiency and obtuse syntax. Commonly referred to as a write only language, it was difficult to come up to speed as a developer, especially when using other's code. My own project in creating a Java VM for the Apple II uncovered the folly of shoehorning a large system into something never intended to run 32 bit applications.
|
||||
|
||||
##Low Level Implementation
|
||||
|
||||
Both the Pascal and Java VMs used a bytecode to hide the underlying CPU architecture and offer platform agnostic application execution. The application and tool chains were easily moved from platform to platform by simply writing a bytecode interpreter and small runtime to translate the higher level constructs to the underlying hardware. The performance of the system was dependent on the actual hardware and efficiency of the interpreter. Just-in-time compilation wasn't really an option on small, 8 bit systems. FORTH, on the other hand, was usually implemented as a threaded interpreter. A threaded interpreter will use the address of functions to call as the code stream instead of a bytecode, eliminating one level of indirection with a slight increase in code size. The threaded approach can be made faster at the expense of another slight increase in size by inserting an actual Jump SubRoutine opcode before each address, thus removing the interpreter's inner loop altogether.
|
||||
|
||||
All three systems were implemented using stack architecture. Pascal and Java were meant to be compiled high level languages, using a stack machine as a simple compilation target. FORTH was meant to be written directly as a stack oriented language, similar to RPN on HP calculators. The 6502 is a challenging target due to it's unusual architecture so writing a bytecode interpreter for Pascal and Java results in some inefficiencies and limitations. FORTH's inner interpreter loop on the 6502 tends to be less efficient than most other CPUs. Another difference is how each system creates and manipulates it's stack. Pascal and Java use the 6502 hardware stack for all stack operations. Unfortunately the 6502 stack is hard-limited to 256 bytes. However, in normal usage this isn't too much of a problem as the compilers don't put undue pressure on the stack size by keeping most values in global or local variables. FORTH creates a small stack using a portion of the 6502's zero page, a 256 byte area of low memory that can be accessed with only a byte address and indexed using either of the X or Y registers. With zero page, the X register can be used as an indexed, indirect address and the Y register can be used as an indirect, indexed address.
|
||||
|
||||
##A New Approach
|
||||
|
||||
PLASMA takes an approach that uses the best of all the above implementations to create a unique, powerful and efficient platform for developing new applications on the Apple II. One goal was to create a very small VM runtime, bytecode interpreter, and module loader that could adjust the code size vs. performance optimizations to allow for interpreted code, threaded code, or efficiently compiled native code. The decision was made early on to implement a stack based architecture duplicating the approach taken by FORTH. Space in the zero page would be assigned to a 16 bit, 32 element evaluation stack, indexed by the X register. The stack is purposely not split between low and high values so as to allow reading and writing addresses stored directly on the stack. The trade off is that the stack pointer has to be incremented and decremented by two for every push/pop operation. A simple compiler was written so that higher level constructs could be used and global/local variables would hold values instead of using clever stack manipulation. Function/procedure frames would allow for local variables, but with a limitation - the frame could be no larger than 256 bytes. By enforcing this limitation, the function frame could easily be accessed through a frame pointer value in zero page, indexed by the Y register. The call stack uses the 6502's hardware stack resulting in the same 256 byte limitation imposed by the hardware. However, this limitation could be lifted by extending the call sequence to save and restore the return address in the function frame. This was not done initially for performance reasons and simplicity of implementation. One of the goals of PLASMA was to allow for intermixing of functions implemented as bytecode, or native code. Taking a page from the FORTH play book, a function call is implemented as a native subroutine call to an address. If the function is in bytecode, the first thing it does is call back into the interpreter to execute the following bytecode. Function call parameters are pushed onto the evaluation stack in order they are written. The first operation inside of the function call is to pull the parameters off the evaluation stack and put them in local frame storage. Function callers and callees must agree on the number of parameters to avoid stack underflow/overflow. All functions return a value on the evaluation stack regardless of it being used or not. Lastly, PLASMA is not a typed language. Just like assembly, any value can represent a character, integer, or address. It's the programmer's job to know the type. Only bytes and words are known to PLASMA. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. All stack operations involve 16 bits of precision.
|
||||
|
||||
The PLASMA low level operations are defined as:
|
||||
|
||||
| OP | Description
|
||||
|-------|-----------------------------------
|
||||
| ZERO | push zero on the stack
|
||||
| ADD | add top two values, leave result on top
|
||||
| SUB | subtract next from top from top, leave result on top
|
||||
| MUL | multiply two topmost stack values, leave result on top
|
||||
| DIV | divide next from top by top, leave result on top
|
||||
| MOD | divide next from top by top, leave remainder on top
|
||||
| INCR | increment top of stack
|
||||
| DECR | decrement top of stack
|
||||
| NEG | negate top of stack
|
||||
| COMP | compliment top of stack
|
||||
| AND | bit wise AND top two values, leave result on top
|
||||
| IOR | bit wise inclusive OR top two values, leave result on top
|
||||
| XOR | bit wise exclusive OR top two values, leave result on top
|
||||
| LOR | logical OR top two values, leave result on top
|
||||
| LAND | logical AND top two values, leave result on top
|
||||
| SHL | shift left next from top by top, leave result on top
|
||||
| SHR | shift right next from top by top, leave result on top
|
||||
| IDXB | add top of stack to next from top, leave result on top (ADD)
|
||||
| IDXW | add 2X top of stack to next from top, leave result on top
|
||||
| NOT | logical NOT of top of stack
|
||||
| LA | load address
|
||||
| LLA | load local address from frame offset
|
||||
| CB | constant byte
|
||||
| CW | constant word
|
||||
| SWAP | swap two topmost stack values
|
||||
| DROP | drop top stack value
|
||||
| DUP | duplicate top stack value
|
||||
| PUSH | push top to call stack
|
||||
| PULL | pull from call stack
|
||||
| BRGT | branch next from top greater than top
|
||||
| BRLT | branch next from top less than top
|
||||
| BREQ | branch next from top equal to top
|
||||
| BRNE | branch next from top not equal to top
|
||||
| ISEQ | if next from top is equal to top, set top true
|
||||
| ISNE | if next from top is not equal to top, set top true
|
||||
| ISGT | if next from top is greater than top, set top true
|
||||
| ISLT | if next from top is less than top, set top true
|
||||
| ISGE | if next from top is greater than or equal to top, set top true
|
||||
| ISLE | if next from top is less than or equal to top, set top true
|
||||
| BRFLS | branch if top of stack is zero
|
||||
| BRTRU | branch if top of stack is non-zero
|
||||
| BRNCH | branch to address
|
||||
| CALL | sub routine call with stack parameters
|
||||
| ICAL | sub routine call to indirect address on stack top with stack parameters
|
||||
| ENTER | allocate frame size and copy stack parameters to local frame
|
||||
| LEAVE | deallocate frame and return from sub routine call
|
||||
| RET | return from sub routine call
|
||||
| LB | load byte from top of stack address
|
||||
| LW | load word from top of stack address
|
||||
| LLB | load byte from frame offset
|
||||
| LLW | load word from frame offset
|
||||
| LAB | load byte from absolute address
|
||||
| LAW | load word from absolute address
|
||||
| SB | store top of stack byte into next from top address
|
||||
| SW | store top of stack word into next from top address
|
||||
| SLB | store top of stack into local byte at frame offset
|
||||
| SLW | store top of stack into local word at frame offset
|
||||
| SAB | store top of stack into byte at absolute address
|
||||
| SAW | store top of stack into word at absolute address
|
||||
| DLB | duplicate top of stack into local byte at frame offset
|
||||
| DLW | duplicate top of stack into local word at frame offset
|
||||
| DAB | duplicate top of stack into byte at absolute address
|
||||
| DAW | duplicate top of stack into word at absolute address
|
||||
|
||||
|
||||
##PLASMA Compiler/Assembler
|
||||
|
||||
Although the low-level operations could easily by coded by hand, they were chosen to be an easy target for a simple compiler. Think along the lines of an advanced assembler or stripped down C compiler ( C--). Taking concepts from BASIC, Pascal, C and assembler, the PLASMA compiler is simple yet expressive. The syntax is line oriented; there is no statement delimiter except newline.
|
||||
|
||||
Comments are allowed throughout the source, starting with the ‘;’ character. The rest of the line is ignored.
|
||||
|
||||
```
|
||||
; Data and text buffer constants
|
||||
```
|
||||
|
||||
Hexadecimal constants are preceded with a ‘$’ to identify them as such.
|
||||
|
||||
```
|
||||
$C030 ; Speaker address
|
||||
```
|
||||
|
||||
###Constants, Variables and Functions
|
||||
|
||||
The source code of a PLASMA module first defines constants, variables and data. Constants must be initialized with a value. Variables can have sizes associated with them to declare storage space. Data can be declared with or without a variable name associated with it. Arrays, tables, strings and any predeclared data can be created and accessed in multiple ways.
|
||||
|
||||
```
|
||||
;
|
||||
; Constants used for hardware and flags
|
||||
;
|
||||
const speaker = $C030
|
||||
const changed = 1
|
||||
const insmode = 2
|
||||
;
|
||||
; Array declaration of screen row addresses
|
||||
;
|
||||
word txtscrn[] = $0400,$0480,$0500,$0580,$0600,$0680,$0700,$0780
|
||||
word = $0428,$04A8,$0528,$05A8,$0628,$06A8,$0728,$07A8
|
||||
word = $0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0
|
||||
;
|
||||
; Misc global variables
|
||||
;
|
||||
byte flags = 0
|
||||
word numlines = 0
|
||||
byte cursx, cursy
|
||||
word cursrow, scrntop, cursptr
|
||||
```
|
||||
|
||||
Variables can have optional brackets; empty brackets don’t reserve any space for the variable but are useful as a label for data that is defined following the variable. Brackets with a constant inside defines a minimum size reserved for the variable. Any data following the variable will take at least the amount of reserved space, but potentially more.
|
||||
|
||||
Strings are defined like Pascal strings, a length byte followed by the string characters so they can be a maximum of 255 characters long. Strings can only appear in the variable definitions of a module. String constants can’t be used in expressions or statements.
|
||||
|
||||
```
|
||||
;
|
||||
; An initialized string of 64 characters
|
||||
;
|
||||
byte txtfile[64] = "UNTITLED"
|
||||
```
|
||||
|
||||
Functions are defined after all constants, variables and data. Functions can be forward declared with a func type in the constant and variable declarations. Functions have optional parameters and always return a value. By using one of three function declarations (def, deft and defn) you can have the function loaded as interpreted bytecode, threaded calls into the interpreter, or natively compiled code. There are space and time tradeoffs between the three choices. Bytecode is the best choice for the majority of functions. It has decent performance and is extremely compact. Threaded code would be the choice for functions that are called often but are not leaf routines, i.e. they themselves call other functions. Native code is a good choice for small, leaf functions that are called often and need the highest performance. Simply altering the definition is all that is required to set the function code implementation. Functions can have their own variable declarations. However, unlike the global declarations, no data can be predeclared, only storage space. There is also a limit of 256 bytes of local storage. Each parameter takes two bytes of local storage, plus two bytes for the previous frame pointer. If a function has no parameters or local variables, no local frame will be created, improving performance. A function can specify a value to return. If no return value is specified, a default of 0 will be returned.
|
||||
|
||||
After functions are defined, the main code for the module follows. There is no option to declare how the main code is loaded - it is always bytecode. The last statement in the module must be done, or else a compile error is issued.
|
||||
|
||||
There are four basic types of data that can be manipulated: constants, variables, addresses, and functions. Memory can only be read or written as either a byte or a word. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. Everything on the evaluation stack is treated as a word. Other than that, any value can be treated as a pointer, address, function, character, integer, etc. There are convenience operations in PLASMA to easily manipulate addresses and expressions as pointers, arrays, structures, functions, or combinations thereof. If a variable is declared as a byte, it can be accessed as a simple, single dimension byte array by using brackets to indicate the offset. Any expression can calculate the indexed offset. A word variable can be accessed as a word array in the same fashion. In order to access expressions or constants as arrays, a type identifier has to be inserted before the brackets. a ‘.’ character denotes a byte type, a ‘:’ character denotes a word type. Along with brackets to calculate an indexed offset, a constant can be used after the ‘.’ or ‘:’ and will be added to the base address. The constant can be a defined const to allow for structure style syntax. If the offset is a known constant, using the constant offset is a much more efficient way to address the elements over an array index. Multidimensional arrays are treated as arrays of array pointers. Multiple brackets can follow the ‘.’ or ‘:’ type identifier, but all but the last index will be treated as a pointer to an array.
|
||||
|
||||
```
|
||||
word hgrscan[] = $2000,$2400,$2800,$2C00,$3000,$3400,$3800,$3C00
|
||||
word = $2080,$2480,$2880,$2C80,$3080,$3480,$3880,$3C80
|
||||
|
||||
hgrscan:[yscan][xscan] = fillval
|
||||
```
|
||||
|
||||
Values can be treated as pointers by preceding them with a ‘^’ for byte pointers, ‘*’ for word pointers.
|
||||
|
||||
```
|
||||
strlen = ^srcstr
|
||||
```
|
||||
|
||||
Addresses of variables and functions can be taken with a preceding ‘@’, address-of operator. Parenthesis can surround an expression to be used as a pointer, but not address-of.
|
||||
|
||||
Functions can have optional parameters when called. Defined functions without parameters can be called simply:
|
||||
|
||||
```
|
||||
def redraw
|
||||
cursoff
|
||||
drawscrn(scrntop, scrnleft)
|
||||
curson
|
||||
end
|
||||
|
||||
redraw
|
||||
```
|
||||
|
||||
Functions with parameters or expressions to be used as a function address to call must use parenthesis, even if empty.
|
||||
|
||||
```
|
||||
word keyin
|
||||
byte key
|
||||
|
||||
keyin = @keyin2plus ; address-of keyin2plus function
|
||||
key = keyin()
|
||||
```
|
||||
|
||||
Expressions and Statements
|
||||
|
||||
Expressions are algebraic. Data is free-form, but all operations on the evaluation stack use 16 bits of precision with the exception of byte load and stores. A stand-alone expression will be evaluated and read from or called. This allows for easy access to the Apple’s soft switches and other memory mapped hardware. The value of the expression is dropped.
|
||||
|
||||
```
|
||||
const speaker=$C030
|
||||
|
||||
^speaker ; click speaker
|
||||
close(refnum)
|
||||
```
|
||||
|
||||
More complex expressions can be built up using algebraic unary and binary operations.
|
||||
|
||||
| OP | Unary Operation
|
||||
|------|--------------------
|
||||
| ^ | byte pointer
|
||||
| * | word pointer
|
||||
| @ | address of
|
||||
| - | negate
|
||||
| ~ | bitwise compliment
|
||||
| ! | logical NOT
|
||||
|
||||
|
||||
| OP | Binary Operation
|
||||
|------|---------------------
|
||||
| * | multiply
|
||||
| / | divide
|
||||
| % | modulo
|
||||
| + | add
|
||||
| - | subtract
|
||||
| << | shift left
|
||||
| >> | shift right
|
||||
| & | bitwise AND
|
||||
| | | bitwise OR
|
||||
| ^ | bitwise XOR
|
||||
| == | equals
|
||||
| <> | not equal
|
||||
| >= | greater than or equal
|
||||
| > | greater than
|
||||
| <= | less than or equal
|
||||
| < | less than
|
||||
| OR | logical OR
|
||||
| AND | logical AND
|
||||
|
||||
Statements are built up from expressions and control flow keywords. Simplicity of syntax took precedence over flexibility and complexity. The simplest statement is the basic assignment using ‘=’.
|
||||
|
||||
```
|
||||
byte numchars
|
||||
numchars = 0
|
||||
```
|
||||
|
||||
Expressions can be built up with constants, variables, function calls, addresses, and pointers/arrays. Comparison operators evaluate to 0 or -1 instead of the more traditional 0 or 1. The use of -1 allows binary operations to be applied to other non-zero values and still retain a non-zero result. Any conditional tests check only for zero and non-zero values.
|
||||
|
||||
Control structures affect the flow of control through the program. There are conditional and looping constructs. The most widely used is probably the if/elsif/else/fin construct.
|
||||
|
||||
```
|
||||
if ^pushbttn3 < 128
|
||||
if key == $C0
|
||||
key = $D0 ; P
|
||||
elsif key == $DD
|
||||
key = $CD ; M
|
||||
elsif key == $DE
|
||||
key = $CE ; N
|
||||
fin
|
||||
else
|
||||
key = key | $E0
|
||||
fin
|
||||
```
|
||||
|
||||
The when/is/otherwise/wend statement is similar to the if/elsif/else/fin construct except that it is more efficient. It selects one path based on the evaluated expressions, then merges the code path back together at the end. However only the 'when' value is compared against a list of expressions. The expressions do not need to be constants, they can be any valid expression. The list of expressions is evaluated in order, so for efficiency sake, place the most common cases earlier in the list.
|
||||
|
||||
```
|
||||
when keypressed
|
||||
is keyarrowup
|
||||
cursup
|
||||
is keyarrowdown
|
||||
cursdown
|
||||
is keyarrowleft
|
||||
cursleft
|
||||
is keyarrowright
|
||||
cursright
|
||||
is keyctrlx
|
||||
cutline
|
||||
is keyctrlv
|
||||
pasteline
|
||||
is keyescape
|
||||
cursoff
|
||||
cmdmode
|
||||
redraw
|
||||
otherwise
|
||||
bell
|
||||
wend
|
||||
```
|
||||
|
||||
The most common looping statement is the for/next construct.
|
||||
|
||||
```
|
||||
for xscan = 0 to 19
|
||||
(scanptr):[xscan] = val
|
||||
next
|
||||
```
|
||||
|
||||
The for/next statement will efficiently increment or decrement a variable form the starting value to the ending value. The increment/decrement amount can be set with the step option after the ending value; the default is one. If the ending value is less than the starting value, use downto instead of to to progress in the negative direction. Only use positive step values. The to or downto will add or subtract the step value appropriately.
|
||||
|
||||
```
|
||||
for i = heapmapsz - 1 downto 0
|
||||
if sheapmap.[i] <> $FF
|
||||
mapmask = szmask
|
||||
fin
|
||||
next
|
||||
```
|
||||
|
||||
while/loop statements will continue looping as long as the while expression is non-zero.
|
||||
|
||||
```
|
||||
while !(mask & 1)
|
||||
addr = addr + 16
|
||||
mask = mask >> 1
|
||||
loop
|
||||
```
|
||||
|
||||
Lastly, the repeat/until statement will continue looping as long as the until expression is zero.
|
||||
|
||||
```
|
||||
repeat
|
||||
txtbuf = read(refnum, @txtbuf + 1, maxlnlen)
|
||||
numlines = numlines + 1
|
||||
until txtbuf == 0 or numlines == maxlines
|
||||
```
|
||||
|
||||
###Runtime
|
||||
|
||||
PLASMA includes a very minimal runtime that nevertheless provides a great deal of functionality to the system. Two system calls are provided to access native 6502 routines (usually in ROM) and ProDOS.
|
||||
|
||||
call6502(aReg, xReg, yReg, statusReg, addr) returns a pointer to a four byte structure containing the A,X,Y and STATUS register results.
|
||||
|
||||
```
|
||||
const xreg = 1
|
||||
const getlin = $FD6A
|
||||
|
||||
numchars = (call6502(0, 0, 0, 0, getlin)).xreg ; return char count in X reg
|
||||
```
|
||||
|
||||
prodos(cmd, params) calls ProDOS, returning the status value.
|
||||
|
||||
```
|
||||
def read(refnum, buff, len)
|
||||
byte params[8]
|
||||
|
||||
params.0 = 4
|
||||
params.1 = refnum
|
||||
params:2 = buff
|
||||
params:4 = len
|
||||
perr = prodos($CA, @params)
|
||||
return params:6
|
||||
end
|
||||
```
|
||||
|
||||
cout(char), prstr(string), prstrz(stringz) are handy utility routines for printing to the standard Apple II COUT routine.
|
||||
|
||||
```
|
||||
cout('.')
|
||||
byte okstr[] = "OK"
|
||||
prstr(@okstr)
|
||||
```
|
||||
|
||||
memset(val16, addr, len) will fill memory with a 16 bit value. memcpy(dstaddr, srcaddr, len) will copy memory from one address to another, taking care to copy in the proper direction.
|
||||
|
||||
```
|
||||
byte nullstr[] = ""
|
||||
memset(@nullstr, strlinbuf, maxfill * 2) ; fill line buff with pointer to null string
|
||||
memcpy(scrnptr, strptr + ofst + 1, numchars)
|
||||
```
|
||||
|
||||
##Implementation Details
|
||||
|
||||
The original design concept was to create an efficient, flexible, and expressive environment for building applications directly on the Apple II. Choosing a stack based architecture was easy after much experience with other stack based implementations. It also makes the compiler simple to implement. The first take on the stack architecture was to make it a very strict stack architecture in that everything had to be on the stack. The only opcode with operands was the CONSTANT opcode. This allowed for a very small bytecode interpreter and a very easy compile target. However, only when adding an opcode with operands that would greatly improved performance, native code generation or code size was it done. The opcode table grew slowly over time but still retains a small runtime interpreter with good native code density.
|
||||
|
||||
## References
|
||||
B Programming Language User Manual http://cm.bell-labs.com/cm/cs/who/dmr/kbman.html
|
||||
|
||||
FORTH http://en.wikipedia.org/wiki/Forth_(programming_language)
|
||||
|
||||
UCSD Pascal http://wiki.freepascal.org/UCSD_Pascal
|
||||
|
||||
p-code https://www.princeton.edu/~achaney/tmve/wiki100k/docs/P-code_machine.html
|
||||
|
||||
VM02: Apple II Java VM http://sourceforge.net/projects/vm02/
|
||||
|
||||
Threaded code http://en.wikipedia.org/wiki/Threaded_code
|
1272
PLASMA/src/cmd.pla
Normal file
1272
PLASMA/src/cmd.pla
Normal file
File diff suppressed because it is too large
Load Diff
234
PLASMA/src/cmdexec.pla
Normal file
234
PLASMA/src/cmdexec.pla
Normal file
@ -0,0 +1,234 @@
|
||||
const iobuffer = $0800
|
||||
const databuff = $0C00
|
||||
const memmap = $BF58
|
||||
const sysfile = $0280
|
||||
byte syshalt[] = "SYSTEM HALTED..."
|
||||
byte perr
|
||||
|
||||
;
|
||||
; Utility functions
|
||||
;
|
||||
; CALL PRODOS
|
||||
; SYSCALL(CMD, PARAMS)
|
||||
;
|
||||
asm prodos
|
||||
LDA ESTKL,X
|
||||
LDY ESTKH,X
|
||||
STA PARAMS
|
||||
STY PARAMS+1
|
||||
INX
|
||||
LDA ESTKL,X
|
||||
STA CMD
|
||||
STX ESP
|
||||
JSR $BF00
|
||||
CMD: !BYTE 00
|
||||
PARAMS: !WORD 0000
|
||||
LDX ESP
|
||||
STA ESTKL,X
|
||||
LDY #$00
|
||||
STY ESTKH,X
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; CALL LOADED SYSTEM PROGRAM
|
||||
;
|
||||
asm exec
|
||||
LDA #$00
|
||||
STA IFPL
|
||||
LDA #$BF
|
||||
STA IFPH
|
||||
LDX #$FE
|
||||
TXS
|
||||
LDX #ESTKSZ/2
|
||||
BIT ROMEN
|
||||
JMP $2000
|
||||
end
|
||||
;
|
||||
; EXIT
|
||||
;
|
||||
asm reboot
|
||||
BIT ROMEN
|
||||
LDA #$00
|
||||
STA $3F4 ; INVALIDATE POWER-UP BYTE
|
||||
JMP ($FFFC) ; RESET
|
||||
end
|
||||
;
|
||||
; SET MEMORY TO 0
|
||||
; MEMCLR(ADDR, SIZE)
|
||||
;
|
||||
asm memclr
|
||||
LDY #$00
|
||||
LDA ESTKL+1,X
|
||||
STA DSTL
|
||||
LDA ESTKH+1,X
|
||||
STA DSTH
|
||||
INC ESTKL,X
|
||||
INC ESTKH,X
|
||||
TYA
|
||||
SETMLP DEC ESTKL,X
|
||||
BNE +
|
||||
DEC ESTKH,X
|
||||
BEQ ++
|
||||
+ STA (DST),Y
|
||||
INY
|
||||
BNE SETMLP
|
||||
INC DSTH
|
||||
BNE SETMLP
|
||||
++ INX
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; COPY MEMORY
|
||||
; MEMCPY(DSTADDR, SRCADDR, SIZE)
|
||||
;
|
||||
asm memcpy
|
||||
LDY #$00
|
||||
LDA ESTKL,X
|
||||
BNE +
|
||||
LDA ESTKH,X
|
||||
BEQ MEMEXIT
|
||||
+ LDA ESTKL+2,X
|
||||
STA DSTL
|
||||
LDA ESTKH+2,X
|
||||
STA DSTH
|
||||
LDA ESTKL+1,X
|
||||
STA SRCL
|
||||
LDA ESTKH+1,X
|
||||
STA SRCH
|
||||
INC ESTKH,X
|
||||
CPYLP LDA (SRC),Y
|
||||
STA (DST),Y
|
||||
INC DSTL
|
||||
BNE +
|
||||
INC DSTH
|
||||
+ INC SRCL
|
||||
BNE +
|
||||
INC SRCH
|
||||
+ DEC ESTKL,X
|
||||
BNE CPYLP
|
||||
DEC ESTKH,X
|
||||
BNE CPYLP
|
||||
MEMEXIT INX
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; CHAR OUT
|
||||
; COUT(CHAR)
|
||||
;
|
||||
asm cout
|
||||
LDA ESTKL,X
|
||||
ORA #$80
|
||||
BIT ROMEN
|
||||
JSR $FDED
|
||||
BIT LCRDEN+LCBNK2
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; CHAR IN
|
||||
; RDKEY()
|
||||
;
|
||||
asm cin
|
||||
BIT ROMEN
|
||||
STX ESP
|
||||
JSR $FD0C
|
||||
LDX ESP
|
||||
DEX
|
||||
STA ESTKL,X
|
||||
LDY #$00
|
||||
STY ESTKH,X
|
||||
BIT LCRDEN+LCBNK2
|
||||
RTS
|
||||
end
|
||||
;
|
||||
; PRINT STRING
|
||||
; PRSTR(STR)
|
||||
;
|
||||
asm prstr
|
||||
LDY #$00
|
||||
LDA ESTKL,X
|
||||
STA SRCL
|
||||
LDA ESTKH,X
|
||||
STA SRCH
|
||||
BIT ROMEN
|
||||
LDA (SRC),Y
|
||||
STA ESTKL,X
|
||||
BEQ +
|
||||
- INY
|
||||
LDA (SRC),Y
|
||||
ORA #$80
|
||||
JSR $FDED
|
||||
TYA
|
||||
CMP ESTKL,X
|
||||
BNE -
|
||||
+ BIT LCRDEN+LCBNK2
|
||||
RTS
|
||||
end
|
||||
def crout
|
||||
cout($0D)
|
||||
end
|
||||
;
|
||||
; ProDOS routines
|
||||
;
|
||||
def open(path, buff)
|
||||
byte params[6]
|
||||
|
||||
params.0 = 3
|
||||
params:1 = path
|
||||
params:3 = buff
|
||||
params.5 = 0
|
||||
perr = prodos($C8, @params)
|
||||
return params.5
|
||||
end
|
||||
def close(refnum)
|
||||
byte params[2]
|
||||
|
||||
params.0 = 1
|
||||
params.1 = refnum
|
||||
perr = prodos($CC, @params)
|
||||
return perr
|
||||
end
|
||||
def read(refnum, buff, len)
|
||||
byte params[8]
|
||||
|
||||
params.0 = 4
|
||||
params.1 = refnum
|
||||
params:2 = buff
|
||||
params:4 = len
|
||||
params:6 = 0
|
||||
perr = prodos($CA, @params)
|
||||
return params:6
|
||||
end
|
||||
def resetmemfiles
|
||||
;
|
||||
; Close all files
|
||||
;
|
||||
^$BFD8 = 0
|
||||
close(0)
|
||||
;
|
||||
; Set memory bitmap
|
||||
;
|
||||
memclr(memmap, 24)
|
||||
^memmap.0 = $CF
|
||||
^memmap.23 = $01
|
||||
end
|
||||
def execsys
|
||||
byte refnum
|
||||
|
||||
if ^sysfile
|
||||
refnum = open(sysfile, iobuffer)
|
||||
if refnum
|
||||
if read(refnum, $2000, $FFFF)
|
||||
resetmemfiles()
|
||||
exec()
|
||||
fin
|
||||
fin
|
||||
fin
|
||||
end
|
||||
|
||||
resetmemfiles()
|
||||
execsys
|
||||
prstr(@syshalt)
|
||||
cin()
|
||||
reboot()
|
||||
done
|
822
PLASMA/src/codegen.c
Executable file
822
PLASMA/src/codegen.c
Executable file
@ -0,0 +1,822 @@
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "tokens.h"
|
||||
#include "lex.h"
|
||||
#include "symbols.h"
|
||||
#include "codegen.h"
|
||||
/*
|
||||
* Symbol table and fixup information.
|
||||
*/
|
||||
static int consts = 0;
|
||||
static int externs = 0;
|
||||
static int globals = 0;
|
||||
static int locals = 0;
|
||||
static int predefs = 0;
|
||||
static int defs = 0;
|
||||
static int asmdefs = 0;
|
||||
static int codetags = 0;
|
||||
static int fixups = 0;
|
||||
static char idconst_name[1024][17];
|
||||
static int idconst_value[1024];
|
||||
static char idglobal_name[1024][17];
|
||||
static int idglobal_type[1024];
|
||||
static int idglobal_tag[1024];
|
||||
static int localsize = 0;
|
||||
static char idlocal_name[128][17];
|
||||
static int idlocal_type[128];
|
||||
static int idlocal_offset[128];
|
||||
static char fixup_size[1024];
|
||||
static int fixup_type[1024];
|
||||
static int fixup_tag[1024];
|
||||
#define FIXUP_BYTE 0x00
|
||||
#define FIXUP_WORD 0x80
|
||||
int id_match(char *name, int len, char *id)
|
||||
{
|
||||
if (len == id[0])
|
||||
{
|
||||
if (len > 16) len = 16;
|
||||
while (len--)
|
||||
{
|
||||
if (name[len] != id[1 + len])
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
int idconst_lookup(char *name, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < consts; i++)
|
||||
if (id_match(name, len, &(idconst_name[i][0])))
|
||||
return (i);
|
||||
return (-1);
|
||||
}
|
||||
int idlocal_lookup(char *name, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < locals; i++)
|
||||
if (id_match(name, len, &(idlocal_name[i][0])))
|
||||
return (i);
|
||||
return (-1);
|
||||
}
|
||||
int idglobal_lookup(char *name, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < globals; i++)
|
||||
if (id_match(name, len, &(idglobal_name[i][0])))
|
||||
return (i);
|
||||
return (-1);
|
||||
}
|
||||
int idconst_add(char *name, int len, int value)
|
||||
{
|
||||
if (consts > 1024)
|
||||
{
|
||||
printf("Constant count overflow\n");
|
||||
return (0);
|
||||
}
|
||||
char c = name[len];
|
||||
name[len] = '\0';
|
||||
emit_idconst(name, value);
|
||||
name[len] = c;
|
||||
idconst_name[consts][0] = len;
|
||||
if (len > 16) len = 16;
|
||||
while (len--)
|
||||
idconst_name[consts][1 + len] = name[len];
|
||||
idconst_value[consts] = value;
|
||||
consts++;
|
||||
return (1);
|
||||
}
|
||||
int idlocal_add(char *name, int len, int type, int size)
|
||||
{
|
||||
if (localsize > 255)
|
||||
{
|
||||
printf("Local variable size overflow\n");
|
||||
return (0);
|
||||
}
|
||||
char c = name[len];
|
||||
name[len] = '\0';
|
||||
emit_idlocal(name, localsize);
|
||||
name[len] = c;
|
||||
idlocal_name[locals][0] = len;
|
||||
if (len > 16) len = 16;
|
||||
while (len--)
|
||||
idlocal_name[locals][1 + len] = name[len];
|
||||
idlocal_type[locals] = type | LOCAL_TYPE;
|
||||
idlocal_offset[locals] = localsize;
|
||||
localsize += size;
|
||||
locals++;
|
||||
return (1);
|
||||
}
|
||||
int idglobal_add(char *name, int len, int type, int size)
|
||||
{
|
||||
if (globals > 1024)
|
||||
{
|
||||
printf("Global variable count overflow\n");
|
||||
return (0);
|
||||
}
|
||||
char c = name[len];
|
||||
name[len] = '\0';
|
||||
name[len] = c;
|
||||
idglobal_name[globals][0] = len;
|
||||
if (len > 16) len = 16;
|
||||
while (len--)
|
||||
idglobal_name[globals][1 + len] = name[len];
|
||||
idglobal_type[globals] = type;
|
||||
if (!(type & EXTERN_TYPE))
|
||||
{
|
||||
emit_idglobal(globals, size, name);
|
||||
idglobal_tag[globals] = globals;
|
||||
globals++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\t\t\t\t\t; %s -> X%03d\n", &idglobal_name[globals][1], externs);
|
||||
idglobal_tag[globals++] = externs++;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
int id_add(char *name, int len, int type, int size)
|
||||
{
|
||||
return ((type & LOCAL_TYPE) ? idlocal_add(name, len, type, size) : idglobal_add(name, len, type, size));
|
||||
}
|
||||
int idfunc_add(char *name, int len, int type, int tag)
|
||||
{
|
||||
if (globals > 1024)
|
||||
{
|
||||
printf("Global variable count overflow\n");
|
||||
return (0);
|
||||
}
|
||||
idglobal_name[globals][0] = len;
|
||||
if (len > 16) len = 16;
|
||||
while (len--)
|
||||
idglobal_name[globals][1 + len] = name[len];
|
||||
idglobal_type[globals] = type;
|
||||
idglobal_tag[globals++] = tag;
|
||||
if (type & EXTERN_TYPE)
|
||||
printf("\t\t\t\t\t; %s -> X%03d\n", &idglobal_name[globals - 1][1], tag);
|
||||
return (1);
|
||||
}
|
||||
int idfunc_set(char *name, int len, int type, int tag)
|
||||
{
|
||||
int i;
|
||||
if (((i = idglobal_lookup(name, len)) >= 0) && (idglobal_type[i] & FUNC_TYPE))
|
||||
{
|
||||
idglobal_tag[i] = tag;
|
||||
idglobal_type[i] = type;
|
||||
return (type);
|
||||
}
|
||||
parse_error("Undeclared identifier");
|
||||
return (0);
|
||||
}
|
||||
void idglobal_size(int type, int size, int constsize)
|
||||
{
|
||||
if (size > constsize)
|
||||
emit_data(0, 0, 0, size - constsize);
|
||||
else if (size)
|
||||
emit_data(0, 0, 0, size);
|
||||
}
|
||||
int idlocal_size(void)
|
||||
{
|
||||
return (localsize);
|
||||
}
|
||||
void idlocal_reset(void)
|
||||
{
|
||||
locals = 0;
|
||||
localsize = 2;
|
||||
}
|
||||
int id_tag(char *name, int len)
|
||||
{
|
||||
int i;
|
||||
if ((i = idlocal_lookup(name, len)) >= 0)
|
||||
return (idlocal_offset[i]);
|
||||
if ((i = idglobal_lookup(name, len)) >= 0)
|
||||
return (idglobal_tag[i]);
|
||||
parse_error("Undeclared identifier");
|
||||
return (-1);
|
||||
}
|
||||
int id_const(char *name, int len)
|
||||
{
|
||||
int i;
|
||||
if ((i = idconst_lookup(name, len)) >= 0)
|
||||
return (idconst_value[i]);
|
||||
parse_error("Undeclared constant");
|
||||
return (0);
|
||||
}
|
||||
int id_type(char *name, int len)
|
||||
{
|
||||
int i;
|
||||
if ((i = idconst_lookup(name, len)) >= 0)
|
||||
return (CONST_TYPE);
|
||||
if ((i = idlocal_lookup(name, len)) >= 0)
|
||||
return (idlocal_type[i] | LOCAL_TYPE);
|
||||
if ((i = idglobal_lookup(name, len)) >= 0)
|
||||
return (idglobal_type[i]);
|
||||
parse_error("Undeclared identifier");
|
||||
return (0);
|
||||
}
|
||||
int tag_new(int type)
|
||||
{
|
||||
if (type & EXTERN_TYPE)
|
||||
{
|
||||
if (externs > 254)
|
||||
parse_error("External variable count overflow\n");
|
||||
return (externs++);
|
||||
}
|
||||
if (type & PREDEF_TYPE)
|
||||
return (predefs++);
|
||||
if (type & ASM_TYPE)
|
||||
return (asmdefs++);
|
||||
if (type & DEF_TYPE)
|
||||
return (defs++);
|
||||
if (type & BRANCH_TYPE)
|
||||
return (codetags++);
|
||||
return globals++;
|
||||
}
|
||||
int fixup_new(int tag, int type, int size)
|
||||
{
|
||||
fixup_tag[fixups] = tag;
|
||||
fixup_type[fixups] = type;
|
||||
fixup_size[fixups] = size;
|
||||
return (fixups++);
|
||||
}
|
||||
/*
|
||||
* Emit assembly code.
|
||||
*/
|
||||
#define BYTECODE_SEG 8
|
||||
#define INIT 16
|
||||
static int outflags = 0;
|
||||
static char *DB = ".BYTE";
|
||||
static char *DW = ".WORD";
|
||||
static char *DS = ".RES";
|
||||
static char LBL = ':';
|
||||
char *supper(char *s)
|
||||
{
|
||||
static char su[80];
|
||||
int i;
|
||||
for (i = 0; s[i]; i++)
|
||||
su[i] = toupper(s[i]);
|
||||
su[i] = '\0';
|
||||
return su;
|
||||
}
|
||||
char *tag_string(int tag, int type)
|
||||
{
|
||||
static char str[16];
|
||||
char t;
|
||||
|
||||
if (type & EXTERN_TYPE)
|
||||
t = 'X';
|
||||
else if (type & DEF_TYPE)
|
||||
t = 'C';
|
||||
else if (type & ASM_TYPE)
|
||||
t = 'A';
|
||||
else if (type & BRANCH_TYPE)
|
||||
t = 'B';
|
||||
else if (type & PREDEF_TYPE)
|
||||
t = 'P';
|
||||
else
|
||||
t = 'D';
|
||||
sprintf(str, "_%c%03d", t, tag);
|
||||
return str;
|
||||
}
|
||||
void emit_dci(char *str, int len)
|
||||
{
|
||||
if (len--)
|
||||
{
|
||||
printf("\t; DCI STRING: %s\n", supper(str));
|
||||
printf("\t%s\t$%02X", DB, toupper(*str++) | (len ? 0x80 : 0x00));
|
||||
while (len--)
|
||||
printf(",$%02X", toupper(*str++) | (len ? 0x80 : 0x00));
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
void emit_flags(int flags)
|
||||
{
|
||||
outflags = flags;
|
||||
if (outflags & ACME)
|
||||
{
|
||||
DB = "!BYTE";
|
||||
DW = "!WORD";
|
||||
DS = "!FILL";
|
||||
LBL = ' ';
|
||||
}
|
||||
}
|
||||
void emit_header(void)
|
||||
{
|
||||
if (outflags & ACME)
|
||||
printf("; ACME COMPATIBLE OUTPUT\n");
|
||||
else
|
||||
printf("; CA65 COMPATIBLE OUTPUT\n");
|
||||
if (outflags & MODULE)
|
||||
{
|
||||
printf("_SEGBEGIN%c\n", LBL);
|
||||
printf("\t%s\t_SEGEND-_SEGBEGIN\t; LENGTH OF HEADER + CODE/DATA + BYTECODE SEGMENT\n", DW);
|
||||
printf("\t%s\t$DA7E\t\t\t; MAGIC #\n", DW);
|
||||
printf("\t%s\t_SUBSEG\t\t\t; BYTECODE SUB-SEGMENT\n", DW);
|
||||
printf("\t%s\t_INIT\t\t\t; MODULE INITIALIZATION ROUTINE\n", DW);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\tJMP\t_INIT\t\t\t; MODULE INITIALIZATION ROUTINE\n");
|
||||
}
|
||||
}
|
||||
void emit_rld(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf(";\n; RE-LOCATEABLE DICTIONARY\n;\n");
|
||||
/*
|
||||
* First emit the bytecode definition entrypoint information.
|
||||
*/
|
||||
for (i = 0; i < globals; i++)
|
||||
if (!(idglobal_type[i] & EXTERN_TYPE) && (idglobal_type[i] & DEF_TYPE))
|
||||
{
|
||||
printf("\t%s\t$02\t\t\t; CODE TABLE FIXUP\n", DB);
|
||||
printf("\t%s\t_C%03d\t\t\n", DW, idglobal_tag[i]);
|
||||
printf("\t%s\t$00\n", DB);
|
||||
}
|
||||
/*
|
||||
* Now emit the fixup table.
|
||||
*/
|
||||
for (i = 0; i < fixups; i++)
|
||||
{
|
||||
if (fixup_type[i] & EXTERN_TYPE)
|
||||
{
|
||||
printf("\t%s\t$%02X\t\t\t; EXTERNAL FIXUP\n", DB, 0x11 + fixup_size[i] & 0xFF);
|
||||
printf("\t%s\t_F%03d\t\t\n", DW, i);
|
||||
printf("\t%s\t%d\t\t\t; ESD INDEX\n", DB, fixup_tag[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\t%s\t$%02X\t\t\t; INTERNAL FIXUP\n", DB, 0x01 + fixup_size[i] & 0xFF);
|
||||
printf("\t%s\t_F%03d\t\t\n", DW, i);
|
||||
printf("\t%s\t$00\n", DB);
|
||||
}
|
||||
}
|
||||
printf("\t%s\t$00\t\t\t; END OF RLD\n", DB);
|
||||
}
|
||||
void emit_esd(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf(";\n; EXTERNAL/ENTRY SYMBOL DICTIONARY\n;\n");
|
||||
for (i = 0; i < globals; i++)
|
||||
{
|
||||
if (idglobal_type[i] & EXTERN_TYPE)
|
||||
{
|
||||
emit_dci(&idglobal_name[i][1], idglobal_name[i][0]);
|
||||
printf("\t%s\t$10\t\t\t; EXTERNAL SYMBOL FLAG\n", DB);
|
||||
printf("\t%s\t%d\t\t\t; ESD INDEX\n", DW, idglobal_tag[i]);
|
||||
}
|
||||
else if (idglobal_type[i] & EXPORT_TYPE)
|
||||
{
|
||||
emit_dci(&idglobal_name[i][1], idglobal_name[i][0]);
|
||||
printf("\t%s\t$08\t\t\t; ENTRY SYMBOL FLAG\n", DB);
|
||||
printf("\t%s\t%s\t\t\n", DW, tag_string(idglobal_tag[i], idglobal_type[i]));
|
||||
}
|
||||
}
|
||||
printf("\t%s\t$00\t\t\t; END OF ESD\n", DB);
|
||||
}
|
||||
void emit_trailer(void)
|
||||
{
|
||||
if (!(outflags & BYTECODE_SEG))
|
||||
emit_bytecode_seg();
|
||||
if (!(outflags & INIT))
|
||||
printf("_INIT\t=\t0\n");
|
||||
if (outflags & MODULE)
|
||||
{
|
||||
printf("_SEGEND%c\n", LBL);
|
||||
emit_rld();
|
||||
emit_esd();
|
||||
}
|
||||
}
|
||||
void emit_moddep(char *name, int len)
|
||||
{
|
||||
if (name)
|
||||
emit_dci(name, len);
|
||||
else
|
||||
printf("\t%s\t$00\t\t\t; END OF MODULE DEPENDENCIES\n", DB);
|
||||
}
|
||||
void emit_bytecode_seg(void)
|
||||
{
|
||||
if ((outflags & MODULE) && !(outflags & BYTECODE_SEG))
|
||||
printf("_SUBSEG%c\t\t\t\t; BYTECODE STARTS\n", LBL);
|
||||
outflags |= BYTECODE_SEG;
|
||||
}
|
||||
void emit_comment(char *s)
|
||||
{
|
||||
printf("\t\t\t\t\t; %s\n", s);
|
||||
}
|
||||
void emit_asm(char *s)
|
||||
{
|
||||
printf("%s\n", s);
|
||||
}
|
||||
void emit_idlocal(char *name, int value)
|
||||
{
|
||||
printf("\t\t\t\t\t; %s -> [%d]\n", name, value);
|
||||
}
|
||||
void emit_idglobal(int tag, int size, char *name)
|
||||
{
|
||||
if (size == 0)
|
||||
printf("_D%03d%c\t\t\t\t\t; %s\n", tag, LBL, name);
|
||||
else
|
||||
printf("_D%03d%c\t%s\t%d\t\t\t; %s\n", tag, LBL, DS, size, name);
|
||||
}
|
||||
void emit_idfunc(int tag, int type, char *name)
|
||||
{
|
||||
printf("%s%c\t\t\t\t\t; %s()\n", tag_string(tag, type), LBL, name);
|
||||
}
|
||||
void emit_idconst(char *name, int value)
|
||||
{
|
||||
printf("\t\t\t\t\t; %s = %d\n", name, value);
|
||||
}
|
||||
int emit_data(int vartype, int consttype, long constval, int constsize)
|
||||
{
|
||||
int datasize, i;
|
||||
char *str;
|
||||
if (consttype == 0)
|
||||
{
|
||||
datasize = constsize;
|
||||
printf("\t%s\t$%02X\n", DS, constsize);
|
||||
}
|
||||
else if (consttype & STRING_TYPE)
|
||||
{
|
||||
datasize = constsize;
|
||||
str = (char *)constval;
|
||||
printf("\t%s\t$%02X\n", DB, --constsize);
|
||||
while (constsize-- > 0)
|
||||
{
|
||||
printf("\t%s\t$%02X", DB, *str++);
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
if (constsize-- > 0)
|
||||
printf(",$%02X", *str++);
|
||||
else
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
else if (consttype & ADDR_TYPE)
|
||||
{
|
||||
if (vartype == WORD_TYPE)
|
||||
{
|
||||
int fixup = fixup_new(constval, consttype, FIXUP_WORD);
|
||||
datasize = 2;
|
||||
if (consttype & EXTERN_TYPE)
|
||||
printf("_F%03d%c\t%s\t0\t\t\t; %s\n", fixup, LBL, DW, tag_string(constval, consttype));
|
||||
else
|
||||
printf("_F%03d%c\t%s\t%s\n", fixup, LBL, DW, tag_string(constval, consttype));
|
||||
}
|
||||
else
|
||||
{
|
||||
int fixup = fixup_new(constval, consttype, FIXUP_BYTE);
|
||||
datasize = 1;
|
||||
if (consttype & EXTERN_TYPE)
|
||||
printf("_F%03d%c\t%s\t0\t\t\t; %s\n", fixup, LBL, DB, tag_string(constval, consttype));
|
||||
else
|
||||
printf("_F%03d%c\t%s\t%s\n", fixup, LBL, DB, tag_string(constval, consttype));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vartype == WORD_TYPE)
|
||||
{
|
||||
datasize = 2;
|
||||
printf("\t%s\t$%04lX\n", DW, constval & 0xFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
datasize = 1;
|
||||
printf("\t%s\t$%02lX\n", DB, constval & 0xFF);
|
||||
}
|
||||
}
|
||||
return (datasize);
|
||||
}
|
||||
void emit_def(char *name, int is_bytecode)
|
||||
{
|
||||
if (!(outflags & MODULE))
|
||||
{
|
||||
//printf("%s%c\n", name, LBL);
|
||||
if (is_bytecode)
|
||||
printf("\tJSR $03D0\n");
|
||||
}
|
||||
}
|
||||
void emit_codetag(int tag)
|
||||
{
|
||||
printf("_B%03d%c\n", tag, LBL);
|
||||
}
|
||||
void emit_const(int cval)
|
||||
{
|
||||
if (cval == 0)
|
||||
printf("\t%s\t$00\t\t\t; ZERO\n", DB);
|
||||
else if (cval > 0 && cval < 256)
|
||||
printf("\t%s\t$2A,$%02X\t\t\t; CB\t%d\n", DB, cval, cval);
|
||||
else
|
||||
printf("\t%s\t$2C,$%02X,$%02X\t\t; CW\t%d\n", DB, cval&0xFF,(cval>>8)&0xFF, cval);
|
||||
}
|
||||
void emit_lb(void)
|
||||
{
|
||||
printf("\t%s\t$60\t\t\t; LB\n", DB);
|
||||
}
|
||||
void emit_lw(void)
|
||||
{
|
||||
printf("\t%s\t$62\t\t\t; LW\n", DB);
|
||||
}
|
||||
void emit_llb(int index)
|
||||
{
|
||||
printf("\t%s\t$64,$%02X\t\t\t; LLB\t[%d]\n", DB, index, index);
|
||||
}
|
||||
void emit_llw(int index)
|
||||
{
|
||||
printf("\t%s\t$66,$%02X\t\t\t; LLW\t[%d]\n", DB, index, index);
|
||||
}
|
||||
void emit_lab(int tag, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$68\t\t\t; LAB\t%s\n", DB, taglbl);
|
||||
printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl);
|
||||
}
|
||||
void emit_law(int tag, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$6A\t\t\t; LAW\t%s\n", DB, taglbl);
|
||||
printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl);
|
||||
}
|
||||
void emit_sb(void)
|
||||
{
|
||||
printf("\t%s\t$70\t\t\t; SB\n", DB);
|
||||
}
|
||||
void emit_sw(void)
|
||||
{
|
||||
printf("\t%s\t$72\t\t\t; SW\n", DB);
|
||||
}
|
||||
void emit_slb(int index)
|
||||
{
|
||||
printf("\t%s\t$74,$%02X\t\t\t; SLB\t[%d]\n", DB, index, index);
|
||||
}
|
||||
void emit_slw(int index)
|
||||
{
|
||||
printf("\t%s\t$76,$%02X\t\t\t; SLW\t[%d]\n", DB, index, index);
|
||||
}
|
||||
void emit_dlb(int index)
|
||||
{
|
||||
printf("\t%s\t$6C,$%02X\t\t\t; DLB\t[%d]\n", DB, index, index);
|
||||
}
|
||||
void emit_dlw(int index)
|
||||
{
|
||||
printf("\t%s\t$6E,$%02X\t\t\t; DLW\t[%d]\n", DB, index, index);
|
||||
}
|
||||
void emit_sab(int tag, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$78\t\t\t; SAB\t%s\n", DB, taglbl);
|
||||
printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl);
|
||||
}
|
||||
void emit_saw(int tag, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$7A\t\t\t; SAW\t%s\n", DB, taglbl);
|
||||
printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl);
|
||||
}
|
||||
void emit_sab_ofst(int tag, int offset, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$78\t\t\t; SAB\t%s\n", DB, taglbl);
|
||||
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
|
||||
}
|
||||
void emit_saw_ofst(int tag, int offset, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$7A\t\t\t; SAW\t%s\n", DB, taglbl);
|
||||
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
|
||||
}
|
||||
void emit_dab(int tag, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$7C\t\t\t; DAB\t%s\n", DB, taglbl);
|
||||
printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl);
|
||||
}
|
||||
void emit_daw(int tag, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$7E\t\t\t; DAW\t%s\n", DB, taglbl);
|
||||
printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl);
|
||||
}
|
||||
void emit_localaddr(int index)
|
||||
{
|
||||
printf("\t%s\t$28,$%02X\t\t\t; LLA\t[%d]\n", DB, index, index);
|
||||
}
|
||||
void emit_globaladdr(int tag, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$26\t\t\t; LA\t%s\n", DB, taglbl);
|
||||
printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl);
|
||||
}
|
||||
void emit_globaladdrofst(int tag, int ofst, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$26\t\t\t; LA\t%s+%d\n", DB, taglbl, ofst);
|
||||
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "" : taglbl, ofst);
|
||||
}
|
||||
void emit_indexbyte(void)
|
||||
{
|
||||
printf("\t%s\t$02\t\t\t; IDXB\n", DB);
|
||||
}
|
||||
void emit_indexword(void)
|
||||
{
|
||||
printf("\t%s\t$1E\t\t\t; IDXW\n", DB);
|
||||
}
|
||||
void emit_brfls(int tag)
|
||||
{
|
||||
printf("\t%s\t$4C\t\t\t; BRFLS\t_B%03d\n", DB, tag);
|
||||
printf("\t%s\t_B%03d-*\n", DW, tag);
|
||||
}
|
||||
void emit_brtru(int tag)
|
||||
{
|
||||
printf("\t%s\t$4E\t\t\t; BRTRU\t_B%03d\n", DB, tag);
|
||||
printf("\t%s\t_B%03d-*\n", DW, tag);
|
||||
}
|
||||
void emit_brnch(int tag)
|
||||
{
|
||||
printf("\t%s\t$50\t\t\t; BRNCH\t_B%03d\n", DB, tag);
|
||||
printf("\t%s\t_B%03d-*\n", DW, tag);
|
||||
}
|
||||
void emit_breq(int tag)
|
||||
{
|
||||
printf("\t%s\t$3C\t\t\t; BREQ\t_B%03d\n", DB, tag);
|
||||
printf("\t%s\t_B%03d-*\n", DW, tag);
|
||||
}
|
||||
void emit_brne(int tag)
|
||||
{
|
||||
printf("\t%s\t$3E\t\t\t; BRNE\t_B%03d\n", DB, tag);
|
||||
printf("\t%s\t_B%03d-*\n", DW, tag);
|
||||
}
|
||||
void emit_brgt(int tag)
|
||||
{
|
||||
printf("\t%s\t$38\t\t\t; BRGT\t_B%03d\n", DB, tag);
|
||||
printf("\t%s\t_B%03d-*\n", DW, tag);
|
||||
}
|
||||
void emit_brlt(int tag)
|
||||
{
|
||||
printf("\t%s\t$3A\t\t\t; BRLT\t_B%03d\n", DB, tag);
|
||||
printf("\t%s\t_B%03d-*\n", DW, tag);
|
||||
}
|
||||
void emit_call(int tag, int type)
|
||||
{
|
||||
int fixup = fixup_new(tag, type, FIXUP_WORD);
|
||||
char *taglbl = tag_string(tag, type);
|
||||
printf("\t%s\t$54\t\t\t; CALL\t%s\n", DB, taglbl);
|
||||
printf("_F%03d%c\t%s\t%s\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl);
|
||||
}
|
||||
void emit_ical(void)
|
||||
{
|
||||
printf("\t%s\t$56\t\t\t; ICAL\n", DB);
|
||||
}
|
||||
void emit_leave(int framesize)
|
||||
{
|
||||
if (framesize > 2)
|
||||
printf("\t%s\t$5A\t\t\t; LEAVE\n", DB);
|
||||
else
|
||||
printf("\t%s\t$5C\t\t\t; RET\n", DB);
|
||||
}
|
||||
void emit_ret(void)
|
||||
{
|
||||
printf("\t%s\t$5C\t\t\t; RET\n", DB);
|
||||
}
|
||||
void emit_enter(int framesize, int cparams)
|
||||
{
|
||||
if (framesize > 2)
|
||||
printf("\t%s\t$58,$%02X,$%02X\t\t; ENTER\t%d,%d\n", DB, framesize, cparams, framesize, cparams);
|
||||
}
|
||||
void emit_start(void)
|
||||
{
|
||||
printf("_INIT%c\n", LBL);
|
||||
outflags |= INIT;
|
||||
}
|
||||
void emit_dup(void)
|
||||
{
|
||||
printf("\t%s\t$32\t\t\t; DUP\n", DB);
|
||||
}
|
||||
void emit_push(void)
|
||||
{
|
||||
printf("\t%s\t$34\t\t\t; PUSH\n", DB);
|
||||
}
|
||||
void emit_pull(void)
|
||||
{
|
||||
printf("\t%s\t$36\t\t\t; PULL\n", DB);
|
||||
}
|
||||
void emit_swap(void)
|
||||
{
|
||||
printf("\t%s\t$2E\t\t\t; SWAP\n", DB);
|
||||
}
|
||||
void emit_drop(void)
|
||||
{
|
||||
printf("\t%s\t$30\t\t\t; DROP\n", DB);
|
||||
}
|
||||
int emit_unaryop(int op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case NEG_TOKEN:
|
||||
printf("\t%s\t$10\t\t\t; NEG\n", DB);
|
||||
break;
|
||||
case COMP_TOKEN:
|
||||
printf("\t%s\t$12\t\t\t; COMP\n", DB);
|
||||
break;
|
||||
case LOGIC_NOT_TOKEN:
|
||||
printf("\t%s\t$20\t\t\t; NOT\n", DB);
|
||||
break;
|
||||
case INC_TOKEN:
|
||||
printf("\t%s\t$0C\t\t\t; INCR\n", DB);
|
||||
break;
|
||||
case DEC_TOKEN:
|
||||
printf("\t%s\t$0E\t\t\t; DECR\n", DB);
|
||||
break;
|
||||
case BPTR_TOKEN:
|
||||
emit_lb();
|
||||
break;
|
||||
case WPTR_TOKEN:
|
||||
emit_lw();
|
||||
break;
|
||||
default:
|
||||
printf("emit_unaryop(%c) ???\n", op & 0x7F);
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
int emit_op(t_token op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case MUL_TOKEN:
|
||||
printf("\t%s\t$06\t\t\t; MUL\n", DB);
|
||||
break;
|
||||
case DIV_TOKEN:
|
||||
printf("\t%s\t$08\t\t\t; DIV\n", DB);
|
||||
break;
|
||||
case MOD_TOKEN:
|
||||
printf("\t%s\t$0A\t\t\t; MOD\n", DB);
|
||||
break;
|
||||
case ADD_TOKEN:
|
||||
printf("\t%s\t$02\t\t\t; ADD\n", DB);
|
||||
break;
|
||||
case SUB_TOKEN:
|
||||
printf("\t%s\t$04\t\t\t; SUB\n", DB);
|
||||
break;
|
||||
case SHL_TOKEN:
|
||||
printf("\t%s\t$1A\t\t\t; SHL\n", DB);
|
||||
break;
|
||||
case SHR_TOKEN:
|
||||
printf("\t%s\t$1C\t\t\t; SHR\n", DB);
|
||||
break;
|
||||
case AND_TOKEN:
|
||||
printf("\t%s\t$14\t\t\t; AND\n", DB);
|
||||
break;
|
||||
case OR_TOKEN:
|
||||
printf("\t%s\t$16\t\t\t; IOR\n", DB);
|
||||
break;
|
||||
case EOR_TOKEN:
|
||||
printf("\t%s\t$18\t\t\t; XOR\n", DB);
|
||||
break;
|
||||
case EQ_TOKEN:
|
||||
printf("\t%s\t$40\t\t\t; ISEQ\n", DB);
|
||||
break;
|
||||
case NE_TOKEN:
|
||||
printf("\t%s\t$42\t\t\t; ISNE\n", DB);
|
||||
break;
|
||||
case GE_TOKEN:
|
||||
printf("\t%s\t$48\t\t\t; ISGE\n", DB);
|
||||
break;
|
||||
case LT_TOKEN:
|
||||
printf("\t%s\t$46\t\t\t; ISLT\n", DB);
|
||||
break;
|
||||
case GT_TOKEN:
|
||||
printf("\t%s\t$44\t\t\t; ISGT\n", DB);
|
||||
break;
|
||||
case LE_TOKEN:
|
||||
printf("\t%s\t$4A\t\t\t; ISLE\n", DB);
|
||||
break;
|
||||
case LOGIC_OR_TOKEN:
|
||||
printf("\t%s\t$22\t\t\t; LOR\n", DB);
|
||||
break;
|
||||
case LOGIC_AND_TOKEN:
|
||||
printf("\t%s\t$24\t\t\t; LAND\n", DB);
|
||||
break;
|
||||
case COMMA_TOKEN:
|
||||
break;
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
61
PLASMA/src/codegen.h
Executable file
61
PLASMA/src/codegen.h
Executable file
@ -0,0 +1,61 @@
|
||||
#define ACME 1
|
||||
#define MODULE 2
|
||||
void emit_flags(int flags);
|
||||
void emit_header(void);
|
||||
void emit_trailer(void);
|
||||
void emit_moddep(char *name, int len);
|
||||
void emit_bytecode_seg(void);
|
||||
void emit_comment(char *s);
|
||||
void emit_asm(char *s);
|
||||
void emit_idlocal(char *name, int value);
|
||||
void emit_idglobal(int value, int size, char *name);
|
||||
void emit_idfunc(int tag, int type, char *name);
|
||||
void emit_idconst(char *name, int value);
|
||||
void emit_def(char *name, int is_bytecode);
|
||||
int emit_data(int vartype, int consttype, long constval, int constsize);
|
||||
void emit_codetag(int tag);
|
||||
void emit_const(int cval);
|
||||
void emit_lb(void);
|
||||
void emit_lw(void);
|
||||
void emit_llb(int index);
|
||||
void emit_llw(int index);
|
||||
void emit_lab(int tag, int type);
|
||||
void emit_law(int tag, int type);
|
||||
void emit_sb(void);
|
||||
void emit_sw(void);
|
||||
void emit_slb(int index);
|
||||
void emit_slw(int index);
|
||||
void emit_dlb(int index);
|
||||
void emit_dlw(int index);
|
||||
void emit_sab(int tag, int type);
|
||||
void emit_saw(int tag, int type);
|
||||
void emit_sab_ofst(int tag, int offset, int type);
|
||||
void emit_saw_ofst(int tag, int ofset, int type);
|
||||
void emit_dab(int tag, int type);
|
||||
void emit_daw(int tag, int type);
|
||||
void emit_call(int tag, int type);
|
||||
void emit_ical(void);
|
||||
void emit_localaddr(int index);
|
||||
void emit_globaladdr(int tag, int type);
|
||||
void emit_globaladdrofst(int tag, int offset, int type);
|
||||
void emit_indexbyte(void);
|
||||
void emit_indexword(void);
|
||||
int emit_unaryop(int op);
|
||||
int emit_op(t_token op);
|
||||
void emit_brtru(int tag);
|
||||
void emit_brfls(int tag);
|
||||
void emit_brgt(int tag);
|
||||
void emit_brlt(int tag);
|
||||
void emit_brne(int tag);
|
||||
void emit_brnch(int tag);
|
||||
void emit_swap(void);
|
||||
void emit_dup(void);
|
||||
void emit_push(void);
|
||||
void emit_pull(void);
|
||||
void emit_drop(void);
|
||||
void emit_leave(int framesize);
|
||||
void emit_ret(void);
|
||||
void emit_enter(int framesize, int cparams);
|
||||
void emit_start(void);
|
||||
void emit_rld(void);
|
||||
void emit_esd(void);
|
8
PLASMA/src/hello.pla
Normal file
8
PLASMA/src/hello.pla
Normal file
@ -0,0 +1,8 @@
|
||||
import STDLIB
|
||||
predef puts
|
||||
end
|
||||
|
||||
byte hellostr[] = "Hello, world.\n"
|
||||
|
||||
puts(@hellostr)
|
||||
done
|
363
PLASMA/src/lex.c
Executable file
363
PLASMA/src/lex.c
Executable file
@ -0,0 +1,363 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "tokens.h"
|
||||
#include "symbols.h"
|
||||
|
||||
char *statement, *scanpos, *tokenstr;
|
||||
t_token scantoken, prevtoken;
|
||||
int tokenlen;
|
||||
long constval;
|
||||
int lineno = 0;
|
||||
t_token keywords[] = {
|
||||
IF_TOKEN, 'I', 'F',
|
||||
ELSE_TOKEN, 'E', 'L', 'S', 'E',
|
||||
ELSEIF_TOKEN, 'E', 'L', 'S', 'I', 'F',
|
||||
FIN_TOKEN, 'F', 'I', 'N',
|
||||
WHILE_TOKEN, 'W', 'H', 'I', 'L', 'E',
|
||||
LOOP_TOKEN, 'L', 'O', 'O', 'P',
|
||||
CASE_TOKEN, 'W', 'H', 'E', 'N',
|
||||
OF_TOKEN, 'I', 'S',
|
||||
DEFAULT_TOKEN, 'O', 'T', 'H', 'E', 'R', 'W', 'I', 'S', 'E',
|
||||
ENDCASE_TOKEN, 'W', 'E', 'N', 'D',
|
||||
FOR_TOKEN, 'F', 'O', 'R',
|
||||
TO_TOKEN, 'T', 'O',
|
||||
DOWNTO_TOKEN, 'D', 'O', 'W', 'N', 'T', 'O',
|
||||
STEP_TOKEN, 'S', 'T', 'E', 'P',
|
||||
NEXT_TOKEN, 'N', 'E', 'X', 'T',
|
||||
REPEAT_TOKEN, 'R', 'E', 'P', 'E', 'A', 'T',
|
||||
UNTIL_TOKEN, 'U', 'N', 'T', 'I', 'L',
|
||||
BREAK_TOKEN, 'B', 'R', 'E', 'A', 'K',
|
||||
ASM_TOKEN, 'A', 'S', 'M',
|
||||
DEF_TOKEN, 'D', 'E', 'F',
|
||||
EXPORT_TOKEN, 'E', 'X', 'P', 'O', 'R', 'T',
|
||||
IMPORT_TOKEN, 'I', 'M', 'P', 'O', 'R', 'T',
|
||||
RETURN_TOKEN, 'R', 'E', 'T', 'U', 'R', 'N',
|
||||
END_TOKEN, 'E', 'N', 'D',
|
||||
START_TOKEN, 'S', 'T', 'A', 'R', 'T',
|
||||
EXIT_TOKEN, 'E', 'X', 'I', 'T',
|
||||
DONE_TOKEN, 'D', 'O', 'N', 'E',
|
||||
LOGIC_NOT_TOKEN, 'N', 'O', 'T',
|
||||
LOGIC_AND_TOKEN, 'A', 'N', 'D',
|
||||
LOGIC_OR_TOKEN, 'O', 'R',
|
||||
BYTE_TOKEN, 'B', 'Y', 'T', 'E',
|
||||
WORD_TOKEN, 'W', 'O', 'R', 'D',
|
||||
CONST_TOKEN, 'C', 'O', 'N', 'S', 'T',
|
||||
PREDEF_TOKEN, 'P', 'R', 'E', 'D', 'E', 'F',
|
||||
EOL_TOKEN
|
||||
};
|
||||
|
||||
void parse_error(char *errormsg)
|
||||
{
|
||||
char *error_carrot = statement;
|
||||
|
||||
fprintf(stderr, "\n%4d: %s\n ", lineno, statement);
|
||||
for (error_carrot = statement; error_carrot != tokenstr; error_carrot++)
|
||||
putc(*error_carrot == '\t' ? '\t' : ' ', stderr);
|
||||
fprintf(stderr, "^\nError: %s\n", errormsg);
|
||||
exit(1);
|
||||
}
|
||||
t_token scan(void)
|
||||
{
|
||||
prevtoken = scantoken;
|
||||
/*
|
||||
* Skip whitespace.
|
||||
*/
|
||||
while (*scanpos && (*scanpos == ' ' || *scanpos == '\t')) scanpos++;
|
||||
tokenstr = scanpos;
|
||||
/*
|
||||
* Scan for token based on first character.
|
||||
*/
|
||||
if (*scanpos == '\0' || *scanpos == '\n' || *scanpos == ';')
|
||||
scantoken = EOL_TOKEN;
|
||||
else if ((scanpos[0] >= 'a' && scanpos[0] <= 'z')
|
||||
|| (scanpos[0] >= 'A' && scanpos[0] <= 'Z')
|
||||
|| (scanpos[0] == '_'))
|
||||
{
|
||||
/*
|
||||
* ID, either variable name or reserved word.
|
||||
*/
|
||||
int keypos = 0, matchpos = 0;
|
||||
|
||||
do
|
||||
{
|
||||
scanpos++;
|
||||
}
|
||||
while ((*scanpos >= 'a' && *scanpos <= 'z')
|
||||
|| (*scanpos >= 'A' && *scanpos <= 'Z')
|
||||
|| (*scanpos == '_')
|
||||
|| (*scanpos >= '0' && *scanpos <= '9'));
|
||||
scantoken = ID_TOKEN;
|
||||
tokenlen = scanpos - tokenstr;
|
||||
/*
|
||||
* Search for matching keyword.
|
||||
*/
|
||||
while (keywords[keypos] != EOL_TOKEN)
|
||||
{
|
||||
while (keywords[keypos + 1 + matchpos] == toupper(tokenstr[matchpos]))
|
||||
matchpos++;
|
||||
if (IS_TOKEN(keywords[keypos + 1 + matchpos]) && (matchpos == tokenlen))
|
||||
{
|
||||
/*
|
||||
* A match.
|
||||
*/
|
||||
scantoken = keywords[keypos];
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Find next keyword.
|
||||
*/
|
||||
keypos += matchpos + 1;
|
||||
matchpos = 0;
|
||||
while (!IS_TOKEN(keywords[keypos])) keypos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (scanpos[0] >= '0' && scanpos[0] <= '9')
|
||||
{
|
||||
/*
|
||||
* Number constant.
|
||||
*/
|
||||
for (constval = 0; *scanpos >= '0' && *scanpos <= '9'; scanpos++)
|
||||
constval = constval * 10 + *scanpos - '0';
|
||||
scantoken = INT_TOKEN;
|
||||
}
|
||||
else if (scanpos[0] == '$')
|
||||
{
|
||||
/*
|
||||
* Hexadecimal constant.
|
||||
*/
|
||||
constval = 0;
|
||||
while (scanpos++)
|
||||
{
|
||||
if (*scanpos >= '0' && *scanpos <= '9')
|
||||
constval = constval * 16 + *scanpos - '0';
|
||||
else if (*scanpos >= 'A' && *scanpos <= 'F')
|
||||
constval = constval * 16 + *scanpos - 'A' + 10;
|
||||
else if (*scanpos >= 'a' && *scanpos <= 'f')
|
||||
constval = constval * 16 + *scanpos - 'a' + 10;
|
||||
else
|
||||
break;
|
||||
}
|
||||
scantoken = INT_TOKEN;
|
||||
}
|
||||
else if (scanpos[0] == '\'')
|
||||
{
|
||||
/*
|
||||
* Character constant.
|
||||
*/
|
||||
scantoken = CHAR_TOKEN;
|
||||
if (scanpos[1] != '\\')
|
||||
{
|
||||
constval = scanpos[1];
|
||||
if (scanpos[2] != '\'')
|
||||
{
|
||||
parse_error("Bad character constant");
|
||||
return (-1);
|
||||
}
|
||||
scanpos += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (scanpos[2])
|
||||
{
|
||||
case 'n':
|
||||
constval = 0x0D;
|
||||
break;
|
||||
case 'r':
|
||||
constval = '\r';
|
||||
break;
|
||||
case 't':
|
||||
constval = '\t';
|
||||
break;
|
||||
case '\'':
|
||||
constval = '\'';
|
||||
break;
|
||||
case '\\':
|
||||
constval = '\\';
|
||||
break;
|
||||
case '0':
|
||||
constval = '\0';
|
||||
break;
|
||||
default:
|
||||
parse_error("Bad character constant");
|
||||
return (-1);
|
||||
}
|
||||
if (scanpos[3] != '\'')
|
||||
{
|
||||
parse_error("Bad character constant");
|
||||
return (-1);
|
||||
}
|
||||
scanpos += 4;
|
||||
}
|
||||
}
|
||||
else if (scanpos[0] == '\"')
|
||||
{
|
||||
char *scanshift;
|
||||
/*
|
||||
* String constant.
|
||||
*/
|
||||
scantoken = STRING_TOKEN;
|
||||
constval = (long)++scanpos;
|
||||
while (*scanpos && *scanpos != '\"')
|
||||
{
|
||||
if (*scanpos == '\\')
|
||||
{
|
||||
switch (scanpos[1])
|
||||
{
|
||||
case 'n':
|
||||
*scanpos = 0x0D;
|
||||
break;
|
||||
case 'r':
|
||||
*scanpos = '\r';
|
||||
break;
|
||||
case 't':
|
||||
*scanpos = '\t';
|
||||
break;
|
||||
case '\'':
|
||||
*scanpos = '\'';
|
||||
break;
|
||||
case '\\':
|
||||
*scanpos = '\\';
|
||||
break;
|
||||
case '0':
|
||||
*scanpos = '\0';
|
||||
break;
|
||||
default:
|
||||
parse_error("Bad string constant");
|
||||
return (-1);
|
||||
}
|
||||
for (scanshift = scanpos + 1; *scanshift; scanshift++)
|
||||
scanshift[0] = scanshift[1];
|
||||
}
|
||||
else
|
||||
scanpos++;
|
||||
}
|
||||
if (!*scanpos++)
|
||||
{
|
||||
parse_error("Unterminated string");
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Potential two and three character tokens.
|
||||
*/
|
||||
switch (scanpos[0])
|
||||
{
|
||||
case '>':
|
||||
if (scanpos[1] == '>')
|
||||
{
|
||||
scantoken = SHR_TOKEN;
|
||||
scanpos += 2;
|
||||
}
|
||||
else if (scanpos[1] == '=')
|
||||
{
|
||||
scantoken = GE_TOKEN;
|
||||
scanpos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
scantoken = GT_TOKEN;
|
||||
scanpos++;
|
||||
}
|
||||
break;
|
||||
case '<':
|
||||
if (scanpos[1] == '<')
|
||||
{
|
||||
scantoken = SHL_TOKEN;
|
||||
scanpos += 2;
|
||||
}
|
||||
else if (scanpos[1] == '=')
|
||||
{
|
||||
scantoken = LE_TOKEN;
|
||||
scanpos += 2;
|
||||
}
|
||||
else if (scanpos[1] == '>')
|
||||
{
|
||||
scantoken = NE_TOKEN;
|
||||
scanpos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
scantoken = LT_TOKEN;
|
||||
scanpos++;
|
||||
}
|
||||
break;
|
||||
case '=':
|
||||
if (scanpos[1] == '=')
|
||||
{
|
||||
scantoken = EQ_TOKEN;
|
||||
scanpos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
scantoken = SET_TOKEN;
|
||||
scanpos++;
|
||||
}
|
||||
break;
|
||||
case '+':
|
||||
if (scanpos[1] == '+')
|
||||
{
|
||||
scantoken = INC_TOKEN;
|
||||
scanpos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
scantoken = ADD_TOKEN;
|
||||
scanpos++;
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
if (scanpos[1] == '-')
|
||||
{
|
||||
scantoken = DEC_TOKEN;
|
||||
scanpos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
scantoken = SUB_TOKEN;
|
||||
scanpos++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Simple single character tokens.
|
||||
*/
|
||||
scantoken = TOKEN(*scanpos++);
|
||||
}
|
||||
}
|
||||
tokenlen = scanpos - tokenstr;
|
||||
return (scantoken);
|
||||
}
|
||||
void scan_rewind(char *backptr)
|
||||
{
|
||||
scanpos = backptr;
|
||||
}
|
||||
int scan_lookahead(void)
|
||||
{
|
||||
char *backpos = scanpos;
|
||||
char *backstr = tokenstr;
|
||||
int prevtoken = scantoken;
|
||||
int prevlen = tokenlen;
|
||||
int look = scan();
|
||||
scanpos = backpos;
|
||||
tokenstr = backstr;
|
||||
scantoken = prevtoken;
|
||||
tokenlen = prevlen;
|
||||
return (look);
|
||||
}
|
||||
char inputline[512];
|
||||
int next_line(void)
|
||||
{
|
||||
gets(inputline);
|
||||
lineno++;
|
||||
statement = inputline;
|
||||
scanpos = inputline;
|
||||
scantoken = EOL_TOKEN;
|
||||
scan();
|
||||
printf("; %03d: %s\n", lineno, inputline);
|
||||
return (1);
|
||||
}
|
10
PLASMA/src/lex.h
Executable file
10
PLASMA/src/lex.h
Executable file
@ -0,0 +1,10 @@
|
||||
extern char *statement, *scanpos, *tokenstr;
|
||||
extern t_token scantoken, prevtoken;
|
||||
extern int tokenlen;
|
||||
extern long constval;
|
||||
extern char inputline[];
|
||||
void parse_error(char *errormsg);
|
||||
int next_line(void);
|
||||
void scan_rewind(char *backptr);
|
||||
int scan_lookahead(void);
|
||||
t_token scan(void);
|
58
PLASMA/src/makefile
Executable file
58
PLASMA/src/makefile
Executable file
@ -0,0 +1,58 @@
|
||||
.SUFFIXES =
|
||||
AFLAGS = -o $@
|
||||
LFLAGS = -C default.cfg
|
||||
PLVM = plvm
|
||||
PLVM02 = PLVM02.SYS
|
||||
CMD = CMD.SYS
|
||||
PLASM = plasm
|
||||
INCS = tokens.h symbols.h lex.h parse.h codegen.h
|
||||
OBJS = plasm.c parse.o lex.o codegen.o
|
||||
#
|
||||
# Image filetypes for Virtual ][
|
||||
#
|
||||
PLATYPE = .\$$ED
|
||||
BINTYPE = .BIN
|
||||
SYSTYPE = .SYS
|
||||
TXTTYPE = .TXT
|
||||
#
|
||||
# Image filetypes for CiderPress
|
||||
#
|
||||
#PLATYPE = \#ed0000
|
||||
#BINTYPE = \#060000
|
||||
#SYSTYPE = \#ff0000
|
||||
#TXTTYPE = \#040000
|
||||
|
||||
all: $(PLASM) $(PLVM) $(PLVM02) $(CMD) TESTLIB
|
||||
|
||||
clean:
|
||||
-rm *.o *~ *.a *.SYM *.SYS *.BIN TESTLIB $(PLASM) $(PLVM)
|
||||
|
||||
$(PLASM): $(OBJS) $(INCS)
|
||||
cc $(OBJS) -o $(PLASM)
|
||||
|
||||
$(PLVM): plvm.c
|
||||
cc plvm.c -o $(PLVM)
|
||||
|
||||
cmdexec.a: cmdexec.pla $(PLASM)
|
||||
./$(PLASM) -A < cmdexec.pla > cmdexec.a
|
||||
|
||||
$(PLVM02): plvm02.s cmdexec.a
|
||||
acme -o $(PLVM02) -l PLVM02.SYM plvm02.s
|
||||
|
||||
$(CMD): cmd.pla $(PLVM) $(PLASM)
|
||||
./$(PLASM) -A < cmd.pla > cmd.a
|
||||
acme --setpc 8192 -o $(CMD) cmd.a
|
||||
|
||||
TESTLIB: testlib.pla $(PLVM) $(PLASM)
|
||||
./$(PLASM) -AM < testlib.pla > testlib.a
|
||||
acme --setpc 4096 -o TESTLIB testlib.a
|
||||
|
||||
test: test.pla TESTLIB $(PLVM) $(PLASM)
|
||||
./$(PLASM) -AM < test.pla > test.a
|
||||
acme --setpc 4096 -o TEST.BIN test.a
|
||||
./$(PLVM) TEST.BIN MAIN
|
||||
|
||||
debug: test.pla TESTLIB $(PLVM) $(PLASM)
|
||||
./$(PLASM) -AM < test.pla > test.a
|
||||
acme --setpc 4096 -o TEST.BIN test.a
|
||||
./$(PLVM) -s TEST.BIN MAIN
|
1327
PLASMA/src/parse.c
Executable file
1327
PLASMA/src/parse.c
Executable file
File diff suppressed because it is too large
Load Diff
1
PLASMA/src/parse.h
Executable file
1
PLASMA/src/parse.h
Executable file
@ -0,0 +1 @@
|
||||
int parse_module(void);
|
35
PLASMA/src/plasm.c
Executable file
35
PLASMA/src/plasm.c
Executable file
@ -0,0 +1,35 @@
|
||||
#include <stdio.h>
|
||||
#include "tokens.h"
|
||||
#include "lex.h"
|
||||
#include "codegen.h"
|
||||
#include "parse.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int j, i, flags = 0;
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (argv[i][0] == '-')
|
||||
{
|
||||
j = 1;
|
||||
while (argv[i][j])
|
||||
{
|
||||
switch(argv[i][j++])
|
||||
{
|
||||
case 'A':
|
||||
flags |= ACME;
|
||||
break;
|
||||
case 'M':
|
||||
flags |= MODULE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
emit_flags(flags);
|
||||
if (parse_module())
|
||||
{
|
||||
fprintf(stderr, "Compilation complete.\n");
|
||||
}
|
||||
return (0);
|
||||
}
|
941
PLASMA/src/plvm.c
Executable file
941
PLASMA/src/plvm.c
Executable file
@ -0,0 +1,941 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef unsigned char code;
|
||||
typedef unsigned char byte;
|
||||
typedef signed short word;
|
||||
typedef unsigned short uword;
|
||||
typedef unsigned short address;
|
||||
/*
|
||||
* Debug
|
||||
*/
|
||||
int show_state = 0;
|
||||
/*
|
||||
* Bytecode memory
|
||||
*/
|
||||
#define BYTE_PTR(bp) ((byte)((bp)[0]))
|
||||
#define WORD_PTR(bp) ((word)((bp)[0] | ((bp)[1] << 8)))
|
||||
#define UWORD_PTR(bp) ((uword)((bp)[0] | ((bp)[1] << 8)))
|
||||
#define TO_UWORD(w) ((uword)((w)))
|
||||
#define MOD_ADDR 0x1000
|
||||
#define DEF_CALL 0x0800
|
||||
#define DEF_CALLSZ 0x0800
|
||||
#define DEF_ENTRYSZ 6
|
||||
#define MEM_SIZE 65536
|
||||
byte mem_data[MEM_SIZE], mem_code[MEM_SIZE];
|
||||
byte *mem_bank[2] = {mem_data, mem_code};
|
||||
uword sp = 0x01FE, fp = 0xBEFF, heap = 0x6000, xheap = 0x0800, deftbl = DEF_CALL, lastdef = DEF_CALL;
|
||||
|
||||
#define EVAL_STACKSZ 16
|
||||
#define PUSH(v) (*(--esp))=(v)
|
||||
#define POP ((word)(*(esp++)))
|
||||
#define UPOP ((uword)(*(esp++)))
|
||||
#define TOS (esp[0])
|
||||
word eval_stack[EVAL_STACKSZ];
|
||||
word *esp = eval_stack + EVAL_STACKSZ;
|
||||
|
||||
#define SYMTBLSZ 1024
|
||||
#define SYMSZ 16
|
||||
#define MODTBLSZ 128
|
||||
#define MODSZ 16
|
||||
#define MODLSTSZ 32
|
||||
byte symtbl[SYMTBLSZ];
|
||||
byte *lastsym = symtbl;
|
||||
byte modtbl[MODTBLSZ];
|
||||
byte *lastmod = modtbl;
|
||||
/*
|
||||
* Predef.
|
||||
*/
|
||||
void interp(code *ip);
|
||||
/*
|
||||
* Utility routines.
|
||||
*
|
||||
* A DCI string is one that has the high bit set for every character except the last.
|
||||
* More efficient than C or Pascal strings.
|
||||
*/
|
||||
int dcitos(byte *dci, char *str)
|
||||
{
|
||||
int len = 0;
|
||||
do
|
||||
str[len] = *dci & 0x7F;
|
||||
while ((len++ < 15) && (*dci++ & 0x80));
|
||||
str[len] = 0;
|
||||
return len;
|
||||
}
|
||||
int stodci(char *str, byte *dci)
|
||||
{
|
||||
int len = 0;
|
||||
do
|
||||
dci[len] = toupper(*str) | 0x80;
|
||||
while (*str++ && (len++ < 15));
|
||||
dci[len - 1] &= 0x7F;
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Heap routines.
|
||||
*/
|
||||
uword avail_heap(void)
|
||||
{
|
||||
return fp - heap;
|
||||
}
|
||||
uword alloc_heap(int size)
|
||||
{
|
||||
uword addr = heap;
|
||||
heap += size;
|
||||
if (heap >= fp)
|
||||
{
|
||||
printf("Error: heap/frame collision.\n");
|
||||
exit (1);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
uword free_heap(int size)
|
||||
{
|
||||
heap -= size;
|
||||
return fp - heap;
|
||||
}
|
||||
uword mark_heap(void)
|
||||
{
|
||||
return heap;
|
||||
}
|
||||
int release_heap(uword newheap)
|
||||
{
|
||||
heap = newheap;
|
||||
return fp - heap;
|
||||
}
|
||||
uword avail_xheap(void)
|
||||
{
|
||||
return 0xC000 - xheap;
|
||||
}
|
||||
uword alloc_xheap(int size)
|
||||
{
|
||||
uword addr = xheap;
|
||||
xheap += size;
|
||||
if (xheap >= 0xC000)
|
||||
{
|
||||
printf("Error: xheap extinguished.\n");
|
||||
exit (1);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
uword free_xheap(int size)
|
||||
{
|
||||
xheap -= size;
|
||||
return 0xC000 - heap;
|
||||
}
|
||||
uword mark_xheap(void)
|
||||
{
|
||||
return xheap;
|
||||
}
|
||||
int release_xheap(uword newxheap)
|
||||
{
|
||||
xheap = newxheap;
|
||||
return 0xC000 - xheap;
|
||||
}
|
||||
/*
|
||||
* Copy from data mem to code mem.
|
||||
*/
|
||||
void xmemcpy(uword src, uword dst, uword size)
|
||||
{
|
||||
while (size--)
|
||||
mem_code[dst + size] = mem_data[src + size];
|
||||
}
|
||||
/*
|
||||
* Copy from code mem to data mem.
|
||||
*/
|
||||
void memxcpy(uword src, uword dst, uword size)
|
||||
{
|
||||
while (size--)
|
||||
mem_data[dst + size] = mem_code[src + size];
|
||||
}
|
||||
/*
|
||||
* DCI table routines,
|
||||
*/
|
||||
void dump_tbl(byte *tbl)
|
||||
{
|
||||
int len;
|
||||
byte *entbl;
|
||||
while (*tbl)
|
||||
{
|
||||
len = 0;
|
||||
while (*tbl & 0x80)
|
||||
{
|
||||
putchar(*tbl++ & 0x7F);
|
||||
len++;
|
||||
}
|
||||
putchar(*tbl++);
|
||||
putchar(':');
|
||||
while (len++ < 15)
|
||||
putchar(' ');
|
||||
printf("$%04X\n", tbl[0] | (tbl[1] << 8));
|
||||
tbl += 2;
|
||||
}
|
||||
}
|
||||
uword lookup_tbl(byte *dci, byte *tbl)
|
||||
{
|
||||
char str[20];
|
||||
byte *match, *entry = tbl;
|
||||
while (*entry)
|
||||
{
|
||||
match = dci;
|
||||
while (*entry == *match)
|
||||
{
|
||||
if ((*entry & 0x80) == 0)
|
||||
return entry[1] | (entry[2] << 8);
|
||||
entry++;
|
||||
match++;
|
||||
}
|
||||
while (*entry++ & 0x80);
|
||||
entry += 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int add_tbl(byte *dci, int val, byte **last)
|
||||
{
|
||||
while (*dci & 0x80)
|
||||
*(*last)++ = *dci++;
|
||||
*(*last)++ = *dci++;
|
||||
*(*last)++ = val;
|
||||
*(*last)++ = val >> 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Symbol table routines.
|
||||
*/
|
||||
void dump_sym(void)
|
||||
{
|
||||
printf("\nSystem Symbol Table:\n");
|
||||
dump_tbl(symtbl);
|
||||
}
|
||||
uword lookup_sym(byte *sym)
|
||||
{
|
||||
return lookup_tbl(sym, symtbl);
|
||||
}
|
||||
int add_sym(byte *sym, int addr)
|
||||
{
|
||||
return add_tbl(sym, addr, &lastsym);
|
||||
}
|
||||
|
||||
/*
|
||||
* Module routines.
|
||||
*/
|
||||
void dump_mod(void)
|
||||
{
|
||||
printf("\nSystem Module Table:\n");
|
||||
dump_tbl(modtbl);
|
||||
}
|
||||
uword lookup_mod(byte *mod)
|
||||
{
|
||||
return lookup_tbl(mod, modtbl);
|
||||
}
|
||||
int add_mod(byte *mod, int addr)
|
||||
{
|
||||
return add_tbl(mod, addr, &lastmod);
|
||||
}
|
||||
defcall_add(int bank, int addr)
|
||||
{
|
||||
mem_data[lastdef] = bank ? 2 : 1;
|
||||
mem_data[lastdef + 1] = addr;
|
||||
mem_data[lastdef + 2] = addr >> 8;
|
||||
return lastdef++;
|
||||
}
|
||||
int def_lookup(byte *cdd, int defaddr)
|
||||
{
|
||||
int i, calldef = 0;
|
||||
for (i = 0; cdd[i * 4] == 0x02; i++)
|
||||
{
|
||||
if ((cdd[i * 4 + 1] | (cdd[i * 4 + 2] << 8)) == defaddr)
|
||||
{
|
||||
calldef = cdd + i * 4 - mem_data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return calldef;
|
||||
}
|
||||
int extern_lookup(byte *esd, int index)
|
||||
{
|
||||
byte *sym;
|
||||
char string[32];
|
||||
while (*esd)
|
||||
{
|
||||
sym = esd;
|
||||
esd += dcitos(esd, string);
|
||||
if ((esd[0] & 0x10) && (esd[1] == index))
|
||||
return lookup_sym(sym);
|
||||
esd += 3;
|
||||
}
|
||||
printf("\nError: extern index %d not found in ESD.\n", index);
|
||||
return 0;
|
||||
}
|
||||
int load_mod(byte *mod)
|
||||
{
|
||||
unsigned int len, size, end, magic, bytecode, fixup, addr, init = 0, modaddr = mark_heap();
|
||||
byte *moddep, *rld, *esd, *cdd, *sym;
|
||||
byte header[128];
|
||||
char filename[32], string[17];
|
||||
|
||||
dcitos(mod, filename);
|
||||
printf("Load module %s\n", filename);
|
||||
int fd = open(filename, O_RDONLY, 0);
|
||||
if ((fd > 0) && (len = read(fd, header, 128)) > 0)
|
||||
{
|
||||
magic = header[2] | (header[3] << 8);
|
||||
if (magic == 0xDA7E)
|
||||
{
|
||||
/*
|
||||
* This is a relocatable bytecode module.
|
||||
*/
|
||||
bytecode = header[4] | (header[5] << 8);
|
||||
init = header[6] | (header[7] << 8);
|
||||
moddep = header + 8;
|
||||
if (*moddep)
|
||||
{
|
||||
/*
|
||||
* Load module dependencies.
|
||||
*/
|
||||
close(fd);
|
||||
while (*moddep)
|
||||
{
|
||||
if (lookup_mod(moddep) == 0)
|
||||
load_mod(moddep);
|
||||
moddep += dcitos(moddep, string);
|
||||
}
|
||||
modaddr = mark_heap();
|
||||
fd = open(filename, O_RDONLY, 0);
|
||||
len = read(fd, mem_data + modaddr, 128);
|
||||
}
|
||||
else
|
||||
memcpy(mem_data + modaddr, header, len);
|
||||
}
|
||||
addr = modaddr + len;
|
||||
while ((len = read(fd, mem_data + addr, 4096)) > 0)
|
||||
addr += len;
|
||||
close(fd);
|
||||
size = addr - modaddr;
|
||||
len = mem_data[modaddr + 0] | (mem_data[modaddr + 1] << 8);
|
||||
end = modaddr + len;
|
||||
rld = mem_data + modaddr + len; // Re-Locatable Directory
|
||||
esd = rld; // Extern+Entry Symbol Directory
|
||||
bytecode += modaddr - MOD_ADDR;
|
||||
while (*esd != 0x00) // Scan to end of RLD
|
||||
esd += 4;
|
||||
esd++;
|
||||
cdd = rld;
|
||||
if (show_state)
|
||||
{
|
||||
/*
|
||||
* Dump different parts of module.
|
||||
*/
|
||||
printf("Module size: %d\n", size);
|
||||
printf("Module code+data size: %d\n", len);
|
||||
printf("Module magic: $%04X\n", magic);
|
||||
printf("Module bytecode: $%04X\n", bytecode);
|
||||
printf("Module init: $%04X\n", init);
|
||||
}
|
||||
/*
|
||||
* Print out the Re-Location Dictionary.
|
||||
*/
|
||||
if (show_state)
|
||||
printf("\nRe-Location Dictionary:\n");
|
||||
while (*rld)
|
||||
{
|
||||
if (rld[0] == 0x02)
|
||||
{
|
||||
if (show_state) printf("\tDEF CODE");
|
||||
addr = rld[1] | (rld[2] << 8);
|
||||
addr += modaddr - MOD_ADDR;
|
||||
rld[1] = addr;
|
||||
rld[2] = addr >> 8;
|
||||
end = rld - mem_data + 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = rld[1] | (rld[2] << 8);
|
||||
addr += modaddr - MOD_ADDR;
|
||||
if (rld[0] & 0x80)
|
||||
fixup = mem_data[addr] | (mem_data[addr + 1] << 8);
|
||||
else
|
||||
fixup = mem_data[addr];
|
||||
if (rld[0] & 0x10)
|
||||
{
|
||||
if (show_state) printf("\tEXTERN[$%02X] ", rld[3]);
|
||||
fixup += extern_lookup(esd, rld[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (show_state) printf("\tINTERN ");
|
||||
fixup += modaddr - MOD_ADDR;
|
||||
if (fixup >= bytecode)
|
||||
/*
|
||||
* Replace with call def dictionary.
|
||||
*/
|
||||
fixup = def_lookup(cdd, fixup);
|
||||
}
|
||||
if (rld[0] & 0x80)
|
||||
{
|
||||
if (show_state) printf("WORD");
|
||||
mem_data[addr] = fixup;
|
||||
mem_data[addr + 1] = fixup >> 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (show_state) printf("BYTE");
|
||||
mem_data[addr] = fixup;
|
||||
}
|
||||
|
||||
}
|
||||
if (show_state) printf("@$%04X\n", addr);
|
||||
rld += 4;
|
||||
}
|
||||
if (show_state) printf("\nExternal/Entry Symbol Directory:\n");
|
||||
while (*esd)
|
||||
{
|
||||
sym = esd;
|
||||
esd += dcitos(esd, string);
|
||||
if (esd[0] & 0x10)
|
||||
{
|
||||
if (show_state) printf("\tIMPORT %s[$%02X]\n", string, esd[1]);
|
||||
}
|
||||
else if (esd[0] & 0x08)
|
||||
{
|
||||
addr = esd[1] | (esd[2] << 8);
|
||||
addr += modaddr - MOD_ADDR;
|
||||
if (show_state) printf("\tEXPORT %s@$%04X\n", string, addr);
|
||||
if (addr >= bytecode)
|
||||
addr = def_lookup(cdd, addr);
|
||||
add_sym(sym, addr);
|
||||
}
|
||||
esd += 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error: Unable to load module %s\n", filename);
|
||||
exit (1);
|
||||
}
|
||||
/*
|
||||
* Reserve heap space for relocated module.
|
||||
*/
|
||||
alloc_heap(end - modaddr);
|
||||
/*
|
||||
* Call init routine.
|
||||
*/
|
||||
if (init)
|
||||
{
|
||||
interp(mem_data + init + modaddr - MOD_ADDR);
|
||||
POP;
|
||||
}
|
||||
return (fd > 0);
|
||||
}
|
||||
void interp(code *ip);
|
||||
|
||||
void call(uword pc)
|
||||
{
|
||||
unsigned int i, s;
|
||||
char c, sz[64];
|
||||
|
||||
switch (mem_data[pc++])
|
||||
{
|
||||
case 0: // NULL call
|
||||
printf("NULL call code\n");
|
||||
break;
|
||||
case 1: // BYTECODE in mem_code
|
||||
interp(mem_code + (mem_data[pc] + (mem_data[pc + 1] << 8)));
|
||||
break;
|
||||
case 2: // BYTECODE in mem_data
|
||||
interp(mem_data + (mem_data[pc] + (mem_data[pc + 1] << 8)));
|
||||
break;
|
||||
case 3: // LIBRARY STDLIB::VIEWPORT
|
||||
printf("Set Window %d, %d, %d, %d/n", POP, POP, POP, POP);
|
||||
PUSH(0);
|
||||
break;
|
||||
case 4: // LIBRARY STDLIB::PUTC
|
||||
c = POP;
|
||||
if (c == 0x0D)
|
||||
c = '\n';
|
||||
putchar(c);
|
||||
PUSH(0);
|
||||
break;
|
||||
case 5: // LIBRARY STDLIB::PUTS
|
||||
s = POP;
|
||||
i = mem_data[s++];
|
||||
PUSH(i);
|
||||
while (i--)
|
||||
{
|
||||
c = mem_data[s++];
|
||||
if (c == 0x0D)
|
||||
c = '\n';
|
||||
putchar(c);
|
||||
}
|
||||
break;
|
||||
case 6: // LIBRARY STDLIB::PUTSZ
|
||||
s = POP;
|
||||
while (c = mem_data[s++])
|
||||
{
|
||||
if (c == 0x0D)
|
||||
c = '\n';
|
||||
putchar(c);
|
||||
}
|
||||
PUSH(0);
|
||||
break;
|
||||
case 7: // LIBRARY STDLIB::GETC
|
||||
PUSH(getchar());
|
||||
break;
|
||||
case 8: // LIBRARY STDLIB::GETS
|
||||
gets(sz);
|
||||
i = 0;
|
||||
while (sz[i])
|
||||
mem_data[0x200 + i++] = sz[i];
|
||||
mem_data[0x200 + i] = 0;
|
||||
mem_data[0x1FF] = i;
|
||||
PUSH(i);
|
||||
break;
|
||||
case 9: // LIBRARY STDLIB::CLS
|
||||
puts("\033[2J");
|
||||
fflush(stdout);
|
||||
PUSH(0);
|
||||
PUSH(0);
|
||||
case 10: // LIBRARY STDLIB::GOTOXY
|
||||
s = POP + 1;
|
||||
i = POP + 1;
|
||||
printf("\033[%d;%df", s, i);
|
||||
fflush(stdout);
|
||||
PUSH(0);
|
||||
break;
|
||||
default:
|
||||
printf("Bad call code\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OPCODE TABLE
|
||||
*
|
||||
OPTBL: DW ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E
|
||||
DW NEG,COMP,AND,IOR,XOR,SHL,SHR,IDXW ; 10 12 14 16 18 1A 1C 1E
|
||||
DW NOT,LOR,LAND,LA,LLA,CB,CW,SWAP ; 20 22 24 26 28 2A 2C 2E
|
||||
DW DROP,DUP,PUSH,PULL,BRGT,BRLT,BREQ,BRNE ; 30 32 34 36 38 3A 3C 3E
|
||||
DW ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,BRFLS,BRTRU ; 40 42 44 46 48 4A 4C 4E
|
||||
DW BRNCH,IBRNCH,CALL,ICAL,ENTER,LEAVE,RET,??? ; 50 52 54 56 58 5A 5C 5E
|
||||
DW LB,LW,LLB,LLW,LAB,LAW,DLB,DLW ; 60 62 64 66 68 6A 6C 6E
|
||||
DW SB,SW,SLB,SLW,SAB,SAW,DAB,DAW ; 70 72 74 76 78 7A 7C 7E
|
||||
*/
|
||||
void interp(code *ip)
|
||||
{
|
||||
int val, ea, frmsz, parmcnt;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (show_state)
|
||||
{
|
||||
char cmdline[16];
|
||||
word *dsp = &eval_stack[EVAL_STACKSZ - 1];
|
||||
printf("$%04X: $%02X [ ", ip - mem_data, *ip);
|
||||
while (dsp >= esp)
|
||||
printf("$%04X ", (*dsp--) & 0xFFFF);
|
||||
printf("]\n");
|
||||
gets(cmdline);
|
||||
}
|
||||
switch (*ip++)
|
||||
{
|
||||
/*
|
||||
* 0x00-0x0F
|
||||
*/
|
||||
case 0x00: // ZERO : TOS = 0
|
||||
PUSH(0);
|
||||
break;
|
||||
case 0x02: // ADD : TOS = TOS + TOS-1
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(ea + val);
|
||||
break;
|
||||
case 0x04: // SUB : TOS = TOS-1 - TOS
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(ea - val);
|
||||
break;
|
||||
case 0x06: // MUL : TOS = TOS * TOS-1
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(ea * val);
|
||||
break;
|
||||
case 0x08: // DIV : TOS = TOS-1 / TOS
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(ea / val);
|
||||
break;
|
||||
case 0x0A: // MOD : TOS = TOS-1 % TOS
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(ea % val);
|
||||
break;
|
||||
case 0x0C: // INCR : TOS = TOS + 1
|
||||
TOS++;;
|
||||
break;
|
||||
case 0x0E: // DECR : TOS = TOS - 1
|
||||
TOS--;
|
||||
break;
|
||||
/*
|
||||
* 0x10-0x1F
|
||||
*/
|
||||
case 0x10: // NEG : TOS = -TOS
|
||||
TOS = -TOS;
|
||||
break;
|
||||
case 0x12: // COMP : TOS = ~TOS
|
||||
TOS = ~TOS;
|
||||
break;
|
||||
case 0x14: // AND : TOS = TOS & TOS-1
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(ea & val);
|
||||
break;
|
||||
case 0x16: // IOR : TOS = TOS ! TOS-1
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(ea | val);
|
||||
break;
|
||||
case 0x18: // XOR : TOS = TOS ^ TOS-1
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(ea ^ val);
|
||||
break;
|
||||
case 0x1A: // SHL : TOS = TOS-1 << TOS
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(ea << val);
|
||||
break;
|
||||
case 0x1C: // SHR : TOS = TOS-1 >> TOS
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(ea >> val);
|
||||
break;
|
||||
case 0x1E: // IDXW : TOS = TOS * 2
|
||||
TOS *= 2;
|
||||
break;
|
||||
/*
|
||||
* 0x20-0x2F
|
||||
*/
|
||||
case 0x20: // NOT : TOS = !TOS
|
||||
TOS = !TOS;
|
||||
break;
|
||||
case 0x22: // LOR : TOS = TOS || TOS-1
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(ea || val);
|
||||
break;
|
||||
case 0x24: // LAND : TOS = TOS && TOS-1
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(ea && val);
|
||||
break;
|
||||
case 0x26: // LA : TOS = @VAR ; equivalent to CW ADDRESSOF(VAR)
|
||||
PUSH(WORD_PTR(ip));
|
||||
ip += 2;
|
||||
break;
|
||||
case 0x28: // LLA : TOS = @LOCALVAR ; equivalent to CW FRAMEPTR+OFFSET(LOCALVAR)
|
||||
PUSH(fp + BYTE_PTR(ip));
|
||||
ip++;
|
||||
break;
|
||||
case 0x2A: // CB : TOS = CONSTANTBYTE (IP)
|
||||
PUSH(BYTE_PTR(ip));
|
||||
ip++;
|
||||
break;
|
||||
case 0x2C: // CW : TOS = CONSTANTWORD (IP)
|
||||
PUSH(WORD_PTR(ip));
|
||||
ip += 2;
|
||||
break;
|
||||
case 0x2E: // SWAP : TOS = TOS-1, TOS-1 = TOS
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH(val);
|
||||
PUSH(ea);
|
||||
break;
|
||||
/*
|
||||
* 0x30-0x3F
|
||||
*/
|
||||
case 0x30: // DROP : TOS =
|
||||
POP;
|
||||
break;
|
||||
case 0x32: // DUP : TOS = TOS
|
||||
val = TOS;
|
||||
PUSH(val);
|
||||
break;
|
||||
case 0x34: // PUSH : TOSP = TOS
|
||||
val = POP;
|
||||
mem_data[sp--] = val >> 8;
|
||||
mem_data[sp--] = val;
|
||||
break;
|
||||
case 0x36: // PULL : TOS = TOSP
|
||||
PUSH(mem_data[sp] | (mem_data[sp + 1] << 8));
|
||||
sp += 2;
|
||||
break;
|
||||
case 0x38: // BRGT : TOS-1 > TOS ? IP += (IP)
|
||||
val = POP;
|
||||
if (TOS > val)
|
||||
ip += WORD_PTR(ip);
|
||||
else
|
||||
ip += 2;
|
||||
break;
|
||||
case 0x3A: // BRLT : TOS-1 < TOS ? IP += (IP)
|
||||
val = POP;
|
||||
if (TOS < val)
|
||||
ip += WORD_PTR(ip);
|
||||
else
|
||||
ip += 2;
|
||||
break;
|
||||
case 0x3C: // BREQ : TOS == TOS-1 ? IP += (IP)
|
||||
val = POP;
|
||||
if (TOS == val)
|
||||
ip += WORD_PTR(ip);
|
||||
else
|
||||
ip += 2;
|
||||
break;
|
||||
case 0x3E: // BRNE : TOS != TOS-1 ? IP += (IP)
|
||||
val = POP;
|
||||
if (TOS != val)
|
||||
ip += WORD_PTR(ip);
|
||||
else
|
||||
ip += 2;
|
||||
break;
|
||||
/*
|
||||
* 0x40-0x4F
|
||||
*/
|
||||
case 0x40: // ISEQ : TOS = TOS == TOS-1
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH((ea == val) ? -1 : 0);
|
||||
break;
|
||||
case 0x42: // ISNE : TOS = TOS != TOS-1
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH((ea != val) ? -1 : 0);
|
||||
break;
|
||||
case 0x44: // ISGT : TOS = TOS-1 > TOS
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH((ea > val) ? -1 : 0);
|
||||
break;
|
||||
case 0x46: // ISLT : TOS = TOS-1 < TOS
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH((ea < val) ? -1 : 0);
|
||||
break;
|
||||
case 0x48: // ISGE : TOS = TOS-1 >= TOS
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH((ea >= val) ? -1 : 0);
|
||||
break;
|
||||
case 0x4A: // ISLE : TOS = TOS-1 <= TOS
|
||||
val = POP;
|
||||
ea = POP;
|
||||
PUSH((ea <= val) ? -1 : 0);
|
||||
break;
|
||||
case 0x4C: // BRFLS : !TOS ? IP += (IP)
|
||||
if (!POP)
|
||||
ip += WORD_PTR(ip) ;
|
||||
else
|
||||
ip += 2;
|
||||
break;
|
||||
case 0x4E: // BRTRU : TOS ? IP += (IP)
|
||||
if (POP)
|
||||
ip += WORD_PTR(ip);
|
||||
else
|
||||
ip += 2;
|
||||
break;
|
||||
/*
|
||||
* 0x50-0x5F
|
||||
*/
|
||||
case 0x50: // BRNCH : IP += (IP)
|
||||
ip += WORD_PTR(ip);
|
||||
break;
|
||||
case 0x52: // IBRNCH : IP += TOS
|
||||
ip += POP;
|
||||
break;
|
||||
case 0x54: // CALL : TOFP = IP, IP = (IP) ; call
|
||||
call(UWORD_PTR(ip));
|
||||
ip += 2;
|
||||
break;
|
||||
case 0x56: // ICALL : TOFP = IP, IP = (TOS) ; indirect call
|
||||
val = UPOP;
|
||||
ea = mem_data[val] | (mem_data[val + 1] << 8);
|
||||
call(ea);
|
||||
break;
|
||||
case 0x58: // ENTER : NEW FRAME, FOREACH PARAM LOCALVAR = TOS
|
||||
frmsz = BYTE_PTR(ip);
|
||||
ip++;
|
||||
mem_data[fp - frmsz] = fp;
|
||||
mem_data[fp - frmsz + 1] = fp >> 8;
|
||||
if (show_state)
|
||||
printf("< $%04X: $%04X > ", fp - frmsz, fp);
|
||||
fp -= frmsz;
|
||||
parmcnt = BYTE_PTR(ip);
|
||||
ip++;
|
||||
while (parmcnt--)
|
||||
{
|
||||
val = POP;
|
||||
mem_data[fp + parmcnt * 2 + 2] = val;
|
||||
mem_data[fp + parmcnt * 2 + 3] = val >> 8;
|
||||
if (show_state)
|
||||
printf("< $%04X: $%04X > ", fp + parmcnt * 2 + 2, mem_data[fp + parmcnt * 2 + 2] | (mem_data[fp + parmcnt * 2 + 3] >> 8));
|
||||
}
|
||||
if (show_state)
|
||||
printf("\n");
|
||||
break;
|
||||
case 0x5A: // LEAVE : DEL FRAME, IP = TOFP
|
||||
fp = mem_data[fp] | (mem_data[fp + 1] << 8);
|
||||
case 0x5C: // RET : IP = TOFP
|
||||
return;
|
||||
case 0x5E: // ???
|
||||
break;
|
||||
/*
|
||||
* 0x60-0x6F
|
||||
*/
|
||||
case 0x60: // LB : TOS = BYTE (TOS)
|
||||
ea = TO_UWORD(POP);
|
||||
PUSH(mem_data[ea]);
|
||||
break;
|
||||
case 0x62: // LW : TOS = WORD (TOS)
|
||||
ea = UPOP;
|
||||
PUSH(mem_data[ea] | (mem_data[ea + 1] << 8));
|
||||
break;
|
||||
case 0x64: // LLB : TOS = LOCALBYTE [IP]
|
||||
PUSH(mem_data[TO_UWORD(fp + BYTE_PTR(ip))]);
|
||||
ip++;
|
||||
break;
|
||||
case 0x66: // LLW : TOS = LOCALWORD [IP]
|
||||
ea = TO_UWORD(fp + BYTE_PTR(ip));
|
||||
PUSH(mem_data[ea] | (mem_data[ea + 1] << 8));
|
||||
ip++;
|
||||
break;
|
||||
case 0x68: // LAB : TOS = BYTE (IP)
|
||||
PUSH(mem_data[UWORD_PTR(ip)]);
|
||||
ip += 2;
|
||||
break;
|
||||
case 0x6A: // LAW : TOS = WORD (IP)
|
||||
ea = UWORD_PTR(ip);
|
||||
PUSH(mem_data[ea] | (mem_data[ea + 1] << 8));
|
||||
ip += 2;
|
||||
break;
|
||||
case 0x6C: // DLB : TOS = TOS, LOCALBYTE [IP] = TOS
|
||||
mem_data[TO_UWORD(fp + BYTE_PTR(ip))] = TOS;
|
||||
ip++;
|
||||
break;
|
||||
case 0x6E: // DLW : TOS = TOS, LOCALWORD [IP] = TOS
|
||||
ea = TO_UWORD(fp + BYTE_PTR(ip));
|
||||
mem_data[ea] = TOS;
|
||||
mem_data[ea + 1] = TOS >> 8;
|
||||
ip++;
|
||||
break;
|
||||
/*
|
||||
* 0x70-0x7F
|
||||
*/
|
||||
case 0x70: // SB : BYTE (TOS) = TOS-1
|
||||
val = POP;
|
||||
ea = UPOP;
|
||||
mem_data[ea] = val;
|
||||
break;
|
||||
case 0x72: // SW : WORD (TOS) = TOS-1
|
||||
val = POP;
|
||||
ea = UPOP;
|
||||
mem_data[ea] = val;
|
||||
mem_data[ea + 1] = val >> 8;
|
||||
break;
|
||||
case 0x74: // SLB : LOCALBYTE [TOS] = TOS-1
|
||||
mem_data[TO_UWORD(fp + BYTE_PTR(ip))] = POP;
|
||||
ip++;
|
||||
break;
|
||||
case 0x76: // SLW : LOCALWORD [TOS] = TOS-1
|
||||
ea = TO_UWORD(fp + BYTE_PTR(ip));
|
||||
val = POP;
|
||||
mem_data[ea] = val;
|
||||
mem_data[ea + 1] = val >> 8;
|
||||
ip++;
|
||||
break;
|
||||
case 0x78: // SAB : BYTE (IP) = TOS
|
||||
mem_data[UWORD_PTR(ip)] = POP;
|
||||
ip += 2;
|
||||
break;
|
||||
case 0x7A: // SAW : WORD (IP) = TOS
|
||||
ea = UWORD_PTR(ip);
|
||||
val = POP;
|
||||
mem_data[ea] = val;
|
||||
mem_data[ea + 1] = val >> 8;
|
||||
ip += 2;
|
||||
break;
|
||||
case 0x7C: // DAB : TOS = TOS, BYTE (IP) = TOS
|
||||
mem_data[UWORD_PTR(ip)] = TOS;
|
||||
ip += 2;
|
||||
break;
|
||||
case 0x7E: // DAW : TOS = TOS, WORD (IP) = TOS
|
||||
ea = UWORD_PTR(ip);
|
||||
mem_data[ea] = TOS;
|
||||
mem_data[ea + 1] = TOS >> 8;
|
||||
ip += 2;
|
||||
break;
|
||||
/*
|
||||
* Odd codes and everything else are errors.
|
||||
*/
|
||||
default:
|
||||
fprintf(stderr, "Illegal opcode 0x%02X @ 0x%04X\n", ip[-1], ip - mem_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *stdlib_exp[] = {
|
||||
"VIEWPORT",
|
||||
"PUTC",
|
||||
"PUTS",
|
||||
"PUTSZ",
|
||||
"GETC",
|
||||
"GETS",
|
||||
"CLS",
|
||||
"GOTOXY"
|
||||
};
|
||||
|
||||
byte stdlib[] = {
|
||||
0x00
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
byte dci[32];
|
||||
int i;
|
||||
|
||||
if (--argc)
|
||||
{
|
||||
argv++;
|
||||
if ((*argv)[0] == '-' && (*argv)[1] == 's')
|
||||
{
|
||||
show_state = 1;
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
/*
|
||||
* Add default library.
|
||||
*/
|
||||
stodci("STDLIB", dci);
|
||||
add_mod(dci, 0xFFFF);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
mem_data[i] = i + 3;
|
||||
stodci(stdlib_exp[i], dci);
|
||||
add_sym(dci, i);
|
||||
}
|
||||
if (argc)
|
||||
{
|
||||
stodci(*argv, dci);
|
||||
load_mod(dci);
|
||||
if (show_state) dump_sym();
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
if (argc)
|
||||
{
|
||||
stodci(*argv, dci);
|
||||
call(lookup_sym(dci));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
1930
PLASMA/src/plvm02.s
Normal file
1930
PLASMA/src/plvm02.s
Normal file
File diff suppressed because it is too large
Load Diff
30
PLASMA/src/plvm02zp.inc
Normal file
30
PLASMA/src/plvm02zp.inc
Normal file
@ -0,0 +1,30 @@
|
||||
;**********************************************************
|
||||
;*
|
||||
;* VM ZERO PAGE LOCATIONS
|
||||
;*
|
||||
;**********************************************************
|
||||
ESTKSZ = $20
|
||||
ESTK = $C0
|
||||
ESTKL = ESTK
|
||||
ESTKH = ESTK+ESTKSZ/2
|
||||
VMZP = ESTK+ESTKSZ
|
||||
IFP = VMZP
|
||||
IFPL = IFP
|
||||
IFPH = IFP+1
|
||||
IP = IFP+2
|
||||
IPL = IP
|
||||
IPH = IP+1
|
||||
IPY = IP+2
|
||||
TMP = IP+3
|
||||
TMPL = TMP
|
||||
TMPH = TMP+1
|
||||
TMPX = TMP+2
|
||||
NPARMS = TMPL
|
||||
FRMSZ = TMPH
|
||||
DVSIGN = TMPX
|
||||
SRC = $06
|
||||
SRCL = SRC
|
||||
SRCH = SRC+1
|
||||
DST = SRC+2
|
||||
DSTL = DST
|
||||
DSTH = DST+1
|
150
PLASMA/src/samplib.s
Executable file
150
PLASMA/src/samplib.s
Executable file
@ -0,0 +1,150 @@
|
||||
;
|
||||
; Sample PLASMA library.
|
||||
;
|
||||
!TO "samplib.bin", PLAIN
|
||||
* = $1000
|
||||
;
|
||||
; DATA/CODE SEGMENT
|
||||
;
|
||||
_SEGBEGIN
|
||||
!WORD _SEGEND-_SEGBEGIN ; LENGTH OF HEADER + CODE/DATA + BYTECODE SEGMENT
|
||||
;
|
||||
; MODULE HEADER
|
||||
;
|
||||
!WORD $DA7E ; MAGIC #
|
||||
!WORD _SUBSEG ; BYTECODE SUB-SEGMENT
|
||||
!WORD _INIT ; BYTECODE INIT ROUTINE
|
||||
;
|
||||
; MODULE DEPENDENCY LIST
|
||||
; NOTE: DCI = PSUEDO OP FOR ASCII STRING WITH HI BIT SET EXCEPT LAST CHAR
|
||||
;
|
||||
;DCI "STDLIB"
|
||||
!CT "hi.ascii"
|
||||
!TX "STDLI"
|
||||
!CT RAW
|
||||
!TX 'B'
|
||||
;DCI "FILEIO"
|
||||
!CT "hi.ascii"
|
||||
!TX "FILEI"
|
||||
!CT RAW
|
||||
!TX 'O'
|
||||
!BYTE 0
|
||||
;
|
||||
; NATIVE CODE + GLOBAL DATA
|
||||
;
|
||||
COUNT !WORD 0
|
||||
INCCNT
|
||||
FIXUP1 INC COUNT
|
||||
BNE XINIT
|
||||
FIXUP2 INC COUNT+1
|
||||
XINIT RTS
|
||||
;
|
||||
; BYTECODE SUB-SEGMENT
|
||||
;
|
||||
_SUBSEG
|
||||
MYFUNC !BYTE $58, $01, $16 ; ENTER 1,16
|
||||
!BYTE $66, $02 ; LLW 2
|
||||
!BYTE $2A, $01 ; CB 1
|
||||
!BYTE $54 ; CALL EXTERN(1) "OPEN"
|
||||
FIXUP4 !WORD $0000
|
||||
!BYTE $6E, $04 ; DLW 4
|
||||
!BYTE $54 ; CALL EXTERN(3) "READ"
|
||||
FIXUP5 !WORD $0000
|
||||
!BYTE $30 ; DROP
|
||||
!BYTE $66, $04 ; LLW 4
|
||||
!BYTE $54 ; CALL EXTERN(2) ; "CLOSE"
|
||||
FIXUP6 !WORD $0000
|
||||
!BYTE $30 ; DROP
|
||||
!BYTE $6A ; LAW COUNT
|
||||
FIXUP7 !WORD $0000
|
||||
!BYTE $54 ; CALL INCNT
|
||||
FIXUP8 !WORD $0000
|
||||
!BYTE $5A ; LEAVE
|
||||
_INIT
|
||||
!BYTE $5C ; RET
|
||||
;
|
||||
; END OF CODE/DATA + BYTECODE SEGMENT
|
||||
;
|
||||
_SEGEND
|
||||
;
|
||||
; BYTCODE FUNCTION DICTIONARY
|
||||
;
|
||||
!BYTE $A1 ; FIXUP FLAGS
|
||||
!WORD MYFUNC ; FIXUP OFFSET
|
||||
!BYTE $00 ; FIXUP LO BYTE (OF HI BYTE)/IMPORT INDEX
|
||||
;
|
||||
; RE-LOCATION DICTIONARY (FIXUP TABLE)
|
||||
;
|
||||
!BYTE $81 ; FIXUP FLAGS
|
||||
!WORD FIXUP1+1 ; FIXUP OFFSET
|
||||
!BYTE $00 ; FIXUP LO BYTE (OF HI BYTE)/IMPORT INDEX
|
||||
!BYTE $81
|
||||
!WORD FIXUP2+1
|
||||
!BYTE $00
|
||||
!BYTE $91 ; IMPORT FIXUP
|
||||
!WORD FIXUP4
|
||||
!BYTE $01 ; IMPORT INDEX 1
|
||||
!BYTE $91
|
||||
!WORD FIXUP5
|
||||
!BYTE $03
|
||||
!BYTE $91
|
||||
!WORD FIXUP6
|
||||
!BYTE $02
|
||||
!BYTE $81
|
||||
!WORD FIXUP7
|
||||
!BYTE $00
|
||||
!BYTE $81
|
||||
!WORD FIXUP8
|
||||
!BYTE $00
|
||||
!BYTE 0 ; END OF RLD
|
||||
;
|
||||
; EXTERNAL/ENTRY SYMBOL DIRECTORY
|
||||
;;
|
||||
; IMPORT TABLE
|
||||
;
|
||||
IMPTBL ;DCI "OPEN" ; EXTERNAL SYMBOL NAME
|
||||
!CT "hi.ascii"
|
||||
!TX "OPE"
|
||||
!CT RAW
|
||||
!TX 'N'
|
||||
!BYTE $10 ; EXTERNAL SYMBOL FLAG
|
||||
!WORD 1 ; SYMBOL INDEX
|
||||
;DCI "CLOSE"
|
||||
!CT "hi.ascii"
|
||||
!TX "CLOS"
|
||||
!CT RAW
|
||||
!TX 'E'
|
||||
!BYTE $10
|
||||
!WORD 2
|
||||
;DCI "READ"
|
||||
!CT "hi.ascii"
|
||||
!TX "REA"
|
||||
!CT RAW
|
||||
!TX 'D'
|
||||
!BYTE $10
|
||||
!WORD 3
|
||||
;DCI "MEMSET"
|
||||
!CT "hi.ascii"
|
||||
!TX "MEMSE"
|
||||
!CT RAW
|
||||
!TX 'T'
|
||||
!BYTE $10
|
||||
!WORD 4
|
||||
;
|
||||
; EXPORT TABLE
|
||||
;
|
||||
EXPTBL ;DCI "INCNT" ; ENTRY SYMBOL NAME
|
||||
!CT "hi.ascii"
|
||||
!TX "INCN"
|
||||
!CT RAW
|
||||
!TX 'T'
|
||||
!BYTE $08 ; ENTRY SYMBOL FLAG
|
||||
!WORD INCCNT ; OFFSET
|
||||
;DCI "MYFUNC"
|
||||
!CT "hi.ascii"
|
||||
!TX "MYFUN"
|
||||
!CT RAW
|
||||
!TX 'C'
|
||||
!BYTE $08
|
||||
!WORD MYFUNC
|
||||
!BYTE 0 ; END OF ESD
|
39
PLASMA/src/symbols.h
Executable file
39
PLASMA/src/symbols.h
Executable file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Symbol table types.
|
||||
*/
|
||||
#define GLOBAL_TYPE (0)
|
||||
#define CONST_TYPE (1 << 0)
|
||||
#define WORD_TYPE (1 << 1)
|
||||
#define BYTE_TYPE (1 << 2)
|
||||
#define VAR_TYPE (WORD_TYPE | BYTE_TYPE)
|
||||
#define ASM_TYPE (1 << 3)
|
||||
#define DEF_TYPE (1 << 4)
|
||||
#define BRANCH_TYPE (1 << 5)
|
||||
#define LOCAL_TYPE (1 << 6)
|
||||
#define EXTERN_TYPE (1 << 7)
|
||||
#define ADDR_TYPE (VAR_TYPE | FUNC_TYPE | EXTERN_TYPE)
|
||||
#define WPTR_TYPE (1 << 8)
|
||||
#define BPTR_TYPE (1 << 9)
|
||||
#define PTR_TYPE (BPTR_TYPE | WPTR_TYPE)
|
||||
#define STRING_TYPE (1 << 10)
|
||||
#define TAG_TYPE (1 << 11)
|
||||
#define EXPORT_TYPE (1 << 12)
|
||||
#define PREDEF_TYPE (1 << 13)
|
||||
#define FUNC_TYPE (ASM_TYPE | DEF_TYPE | PREDEF_TYPE)
|
||||
int id_match(char *name, int len, char *id);
|
||||
int idlocal_lookup(char *name, int len);
|
||||
int idglobal_lookup(char *name, int len);
|
||||
int idconst_lookup(char *name, int len);
|
||||
int idlocal_add(char *name, int len, int type, int size);
|
||||
int idglobal_add(char *name, int len, int type, int size);
|
||||
int id_add(char *name, int len, int type, int size);
|
||||
int idfunc_set(char *name, int len, int type, int tag);
|
||||
int idfunc_add(char *name, int len, int type, int tag);
|
||||
int idconst_add(char *name, int len, int value);
|
||||
int id_tag(char *name, int len);
|
||||
int id_const(char *name, int len);
|
||||
int id_type(char *name, int len);
|
||||
void idglobal_size(int type, int size, int constsize);
|
||||
int idlocal_size(void);
|
||||
void idlocal_reset(void);
|
||||
int tag_new(int type);
|
53
PLASMA/src/test.pla
Executable file
53
PLASMA/src/test.pla
Executable file
@ -0,0 +1,53 @@
|
||||
;
|
||||
; Declare all imported modules and their data/functions.
|
||||
;
|
||||
import stdlib
|
||||
predef cls, gotoxy, puts, putc
|
||||
end
|
||||
|
||||
import testlib
|
||||
predef puti
|
||||
end
|
||||
;
|
||||
; Predeclare any functions called before defined.
|
||||
;
|
||||
predef main
|
||||
;
|
||||
; Declare all global variables for this module.
|
||||
;
|
||||
byte hello[] = "Hello, world.\n\n"
|
||||
word defptr = main
|
||||
;
|
||||
; Define functions.
|
||||
;
|
||||
def ascii
|
||||
byte i
|
||||
for i = 32 to 127
|
||||
putc(i)
|
||||
next
|
||||
end
|
||||
|
||||
def nums
|
||||
word i
|
||||
for i = -10 to 10
|
||||
puti(i)
|
||||
putc('\n')
|
||||
next
|
||||
end
|
||||
|
||||
export def main
|
||||
cls()
|
||||
ascii()
|
||||
gotoxy(35,5)
|
||||
puts(@hello)
|
||||
return nums
|
||||
end
|
||||
|
||||
export def indirect
|
||||
word mainptr
|
||||
mainptr = @main
|
||||
mainptr()
|
||||
end
|
||||
|
||||
indirect
|
||||
done
|
25
PLASMA/src/testlib.pla
Executable file
25
PLASMA/src/testlib.pla
Executable file
@ -0,0 +1,25 @@
|
||||
;
|
||||
; Declare all imported modules and their data/functions.
|
||||
;
|
||||
import stdlib
|
||||
predef cls, gotoxy, puts, putc
|
||||
end
|
||||
byte loadstr[] = "testlib loaded!\n"
|
||||
;
|
||||
; Define functions.
|
||||
;
|
||||
export def puti(i)
|
||||
if i < 0
|
||||
putc('-')
|
||||
i = -i
|
||||
fin
|
||||
if i < 10
|
||||
putc(i + '0')
|
||||
else
|
||||
puti(i / 10)
|
||||
putc(i % 10 + '0')
|
||||
fin
|
||||
end
|
||||
|
||||
puts(@loadstr);
|
||||
done
|
106
PLASMA/src/tokens.h
Executable file
106
PLASMA/src/tokens.h
Executable file
@ -0,0 +1,106 @@
|
||||
|
||||
#define TOKEN(c) (0x80|(c))
|
||||
#define IS_TOKEN(c) (0x80&(c))
|
||||
/*
|
||||
* Identifier and constant tokens.
|
||||
*/
|
||||
#define ID_TOKEN TOKEN('V')
|
||||
#define CHAR_TOKEN TOKEN('Y')
|
||||
#define INT_TOKEN TOKEN('Z')
|
||||
#define FLOAT_TOKEN TOKEN('F')
|
||||
#define STRING_TOKEN TOKEN('S')
|
||||
/*
|
||||
* Keyword tokens.
|
||||
*/
|
||||
#define CONST_TOKEN TOKEN(1)
|
||||
#define BYTE_TOKEN TOKEN(2)
|
||||
#define WORD_TOKEN TOKEN(3)
|
||||
#define IF_TOKEN TOKEN(4)
|
||||
#define ELSEIF_TOKEN TOKEN(5)
|
||||
#define ELSE_TOKEN TOKEN(6)
|
||||
#define FIN_TOKEN TOKEN(7)
|
||||
#define END_TOKEN TOKEN(8)
|
||||
#define WHILE_TOKEN TOKEN(9)
|
||||
#define LOOP_TOKEN TOKEN(10)
|
||||
#define CASE_TOKEN TOKEN(11)
|
||||
#define OF_TOKEN TOKEN(12)
|
||||
#define DEFAULT_TOKEN TOKEN(13)
|
||||
#define ENDCASE_TOKEN TOKEN(14)
|
||||
#define FOR_TOKEN TOKEN(15)
|
||||
#define TO_TOKEN TOKEN(16)
|
||||
#define DOWNTO_TOKEN TOKEN(17)
|
||||
#define STEP_TOKEN TOKEN(18)
|
||||
#define NEXT_TOKEN TOKEN(19)
|
||||
#define REPEAT_TOKEN TOKEN(20)
|
||||
#define UNTIL_TOKEN TOKEN(21)
|
||||
#define PREDEF_TOKEN TOKEN(22)
|
||||
#define DEF_TOKEN TOKEN(23)
|
||||
#define ASM_TOKEN TOKEN(24)
|
||||
#define IMPORT_TOKEN TOKEN(25)
|
||||
#define EXPORT_TOKEN TOKEN(26)
|
||||
#define DONE_TOKEN TOKEN(27)
|
||||
#define RETURN_TOKEN TOKEN(28)
|
||||
#define BREAK_TOKEN TOKEN(29)
|
||||
#define START_TOKEN TOKEN(30)
|
||||
#define EXIT_TOKEN TOKEN(31)
|
||||
#define EVAL_TOKEN TOKEN(32)
|
||||
/*
|
||||
* Double operand operators.
|
||||
*/
|
||||
#define SET_TOKEN TOKEN('=')
|
||||
#define ADD_TOKEN TOKEN('+')
|
||||
#define ADD_SELF_TOKEN TOKEN('a')
|
||||
#define SUB_TOKEN TOKEN('-')
|
||||
#define SUB_SELF_TOKEN TOKEN('u')
|
||||
#define MUL_TOKEN TOKEN('*')
|
||||
#define MUL_SELF_TOKEN TOKEN('m')
|
||||
#define DIV_TOKEN TOKEN('/')
|
||||
#define DIV_SELF_TOKEN TOKEN('d')
|
||||
#define MOD_TOKEN TOKEN('%')
|
||||
#define OR_TOKEN TOKEN('|')
|
||||
#define OR_SELF_TOKEN TOKEN('o')
|
||||
#define EOR_TOKEN TOKEN('^')
|
||||
#define EOR_SELF_TOKEN TOKEN('x')
|
||||
#define AND_TOKEN TOKEN('&')
|
||||
#define AND_SELF_TOKEN TOKEN('n')
|
||||
#define SHR_TOKEN TOKEN('R')
|
||||
#define SHR_SELF_TOKEN TOKEN('r')
|
||||
#define SHL_TOKEN TOKEN('L')
|
||||
#define SHL_SELF_TOKEN TOKEN('l')
|
||||
#define GT_TOKEN TOKEN('>')
|
||||
#define GE_TOKEN TOKEN('H')
|
||||
#define LT_TOKEN TOKEN('<')
|
||||
#define LE_TOKEN TOKEN('B')
|
||||
#define NE_TOKEN TOKEN('U')
|
||||
#define EQ_TOKEN TOKEN('E')
|
||||
#define LOGIC_AND_TOKEN TOKEN('N')
|
||||
#define LOGIC_OR_TOKEN TOKEN('O')
|
||||
/*
|
||||
* Single operand operators.
|
||||
*/
|
||||
#define NEG_TOKEN TOKEN('-')
|
||||
#define COMP_TOKEN TOKEN('~')
|
||||
#define LOGIC_NOT_TOKEN TOKEN('!')
|
||||
#define INC_TOKEN TOKEN('P')
|
||||
#define DEC_TOKEN TOKEN('K')
|
||||
#define BPTR_TOKEN TOKEN('^')
|
||||
#define WPTR_TOKEN TOKEN('*')
|
||||
#define POST_INC_TOKEN TOKEN('p')
|
||||
#define POST_DEC_TOKEN TOKEN('k')
|
||||
#define OPEN_PAREN_TOKEN TOKEN('(')
|
||||
#define CLOSE_PAREN_TOKEN TOKEN(')')
|
||||
#define OPEN_BRACKET_TOKEN TOKEN('[')
|
||||
#define CLOSE_BRACKET_TOKEN TOKEN(']')
|
||||
/*
|
||||
* Misc. tokens.
|
||||
*/
|
||||
#define AT_TOKEN TOKEN('@')
|
||||
#define DOT_TOKEN TOKEN('.')
|
||||
#define COLON_TOKEN TOKEN(':')
|
||||
#define POUND_TOKEN TOKEN('#')
|
||||
#define COMMA_TOKEN TOKEN(',')
|
||||
#define COMMENT_TOKEN TOKEN(';')
|
||||
#define EOL_TOKEN TOKEN(0)
|
||||
#define EOF_TOKEN TOKEN(0x7F)
|
||||
|
||||
typedef unsigned char t_token;
|
Loading…
Reference in New Issue
Block a user