mirror of
https://git.code.sf.net/p/newrpl/sources
synced 2024-11-16 19:51:25 +01:00
205 lines
6.4 KiB
C
205 lines
6.4 KiB
C
/*
|
|
* Copyright (c) 2014, Claudio Lapilli and the newRPL Team
|
|
* All rights reserved.
|
|
* This file is released under the 3-clause BSD license.
|
|
* See the file LICENSE.txt that shipped with this distribution.
|
|
*/
|
|
|
|
// LIBRARY ZERO HAS SPECIAL RUNSTREAM OPERATORS
|
|
|
|
#include "newrpl.h"
|
|
#include "libraries.h"
|
|
#include "hal.h"
|
|
// THERE'S ONLY ONE EXTERNAL FUNCTION: THE LIBRARY HANDLER
|
|
// ALL OTHER FUNCTIONS ARE LOCAL
|
|
// LIB0 PROVIDES EXIT FROM RPL, BREAKPOINTS AND RUNSTREAM MANIPULATION OPCODES
|
|
|
|
// MAIN LIBRARY NUMBER, CHANGE THIS FOR EACH LIBRARY
|
|
#define LIBRARY_NUMBER 8
|
|
#define LIB_ENUM lib8_enum
|
|
#define LIB_NAMES lib8_names
|
|
#define LIB_HANDLER lib8_handler
|
|
#define LIB_NUMBEROFCMDS LIB8_NUMBEROFCMDS
|
|
|
|
// LIST OF COMMANDS EXPORTED, CHANGE FOR EACH LIBRARY
|
|
#define CMD_LIST \
|
|
CMD(EXITRPL), \
|
|
CMD(BREAKPOINT), \
|
|
CMD(XEQSECO)
|
|
|
|
// ADD MORE OPCODES HERE
|
|
|
|
|
|
// EXTRA LIST FOR COMMANDS WITH SYMBOLS THAT ARE DISALLOWED IN AN ENUM
|
|
// THE NAMES AND ENUM SYMBOLS ARE GIVEN SEPARATELY
|
|
#define CMD_EXTRANAME \
|
|
";",
|
|
|
|
#define CMD_EXTRAENUM \
|
|
SEMI
|
|
|
|
//
|
|
|
|
// INTERNAL DECLARATIONS
|
|
|
|
|
|
// CREATE AN ENUM WITH THE OPCODE NAMES FOR THE DISPATCHER
|
|
#define CMD(a) a
|
|
enum LIB_ENUM { CMD_LIST , CMD_EXTRAENUM , LIB_NUMBEROFCMDS };
|
|
#undef CMD
|
|
|
|
// AND A LIST OF STRINGS WITH THE NAMES FOR THE COMPILER
|
|
#define CMD(a) #a
|
|
char *LIB_NAMES[]= { CMD_LIST , CMD_EXTRANAME };
|
|
#undef CMD
|
|
|
|
|
|
void LIB_HANDLER()
|
|
{
|
|
if(ISPROLOG(CurOpcode)) {
|
|
// PROVIDE BEHAVIOR OF EXECUTING THE OBJECT HERE
|
|
|
|
rplPushRet(IPtr); // PUSH CURRENT POINTER AS THE RETURN ADDRESS. AT THIS POINT, IPtr IS POINTING TO THIS SECONDARY WORD
|
|
// BUT THE MAIN LOOP WILL ALWAYS SKIP TO THE NEXT OBJECT AFTER A SEMI.
|
|
CurOpcode=MKPROLOG(LIBRARY_NUMBER,0); // ALTER THE SIZE OF THE SECONDARY TO ZERO WORDS, SO THE NEXT EXECUTED INSTRUCTION WILL BE THE FIRST IN THIS SECONDARY
|
|
return;
|
|
}
|
|
|
|
switch(OPCODE(CurOpcode))
|
|
{
|
|
case EXITRPL:
|
|
return;
|
|
case BREAKPOINT:
|
|
Exceptions|=EX_BKPOINT;
|
|
ExceptionPointer=IPtr;
|
|
return;
|
|
case XEQSECO:
|
|
// IF THE NEXT OBJECT IN THE SECONDARY
|
|
// IS A SECONDARY, IT EVALUATES IT INSTEAD OF PUSHING IT ON THE STACK
|
|
++IPtr;
|
|
CurOpcode=*IPtr;
|
|
if(ISPROLOG(CurOpcode)&& (LIBNUM(CurOpcode)==SECO)) {
|
|
CurOpcode=MKPROLOG(SECO,0); // MAKE IT SKIP INSIDE THE SECONDARY
|
|
rplPushRet(IPtr);
|
|
return;
|
|
}
|
|
// HAVE NO EFFECT ON ANY OTHER OBJECTS
|
|
--IPtr;
|
|
CurOpcode=*IPtr;
|
|
return;
|
|
|
|
case SEMI:
|
|
// POP THE RETURN ADDRESS
|
|
IPtr=rplPopRet(); // GET THE CALLER ADDRESS
|
|
CurOpcode=*IPtr; // SET THE WORD SO MAIN LOOP SKIPS THIS OBJECT, AND THE NEXT ONE IS EXECUTED
|
|
return;
|
|
|
|
|
|
// ADD MORE OPCODES HERE
|
|
case OVR_EVAL:
|
|
// EXECUTE THE OBJECT
|
|
case OVR_XEQ:
|
|
// ALSO EXECUTE THE OBJECT
|
|
rplPushRet(IPtr); // PUSH CURRENT POINTER AS THE RETURN ADDRESS.
|
|
IPtr=rplPopData(); // SET NEW IPTR TO THE PROGRAM, TO BE EXECUTED
|
|
CurOpcode=MKPROLOG(LIBRARY_NUMBER,0); // ALTER THE SIZE OF THE SECONDARY TO ZERO WORDS, SO THE NEXT EXECUTED INSTRUCTION WILL BE THE FIRST IN THIS SECONDARY
|
|
return;
|
|
|
|
// STANDARIZED OPCODES:
|
|
// --------------------
|
|
// LIBRARIES ARE FORCED TO ALWAYS HANDLE THE STANDARD OPCODES
|
|
|
|
|
|
case OPCODE_COMPILE:
|
|
// COMPILE RECEIVES:
|
|
// TokenStart = token string
|
|
// TokenLen = token length
|
|
// BlankStart = token blanks afterwards
|
|
// BlanksLen = blanks length
|
|
// CurrentConstruct = Opcode of current construct/WORD of current composite
|
|
|
|
// COMPILE RETURNS:
|
|
// RetNum = enum CompileErrors
|
|
|
|
// CHECK IF THE TOKEN IS THE OBJECT DOCOL
|
|
|
|
if((TokenLen==2) && (!strncmp((char * )TokenStart,"::",2)))
|
|
{
|
|
rplCompileAppend((WORD) MKPROLOG(LIBRARY_NUMBER,0));
|
|
RetNum=OK_STARTCONSTRUCT;
|
|
return;
|
|
}
|
|
// CHECK IF THE TOKEN IS SEMI
|
|
|
|
if(((TokenLen==1) && (!strncmp((char *)TokenStart,";",1))))
|
|
{
|
|
if(CurrentConstruct!=MKPROLOG(LIBRARY_NUMBER,0)) {
|
|
RetNum=ERR_SYNTAX;
|
|
return;
|
|
}
|
|
rplCleanupLAMs(*(ValidateTop-1));
|
|
rplCompileAppend(MKOPCODE(LIBRARY_NUMBER,SEMI));
|
|
RetNum=OK_ENDCONSTRUCT;
|
|
return;
|
|
}
|
|
|
|
// THIS STANDARD FUNCTION WILL TAKE CARE OF COMPILATION OF STANDARD COMMANDS GIVEN IN THE LIST
|
|
// NO NEED TO CHANGE THIS UNLESS CUSTOM OPCODES
|
|
libCompileCmds(LIBRARY_NUMBER,LIB_NAMES,NULL,LIB_NUMBEROFCMDS);
|
|
|
|
// SINCE THIS IS THE LAST LIBRARY TO BE EVALUATED, DO ONE LAST PASS TO COMPILE IT AS AN IDENT
|
|
// EITHER LAM OR IN USEROB
|
|
return;
|
|
|
|
case OPCODE_DECOMPILE:
|
|
// DECOMPILE RECEIVES:
|
|
// DecompileObject = Ptr to WORD of object to decompile
|
|
// DecompStringEnd = Ptr to the end of decompile string
|
|
|
|
//DECOMPILE RETURNS
|
|
// RetNum = enum DecompileErrors
|
|
|
|
if(ISPROLOG(*DecompileObject)) {
|
|
rplDecompAppendString((BYTEPTR)"::");
|
|
RetNum=OK_STARTCONSTRUCT;
|
|
return;
|
|
}
|
|
|
|
|
|
// THIS STANDARD FUNCTION WILL TAKE CARE OF DECOMPILING STANDARD COMMANDS GIVEN IN THE LIST
|
|
// NO NEED TO CHANGE THIS UNLESS THERE ARE CUSTOM OPCODES
|
|
libDecompileCmds(LIB_NAMES,NULL,LIB_NUMBEROFCMDS);
|
|
return;
|
|
case OPCODE_VALIDATE:
|
|
// VALIDATE RECEIVES OPCODES COMPILED BY OTHER LIBRARIES, TO BE INCLUDED WITHIN A COMPOSITE OWNED BY
|
|
// THIS LIBRARY. EVERY COMPOSITE HAS TO EVALUATE IF THE OBJECT BEING COMPILED IS ALLOWED INSIDE THIS
|
|
// COMPOSITE OR NOT. FOR EXAMPLE, A REAL MATRIX SHOULD ONLY ALLOW REAL NUMBERS INSIDE, ANY OTHER
|
|
// OPCODES SHOULD BE REJECTED AND AN ERROR THROWN.
|
|
// Library receives:
|
|
// CurrentConstruct = SET TO THE CURRENT ACTIVE CONSTRUCT TYPE
|
|
// LastCompiledObject = POINTER TO THE LAST OBJECT THAT WAS COMPILED, THAT NEEDS TO BE VERIFIED
|
|
|
|
// VALIDATE RETURNS:
|
|
// RetNum = OK_CONTINUE IF THE OBJECT IS ACCEPTED, ERR_INVALID IF NOT.
|
|
|
|
|
|
RetNum=OK_CONTINUE;
|
|
return;
|
|
}
|
|
// UNHANDLED OPCODE...
|
|
|
|
// IF IT'S A COMPILER OPCODE, RETURN ERR_NOTMINE
|
|
if(OPCODE(CurOpcode)>=MIN_RESERVED_OPCODE) {
|
|
RetNum=ERR_NOTMINE;
|
|
return;
|
|
}
|
|
// BY DEFAULT, ISSUE A BAD OPCODE ERROR
|
|
Exceptions|=EX_BADOPCODE;
|
|
ExceptionPointer=IPtr;
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|