forked from MirrorRepos/RomWBW
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
404 lines
12 KiB
404 lines
12 KiB
//////////////////////////////////////////////////////////////
|
|
// //
|
|
// Propeller Spin/PASM Compiler //
|
|
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|
// Adapted from Chip Gracey's x86 asm code by Roy Eltham //
|
|
// See end of file for terms of use. //
|
|
// //
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// CompileInstruction.cpp
|
|
//
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include "Utilities.h"
|
|
#include "PropellerCompilerInternal.h"
|
|
#include "SymbolEngine.h"
|
|
#include "Elementizer.h"
|
|
#include "ErrorStrings.h"
|
|
#include "CompileUtilities.h"
|
|
|
|
// these are in CompileExpression.cpp
|
|
extern bool CompileTerm_Try(unsigned char anchor);
|
|
extern bool CompileTerm_Sub(unsigned char anchor, int value);
|
|
extern bool CompileTerm_ObjPub(unsigned char anchor, int value);
|
|
extern bool CompileTerm_CogNew(int value);
|
|
extern bool CompileTerm_Inst(int value);
|
|
|
|
bool CompileInst_NextQuit(int value)
|
|
{
|
|
int blockNestPtr = g_pCompilerData->bnest_ptr;
|
|
|
|
unsigned char byteCode = 0;
|
|
int caseDepth = 0;
|
|
|
|
// find repeat block
|
|
for (;;)
|
|
{
|
|
if (blockNestPtr == 0)
|
|
{
|
|
g_pCompilerData->error = true;
|
|
g_pCompilerData->error_msg = g_pErrorStrings[error_tioawarb];
|
|
return false;
|
|
}
|
|
|
|
unsigned char blockNestType = g_pCompilerData->bnest_type[blockNestPtr-1];
|
|
|
|
if (blockNestType == type_repeat)
|
|
{
|
|
byteCode = 0x04; // jmp 'quit'
|
|
break;
|
|
}
|
|
else if (blockNestType == type_repeat_count)
|
|
{
|
|
byteCode = 0x0B; // jnz 'quit'
|
|
break;
|
|
}
|
|
else if (blockNestType == type_if)
|
|
{
|
|
// ignore 'if' block nest(s)
|
|
}
|
|
else if (blockNestType == type_case) // allow nesting within 'case' block(s)
|
|
{
|
|
caseDepth += 8; // pop 2 longs for each nested 'case'
|
|
}
|
|
else
|
|
{
|
|
g_pCompilerData->error = true;
|
|
g_pCompilerData->error_msg = g_pErrorStrings[error_internal];
|
|
return false;
|
|
}
|
|
blockNestPtr--;
|
|
}
|
|
|
|
if (caseDepth > 0)
|
|
{
|
|
if (!CompileConstant(caseDepth)) // enter pop count
|
|
{
|
|
return false;
|
|
}
|
|
if (!EnterObj(0x14)) // pop
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int blockStackPtr = g_pCompilerData->bstack_base[blockNestPtr - 1];
|
|
|
|
if ((value & 0xFF) == 0)
|
|
{
|
|
// next
|
|
if (!EnterObj(0x04)) // jmp 'next'
|
|
{
|
|
return false;
|
|
}
|
|
return CompileAddress(g_pCompilerData->bstack[blockStackPtr]);
|
|
}
|
|
|
|
// quit
|
|
if (!EnterObj(byteCode)) // jmp/jnz 'quit'
|
|
{
|
|
return false;
|
|
}
|
|
return CompileAddress(g_pCompilerData->bstack[blockStackPtr + 1]);
|
|
}
|
|
|
|
bool CompileInst_AbortReturn(int value)
|
|
{
|
|
// preview next element
|
|
bool bEof = false;
|
|
if (!g_pElementizer->GetNext(bEof))
|
|
{
|
|
return false;
|
|
}
|
|
g_pElementizer->Backup();
|
|
|
|
if (g_pElementizer->GetType() != type_end)
|
|
{
|
|
// there's an expression, compile it
|
|
if (!CompileExpression())
|
|
{
|
|
return false;
|
|
}
|
|
value |= 0x01; // +value
|
|
}
|
|
return EnterObj((unsigned char)(value & 0xFF));
|
|
}
|
|
|
|
bool CompileInst_Reboot()
|
|
{
|
|
if (!EnterObj(0x37)) // constant 0x80
|
|
{
|
|
return false;
|
|
}
|
|
if (!EnterObj(0x06))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!EnterObj(0x35)) // constant 0
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return EnterObj(0x20); // clkset
|
|
}
|
|
|
|
bool CompileInst_CogNew(int value)
|
|
{
|
|
return CompileTerm_CogNew(value ^ 0x04); // no push
|
|
}
|
|
|
|
bool CompileInst_CogInit(int value)
|
|
{
|
|
int savedSourcePtr = g_pElementizer->GetSourcePtr();
|
|
|
|
if (!g_pElementizer->GetElement(type_left))
|
|
{
|
|
return false;
|
|
}
|
|
int cogidSourcePtr = g_pElementizer->GetSourcePtr();
|
|
if (!SkipExpression())
|
|
{
|
|
return false;
|
|
}
|
|
if (!g_pElementizer->GetElement(type_comma))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// check for subroutine
|
|
bool bEof = false;
|
|
if (!g_pElementizer->GetNext(bEof))
|
|
{
|
|
return false;
|
|
}
|
|
if (g_pElementizer->GetType() != type_sub)
|
|
{
|
|
// not subroutine, so backup
|
|
g_pElementizer->SetSourcePtr(savedSourcePtr);
|
|
|
|
return CompileTerm_Inst(value); // compile assembly 'coginit'
|
|
}
|
|
|
|
// compile subroutine 'cognew' (push params+index)
|
|
int subConstant = g_pElementizer->GetValue();
|
|
|
|
if (!g_pCompilerData->bFinalCompile && g_pCompilerData->bUnusedMethodElimination)
|
|
{
|
|
AddCogNewOrInit(g_pCompilerData->current_filename, subConstant & 0x000000FF);
|
|
}
|
|
|
|
if (!CompileParameters((g_pElementizer->GetValue() & 0x0000FF00) >> 8))
|
|
{
|
|
return false;
|
|
}
|
|
if (!CompileConstant(subConstant))
|
|
{
|
|
return false;
|
|
}
|
|
if (!g_pElementizer->GetElement(type_comma))
|
|
{
|
|
return false;
|
|
}
|
|
if (!CompileExpression()) // compile stack expression
|
|
{
|
|
return false;
|
|
}
|
|
if (!g_pElementizer->GetElement(type_right))
|
|
{
|
|
return false;
|
|
}
|
|
if (!EnterObj(0x15)) // run
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// compile 'cogid' exp
|
|
if (!CompileOutOfSequenceExpression(cogidSourcePtr))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!EnterObj(0x3F)) // regop
|
|
{
|
|
return false;
|
|
}
|
|
if (!EnterObj(0x8F)) // read+dcurr
|
|
{
|
|
return false;
|
|
}
|
|
if (!EnterObj(0x37)) // constant mask
|
|
{
|
|
return false;
|
|
}
|
|
if (!EnterObj(0x61)) // -4
|
|
{
|
|
return false;
|
|
}
|
|
if (!EnterObj(0xD1)) // write long[base][index]
|
|
{
|
|
return false;
|
|
}
|
|
return EnterObj(0x2C); // coginit
|
|
}
|
|
|
|
bool CompileInst_InstCr(int value)
|
|
{
|
|
return CompileTerm_Inst(value ^ 0x04); // no push
|
|
}
|
|
|
|
bool CompileInst_Unary(int value)
|
|
{
|
|
return CompileVariable_PreSignExtendOrRandom((unsigned char)(0x40 | (value & 0xFF)));
|
|
}
|
|
|
|
bool CompileInst_Assign(unsigned char vOperator, unsigned char type, unsigned char size, int address, int indexSourcePtr)
|
|
{
|
|
if (!CompileExpression())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return CompileVariable(1, vOperator, type, size, address, indexSourcePtr);
|
|
}
|
|
|
|
bool CompileInstruction()
|
|
{
|
|
int type = g_pElementizer->GetType();
|
|
int value = g_pElementizer->GetValue();
|
|
|
|
switch(type)
|
|
{
|
|
case type_back:
|
|
return CompileTerm_Try(0x03);
|
|
case type_sub:
|
|
return CompileTerm_Sub(0x01, value);
|
|
case type_obj:
|
|
return CompileTerm_ObjPub(0x01, value);
|
|
case type_i_next_quit:
|
|
return CompileInst_NextQuit(value);
|
|
case type_i_abort_return:
|
|
return CompileInst_AbortReturn(value);
|
|
case type_i_reboot:
|
|
return CompileInst_Reboot();
|
|
case type_i_cognew:
|
|
return CompileInst_CogNew(value);
|
|
case type_i_coginit:
|
|
return CompileInst_CogInit(value);
|
|
case type_i_cr: // instruction can-return
|
|
return CompileInst_InstCr(value);
|
|
case type_i_nr: // instruction never-return
|
|
return CompileTerm_Inst(value);
|
|
|
|
case type_inc: // assign pre-inc ++var
|
|
return CompileVariable_PreIncOrDec(0x20);
|
|
case type_dec: // assign pre-dec --var
|
|
return CompileVariable_PreIncOrDec(0x30);
|
|
case type_til: // assign sign-extern byte ~var
|
|
return CompileVariable_PreSignExtendOrRandom(0x10);
|
|
case type_tiltil: // assign sign-extern word ~~var
|
|
return CompileVariable_PreSignExtendOrRandom(0x14);
|
|
case type_rnd: // assign random forward ?var
|
|
return CompileVariable_PreSignExtendOrRandom(0x08);
|
|
}
|
|
|
|
g_pElementizer->SubToNeg();
|
|
if (g_pElementizer->GetType() == type_unary)
|
|
{
|
|
return CompileInst_Unary(g_pElementizer->GetOpType());
|
|
}
|
|
|
|
unsigned char varType = 0;
|
|
unsigned char varSize = 0;
|
|
int varAddress = 0;
|
|
int varIndexSourcePtr = 0;
|
|
bool bVariable = false;
|
|
if (!CheckVariable(bVariable, varType, varSize, varAddress, varIndexSourcePtr))
|
|
{
|
|
return false;
|
|
}
|
|
if (!bVariable)
|
|
{
|
|
g_pCompilerData->error = true;
|
|
g_pCompilerData->error_msg = g_pErrorStrings[error_eaiov];
|
|
return false;
|
|
}
|
|
|
|
// check for post-var modifier
|
|
bool bEof = false;
|
|
if (!g_pElementizer->GetNext(bEof))
|
|
{
|
|
return false;
|
|
}
|
|
type = g_pElementizer->GetType();
|
|
switch (type)
|
|
{
|
|
case type_inc: // assign post-inc
|
|
return CompileVariable_IncOrDec(0x28, varType, varSize, varAddress, varIndexSourcePtr);
|
|
case type_dec: // assign post-dec
|
|
return CompileVariable_IncOrDec(0x38, varType, varSize, varAddress, varIndexSourcePtr);
|
|
case type_rnd: // assign random reverse
|
|
return CompileVariable_Assign(0x0C, varType, varSize, varAddress, varIndexSourcePtr);
|
|
case type_til: // assign post-clear
|
|
return CompileVariable_Assign(0x18, varType, varSize, varAddress, varIndexSourcePtr);
|
|
case type_tiltil: // assign post-set
|
|
return CompileVariable_Assign(0x1C, varType, varSize, varAddress, varIndexSourcePtr);
|
|
case type_assign:
|
|
return CompileInst_Assign(0x1C, varType, varSize, varAddress, varIndexSourcePtr);
|
|
}
|
|
|
|
// var binaryop?
|
|
if (type == type_binary)
|
|
{
|
|
unsigned char varOperator = 0x40; // assign math w/swapargs
|
|
varOperator |= (unsigned char)(g_pElementizer->GetOpType());
|
|
|
|
// check for '=' after binary op
|
|
if (!g_pElementizer->GetNext(bEof))
|
|
{
|
|
return false;
|
|
}
|
|
if (g_pElementizer->GetType() == type_equal)
|
|
{
|
|
return CompileVariable_Expression(varOperator, varType, varSize, varAddress, varIndexSourcePtr);
|
|
}
|
|
else
|
|
{
|
|
g_pElementizer->Backup(); // not '=' so backup
|
|
}
|
|
}
|
|
g_pElementizer->Backup(); // no post-var modifier, so backup
|
|
|
|
// error, so backup and reget variable for error display
|
|
g_pElementizer->Backup();
|
|
g_pElementizer->GetNext(bEof); // this won't fail here, because it already succeeded above
|
|
|
|
g_pCompilerData->error = true;
|
|
g_pCompilerData->error_msg = g_pErrorStrings[error_vnao];
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// TERMS OF USE: MIT License //
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this //
|
|
// software and associated documentation files (the "Software"), to deal in the Software //
|
|
// without restriction, including without limitation the rights to use, copy, modify, //
|
|
// merge, publish, distribute, sublicense, and/or sell copies of the Software, and to //
|
|
// permit persons to whom the Software is furnished to do so, subject to the following //
|
|
// conditions: //
|
|
// //
|
|
// The above copyright notice and this permission notice shall be included in all copies //
|
|
// or substantial portions of the Software. //
|
|
// //
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, //
|
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A //
|
|
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT //
|
|
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION //
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE //
|
|
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|