forked from MirrorRepos/RomWBW
Browse Source
- Added support for Duodyne to PS2INFO application. - Switched all build paths to consistently use OpenSpin since it appears to be compatible with all build environments supported by RomWBW.patch
61 changed files with 15526 additions and 86 deletions
@ -1,5 +1,5 @@ |
|||
@echo off |
|||
setlocal |
|||
|
|||
if exist *.eeprom del *.eeprom |
|||
if exist *.list del *.list |
|||
if exist Spin\*.eeprom del Spin\*.eeprom |
|||
if exist Spin\*.list del Spin\*.list |
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,5 @@ |
|||
language: c |
|||
os: |
|||
- linux |
|||
- osx |
|||
script: make |
|||
@ -0,0 +1,68 @@ |
|||
# modified for RomWBW build environment
|
|||
|
|||
UNAME := $(shell uname) |
|||
DEST = ../../$(UNAME) |
|||
|
|||
# cross compilation scheme taken from Eric Smith's spin2cpp compiler
|
|||
# if CROSS is defined, we are building a cross compiler
|
|||
# possible targets are: win32, rpi
|
|||
|
|||
ifeq ($(CC),) |
|||
CC=gcc |
|||
endif |
|||
|
|||
ifeq ($(CXX),) |
|||
CXX=g++ |
|||
endif |
|||
|
|||
ifeq ($(CROSS),win32) |
|||
CC=i686-w64-mingw32-gcc |
|||
CXX=i686-w64-mingw32-g++ |
|||
EXT=.exe |
|||
BUILD=./build-win32 |
|||
else ifeq ($(CROSS),rpi) |
|||
CC=arm-linux-gnueabihf-gcc |
|||
CXX=arm-linux-gnueabihf-g++ |
|||
EXT= |
|||
BUILD=./build-rpi |
|||
else |
|||
EXT= |
|||
BUILD=./build |
|||
endif |
|||
|
|||
OS:=$(shell uname) |
|||
|
|||
ifeq ($(OS),Darwin) |
|||
CFLAGS+=-Wall -g -Wno-self-assign |
|||
else |
|||
CFLAGS+=-Wall -g $(MSTATIC) |
|||
endif |
|||
|
|||
CXXFLAGS += $(CFLAGS) |
|||
|
|||
TARGET=$(BUILD)/openspin$(EXT) |
|||
SRCDIR=SpinSource |
|||
OBJ=$(BUILD)/openspin.o \
|
|||
$(BUILD)/pathentry.o |
|||
|
|||
LIBNAME=$(BUILD)/PropellerCompiler/libopenspin.a |
|||
|
|||
all: $(BUILD) $(DEST) $(LIBNAME) $(OBJ) Makefile |
|||
$(CXX) -o $(TARGET) $(CXXFLAGS) $(OBJ) $(LIBNAME) |
|||
cp -p $(TARGET) $(DEST) |
|||
|
|||
$(BUILD)/%.o: $(SRCDIR)/%.cpp |
|||
$(CXX) $(CXXFLAGS) -o $@ -c $< |
|||
|
|||
$(LIBNAME): $(BUILD) |
|||
$(MAKE) -C PropellerCompiler CROSS=$(CROSS) BUILD=$(realpath $(BUILD))/PropellerCompiler all |
|||
|
|||
$(BUILD): |
|||
mkdir -p $(BUILD) |
|||
|
|||
$(DEST): |
|||
mkdir -p $(DEST) |
|||
|
|||
clean: |
|||
rm -rf $(BUILD) |
|||
make -C PropellerCompiler BUILD=$(realpath $(BUILD))/PropellerCompiler clean |
|||
@ -0,0 +1,136 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// BlockNestStackRoutines.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" |
|||
|
|||
//
|
|||
// Block Nest Routines
|
|||
//
|
|||
|
|||
bool BlockNest_New(unsigned char type, int stackSize) |
|||
{ |
|||
if (g_pCompilerData->bnest_ptr > block_nest_limit) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_loxnbe]; |
|||
return false; |
|||
} |
|||
|
|||
// set blockstack base
|
|||
g_pCompilerData->bnest_type[g_pCompilerData->bnest_ptr] = type; |
|||
g_pCompilerData->bstack_base[g_pCompilerData->bnest_ptr++] = g_pCompilerData->bstack_ptr; |
|||
|
|||
// init bstack values to max forward
|
|||
for (int i = 0; i < stackSize; i++) |
|||
{ |
|||
g_pCompilerData->bstack[g_pCompilerData->bstack_ptr + i] = 0x0000FFC0; |
|||
} |
|||
g_pCompilerData->bstack_ptr += stackSize; |
|||
if (g_pCompilerData->bstack_ptr >= block_stack_limit) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_bnso]; |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
void BlockNest_Redo(unsigned char type) |
|||
{ |
|||
g_pCompilerData->bnest_type[g_pCompilerData->bnest_ptr - 1] = type; |
|||
} |
|||
|
|||
void BlockNest_End() |
|||
{ |
|||
g_pCompilerData->bnest_ptr--; |
|||
g_pCompilerData->bstack_ptr = g_pCompilerData->bstack_base[g_pCompilerData->bnest_ptr]; |
|||
} |
|||
|
|||
//
|
|||
// Block Stack Routines
|
|||
//
|
|||
|
|||
void BlockStack_Write(int address, int value) |
|||
{ |
|||
int stackAddress = g_pCompilerData->bstack_base[g_pCompilerData->bnest_ptr - 1] + address; |
|||
g_pCompilerData->bstack[stackAddress] = value; |
|||
} |
|||
|
|||
int BlockStack_Read(int address) |
|||
{ |
|||
int stackAddress = g_pCompilerData->bstack_base[g_pCompilerData->bnest_ptr - 1] + address; |
|||
return g_pCompilerData->bstack[stackAddress]; |
|||
} |
|||
|
|||
bool BlockStack_CompileAddress(int address) |
|||
{ |
|||
return CompileAddress(BlockStack_Read(address)); |
|||
} |
|||
|
|||
bool BlockStack_CompileConstant() |
|||
{ |
|||
int value = BlockStack_Read(0); |
|||
|
|||
if (value >= 0x100) |
|||
{ |
|||
// two byte
|
|||
if (!EnterObj(0x39)) // 0x39 = 00111001b
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj((unsigned char)((value >> 8) & 0xFF))) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// one byte
|
|||
if (!EnterObj(0x38)) // 0x38 = 00111000b
|
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
return EnterObj((unsigned char)(value & 0xFF)); |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,932 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// CompileDatBlocks.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" |
|||
|
|||
void CompileDatBlocks_EnterInfo(int datstart, int objstart) |
|||
{ |
|||
g_pCompilerData->inf_start = datstart; |
|||
g_pCompilerData->inf_finish = g_pElementizer->GetSourcePtr(); |
|||
g_pCompilerData->inf_data0 = objstart; |
|||
g_pCompilerData->inf_data1 = g_pCompilerData->obj_ptr; |
|||
g_pCompilerData->inf_data2 = 0; |
|||
g_pCompilerData->inf_data3 = 0; |
|||
g_pCompilerData->inf_data4 = 0; |
|||
g_pCompilerData->inf_type = info_dat; |
|||
EnterInfo(); |
|||
} |
|||
|
|||
void CompileDatBlocks_EnterSymbol(bool bResSymbol, int size) |
|||
{ |
|||
int value_1 = g_pCompilerData->obj_ptr; |
|||
int value_2 = g_pCompilerData->cog_org; |
|||
g_pCompilerData->inf_data0 = value_1; |
|||
g_pCompilerData->inf_data1 = size; |
|||
g_pCompilerData->inf_data2 = value_2; |
|||
g_pCompilerData->inf_data3 = 0; |
|||
g_pCompilerData->inf_data4 = 0; |
|||
g_pCompilerData->inf_type = info_dat_symbol; |
|||
EnterInfo(); |
|||
g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, bResSymbol ? type_dat_long_res : (size == 0 ? type_dat_byte : (size == 1 ? type_dat_word : type_dat_long)), value_1, value_2); |
|||
#ifdef RPE_DEBUG |
|||
printf("dat: %s %08X %08X (%d)\n", g_pCompilerData->symbolBackup, value_1, value_2, size); |
|||
#endif |
|||
} |
|||
|
|||
bool CompileDatBlocks_EnterByte(unsigned char value) |
|||
{ |
|||
if (EnterObj(value)) |
|||
{ |
|||
if (g_pCompilerData->orgx == 0) |
|||
{ |
|||
g_pCompilerData->cog_org++; |
|||
} |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
bool CompileDatBlocks_Enter(int value, int count, int size) |
|||
{ |
|||
int numBytesPer = 1 << size; |
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
if(!CompileDatBlocks_EnterByte(value & 0x000000FF)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (numBytesPer > 1) |
|||
{ |
|||
if(!CompileDatBlocks_EnterByte((value >> 8) & 0x000000FF)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
if (numBytesPer > 2) |
|||
{ |
|||
if(!CompileDatBlocks_EnterByte((value >> 16) & 0x000000FF)) |
|||
{ |
|||
return false; |
|||
} |
|||
if(!CompileDatBlocks_EnterByte((value >> 24) & 0x000000FF)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool CompileDatBlocks_Advance(bool bSymbol, bool bResSymbol, int size) |
|||
{ |
|||
int testVal = (1 << size) - 1; |
|||
for (;;) |
|||
{ |
|||
if ((g_pCompilerData->obj_ptr & testVal) == 0) |
|||
{ |
|||
if (bSymbol) |
|||
{ |
|||
CompileDatBlocks_EnterSymbol(bResSymbol, size); |
|||
} |
|||
break; |
|||
} |
|||
if (!CompileDatBlocks_EnterByte(0)) // obj_ptr gets incremented in here
|
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool CompileDatBlocks_Data(bool& bEof, int pass, bool bSymbol, bool& bResSymbol, int& size) |
|||
{ |
|||
size = g_pElementizer->GetValue() & 0x000000FF; |
|||
int overrideSize = size; |
|||
|
|||
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() == type_end) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
while (!bEof) |
|||
{ |
|||
// do we have a size override?
|
|||
if (g_pElementizer->GetType() == type_size) |
|||
{ |
|||
// yes, get it
|
|||
overrideSize = g_pElementizer->GetValue() & 0x000000FF; |
|||
if (overrideSize < size) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_sombl]; |
|||
return false; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// no, backup
|
|||
g_pElementizer->Backup(); |
|||
} |
|||
|
|||
// get the value
|
|||
if (!GetTryValue(pass == 1 ? true : false, overrideSize == 2 ? false : true, true)) |
|||
{ |
|||
return false; |
|||
} |
|||
int value = GetResult(); |
|||
|
|||
// get the count
|
|||
int count = 1; |
|||
if (g_pElementizer->CheckElement(type_leftb)) |
|||
{ |
|||
if (!GetTryValue(true, true, true)) |
|||
{ |
|||
return false; |
|||
} |
|||
count = GetResult(); |
|||
if (!g_pElementizer->GetElement(type_rightb)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// enter the value count times into the obj
|
|||
if (!CompileDatBlocks_Enter(value, count, overrideSize)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
bool bComma = false; |
|||
if (!GetCommaOrEnd(bComma)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!bComma) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool CompileDatBlocks_File(bool bSymbol, bool bResSymbol, int& size) |
|||
{ |
|||
size = 0; // force size to byte
|
|||
if (bSymbol) |
|||
{ |
|||
CompileDatBlocks_EnterSymbol(bResSymbol, size); |
|||
} |
|||
|
|||
int filenameStart = 0; |
|||
int filenameFinish = 0; |
|||
if (!GetFilename(filenameStart, filenameFinish)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// find the file in the dat_data array and copy it into obj
|
|||
for (int i = 0; i < g_pCompilerData->dat_files; i++) |
|||
{ |
|||
if (strcmp(&(g_pCompilerData->dat_filenames[256*i]), g_pCompilerData->filename) == 0) |
|||
{ |
|||
// copy dat data into obj (RPE: this should be optimized)
|
|||
for (int j = 0; j < g_pCompilerData->dat_lengths[i]; j++) |
|||
{ |
|||
if (!CompileDatBlocks_EnterByte(g_pCompilerData->dat_data[g_pCompilerData->dat_offsets[i] + j])) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
// file data not found
|
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_idfnf]; |
|||
return false; |
|||
} |
|||
|
|||
bool CompileDatBlocks_AsmDirective(bool bSymbol, bool& bResSymbol, int& size) |
|||
{ |
|||
size = 2; // force to long size
|
|||
|
|||
int directive = g_pElementizer->GetValue() & 0x000000FF; |
|||
switch (directive) |
|||
{ |
|||
case dir_nop: |
|||
{ |
|||
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!CompileDatBlocks_Enter(0, 1, 2)) // enter a 0 long
|
|||
{ |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
break; |
|||
case dir_fit: |
|||
{ |
|||
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size)) |
|||
{ |
|||
return false; |
|||
} |
|||
int fit = 0x1F0; |
|||
if (!g_pElementizer->CheckElement(type_end)) |
|||
{ |
|||
if (!GetTryValue(true, true, true)) |
|||
{ |
|||
return false; |
|||
} |
|||
fit = GetResult(); |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
fit <<= 2; |
|||
if ((unsigned int)(g_pCompilerData->cog_org) > (unsigned int)fit) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_oefl]; |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
break; |
|||
case dir_res: |
|||
{ |
|||
if (g_pCompilerData->orgx != 0) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_rinaiom]; |
|||
return false; |
|||
} |
|||
bResSymbol = true; |
|||
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size)) |
|||
{ |
|||
return false; |
|||
} |
|||
int resSize = 1; |
|||
if (!g_pElementizer->CheckElement(type_end)) |
|||
{ |
|||
if (!GetTryValue(true, true, true)) |
|||
{ |
|||
return false; |
|||
} |
|||
resSize = GetResult(); |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
resSize <<= 2; |
|||
g_pCompilerData->cog_org += resSize; |
|||
if (g_pCompilerData->cog_org > (0x1F0 * 4)) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_oexl]; |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
break; |
|||
case dir_org: |
|||
{ |
|||
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size)) |
|||
{ |
|||
return false; |
|||
} |
|||
int newOrg = 0; |
|||
if (!g_pElementizer->CheckElement(type_end)) |
|||
{ |
|||
if (!GetTryValue(true, true, true)) |
|||
{ |
|||
return false; |
|||
} |
|||
newOrg = GetResult(); |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
if (newOrg > 0x1F0) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_oexl]; |
|||
return false; |
|||
} |
|||
g_pCompilerData->cog_org = newOrg << 2; |
|||
g_pCompilerData->orgx = 0; |
|||
return true; |
|||
} |
|||
break; |
|||
} |
|||
|
|||
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pCompilerData->cog_org = 0; |
|||
g_pCompilerData->orgx = 1; |
|||
return true; |
|||
} |
|||
|
|||
bool CompileDatBlocks_ValidateCallSymbol(bool bIsRet, char* pSymbol) |
|||
{ |
|||
if (!g_pElementizer->FindSymbol(pSymbol)) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eads]; |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() == type_undefined) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[bIsRet ? error_urs : error_us]; |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() < type_dat_byte || g_pElementizer->GetType() > type_dat_long_res) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eads]; |
|||
return false; |
|||
} |
|||
|
|||
// the offset to the label symbol is in second symbol value
|
|||
int value = g_pElementizer->GetValue2(); |
|||
|
|||
// make sure it's long aligned
|
|||
if (value & 0x03) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[bIsRet ? error_rainl : error_ainl]; |
|||
return false; |
|||
} |
|||
// make sure is in range
|
|||
value >>= 2; |
|||
if (value >= 0x1F0) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[bIsRet ? error_raioor : error_aioor]; |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool CompileDatBlocks_AsmInstruction(bool& bEof, int pass, bool bSymbol, bool bResSymbol, int& size, unsigned char condition) |
|||
{ |
|||
size = 2; // force to long size
|
|||
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
int opcode = g_pElementizer->GetValue() & 0x000000FF; |
|||
// handle dual type entries and also AND and OR (which are the only type_binary that will get here)
|
|||
if (g_pElementizer->IsDual() || g_pElementizer->GetType() == type_binary) |
|||
{ |
|||
opcode = g_pElementizer->GetAsm() & 0x000000FF; |
|||
} |
|||
|
|||
unsigned int instruction = opcode << 8; |
|||
|
|||
if (opcode & 0x80) // sys instruction
|
|||
{ |
|||
instruction = 0x03 << 8; |
|||
} |
|||
|
|||
instruction |= condition; |
|||
|
|||
if (opcode & 0x40) // set WR?
|
|||
{ |
|||
instruction |= 0x20; |
|||
} |
|||
|
|||
instruction <<= 18; // justify the instruction (s & d will go in lower 18 bits)
|
|||
|
|||
if (opcode & 0x80) // sys instruction
|
|||
{ |
|||
instruction |= 0x00400000; // set immediate
|
|||
instruction |= (opcode & 0x07); // set s
|
|||
|
|||
// get d
|
|||
if (!GetTryValue(pass == 1 ? true : false, true, true)) |
|||
{ |
|||
return false; |
|||
} |
|||
int d = GetResult(); |
|||
if (d > 0x1FF) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_drcex]; |
|||
return false; |
|||
} |
|||
instruction |= (d << 9); // set d
|
|||
} |
|||
else if (opcode == 0x15) // call?
|
|||
{ |
|||
// make 'jmpret label_ret, #label'
|
|||
instruction ^= 0x08C00000; |
|||
if (!g_pElementizer->GetElement(type_pound)) |
|||
{ |
|||
return false; |
|||
} |
|||
int length = 0; |
|||
if (!GetSymbol(&length)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (length > 0) |
|||
{ |
|||
if (length > symbol_limit - 4) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_csmnexc]; |
|||
return false; |
|||
} |
|||
char* pSymbol = g_pElementizer->GetCurrentSymbol(); |
|||
if (pass == 1) |
|||
{ |
|||
if (!CompileDatBlocks_ValidateCallSymbol(false, pSymbol)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
instruction |= ((g_pElementizer->GetValue2() & 0x7FF) >> 2); // set #label
|
|||
|
|||
pSymbol[length] = '_'; |
|||
pSymbol[length+1] = 'R'; |
|||
pSymbol[length+2] = 'E'; |
|||
pSymbol[length+3] = 'T'; |
|||
pSymbol[length+4] = 0; |
|||
if (pass == 1) |
|||
{ |
|||
if (!CompileDatBlocks_ValidateCallSymbol(true, pSymbol)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
instruction |= (((g_pElementizer->GetValue2() & 0x7FF) >> 2) << 9); // set label_ret
|
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eads]; |
|||
return false; |
|||
} |
|||
} |
|||
else if (opcode == 0x16) // ret?
|
|||
{ |
|||
instruction ^= 0x04400000; // make 'jmp #0'
|
|||
} |
|||
else if (opcode == 0x17) // jmp?
|
|||
{ |
|||
// for jmp, we only get s, there is no d
|
|||
|
|||
// see if it's an immediate value for s
|
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() == type_pound) |
|||
{ |
|||
instruction |= 0x00400000; |
|||
} |
|||
else |
|||
{ |
|||
g_pElementizer->Backup(); |
|||
} |
|||
|
|||
// get s
|
|||
if (!GetTryValue(pass == 1 ? true : false, true, true)) |
|||
{ |
|||
return false; |
|||
} |
|||
int s = GetResult(); |
|||
|
|||
// make sure it's in range
|
|||
if (s > 0x1FF) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_srccex]; |
|||
return false; |
|||
} |
|||
|
|||
// set s on instruction
|
|||
instruction |= s; |
|||
} |
|||
else // regular instruction get both d and s
|
|||
{ |
|||
// get d
|
|||
if (!GetTryValue(pass == 1 ? true : false, true, true)) |
|||
{ |
|||
return false; |
|||
} |
|||
int d = GetResult(); |
|||
|
|||
// make sure it's in range
|
|||
if (d > 0x1FF) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_drcex]; |
|||
return false; |
|||
} |
|||
|
|||
// set d on instruction
|
|||
instruction |= (d << 9); |
|||
|
|||
if (!g_pElementizer->GetElement(type_comma)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// see if it's an immediate value for s
|
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() == type_pound) |
|||
{ |
|||
instruction |= 0x00400000; |
|||
} |
|||
else |
|||
{ |
|||
g_pElementizer->Backup(); |
|||
} |
|||
|
|||
// get s
|
|||
if (!GetTryValue(pass == 1 ? true : false, true, true)) |
|||
{ |
|||
return false; |
|||
} |
|||
int s = GetResult(); |
|||
|
|||
// make sure it's in range
|
|||
if (s > 0x1FF) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_srccex]; |
|||
return false; |
|||
} |
|||
|
|||
// set s on instruction
|
|||
instruction |= s; |
|||
} |
|||
|
|||
// check for effects
|
|||
bool bAfterComma = false; |
|||
while (!bEof) |
|||
{ |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() == type_asm_effect) |
|||
{ |
|||
int effectValue = g_pElementizer->GetValue(); |
|||
|
|||
// don't allow wr/nr for r/w instructions
|
|||
if ((effectValue & 0x09) && (instruction >> 26) <= 2) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_micuwn]; |
|||
return false; |
|||
} |
|||
|
|||
// apply effect to instruction
|
|||
int temp = (effectValue & 0x38) << 20; |
|||
instruction |= temp; |
|||
instruction ^= temp; |
|||
instruction |= ((effectValue & 0x07) << 23); |
|||
|
|||
bool bComma = false; |
|||
if (!GetCommaOrEnd(bComma)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!bComma) |
|||
{ |
|||
// got end, done with effects
|
|||
break; |
|||
} |
|||
|
|||
// got a comma, expecting another effect
|
|||
bAfterComma = true; |
|||
} |
|||
else if (bAfterComma) |
|||
{ |
|||
// expected another effect after the comma
|
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eaasme]; |
|||
return false; |
|||
} |
|||
else if (g_pElementizer->GetType() != type_end) |
|||
{ |
|||
// if it wasn't an effect the first time in then it should be an end
|
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eaaeoeol]; |
|||
return false; |
|||
} |
|||
else |
|||
{ |
|||
// we get here if we got no effect and got the proper end
|
|||
break; |
|||
} |
|||
} |
|||
// enter instruction as 1 long
|
|||
if (!CompileDatBlocks_Enter(instruction, 1, 2)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool CompileDatBlocks_CheckInstruction() |
|||
{ |
|||
if (g_pElementizer->GetType() == type_asm_inst || g_pElementizer->IsDual()) |
|||
{ |
|||
return true; |
|||
} |
|||
if (g_pElementizer->GetType() == type_binary) |
|||
{ |
|||
if (g_pElementizer->GetOpType() == op_log_and || g_pElementizer->GetOpType() == op_log_or) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
bool CompileDatBlocks_AsmCondition(bool& bEof, int pass, bool bSymbol, bool bResSymbol, int& size) |
|||
{ |
|||
unsigned char condition = (unsigned char)(g_pElementizer->GetValue() & 0x000000FF); |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (CompileDatBlocks_CheckInstruction()) |
|||
{ |
|||
return CompileDatBlocks_AsmInstruction(bEof, pass, bSymbol, bResSymbol, size, condition); |
|||
} |
|||
|
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eaasmi]; |
|||
return false; |
|||
} |
|||
|
|||
bool CompileDatBlocks() |
|||
{ |
|||
int infoflag = 0; |
|||
int ptr = g_pCompilerData->obj_ptr; |
|||
int datstart = 0; |
|||
int objstart = 0; |
|||
|
|||
for (int pass = 0; pass < 2; pass++) |
|||
{ |
|||
g_pCompilerData->obj_ptr = ptr; |
|||
g_pCompilerData->asm_local = 0; |
|||
g_pCompilerData->cog_org = 0; |
|||
g_pCompilerData->orgx = 0; |
|||
int size = 0; |
|||
|
|||
bool bEof = false; |
|||
g_pElementizer->Reset(); |
|||
|
|||
while(!bEof) |
|||
{ |
|||
if(g_pElementizer->GetNextBlock(block_dat, bEof)) |
|||
{ |
|||
if (bEof) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
datstart = g_pCompilerData->source_start; |
|||
objstart = g_pCompilerData->obj_ptr; |
|||
|
|||
while (!bEof) |
|||
{ |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (bEof) |
|||
{ |
|||
break; |
|||
} |
|||
infoflag = 1; |
|||
if (g_pElementizer->GetType() == type_end) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
g_pCompilerData->inf_start = g_pCompilerData->source_start; |
|||
|
|||
// clear symbol flags
|
|||
bool bLocal = false; |
|||
bool bSymbol = false; |
|||
bool bResSymbol = false; |
|||
|
|||
if (!CheckLocal(bLocal)) // bLocal will be set if it is a local
|
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
g_pCompilerData->inf_finish = g_pCompilerData->source_finish; |
|||
|
|||
if (g_pElementizer->GetType() == type_undefined) // undefined here means it's a symbol
|
|||
{ |
|||
if (!bLocal) |
|||
{ |
|||
if (!IncrementAsmLocal()) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
bSymbol = true; |
|||
g_pElementizer->BackupSymbol(); |
|||
|
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() == type_end) |
|||
{ |
|||
if (bSymbol) |
|||
{ |
|||
CompileDatBlocks_EnterSymbol(bResSymbol, size); |
|||
} |
|||
continue; |
|||
} |
|||
} |
|||
else if (g_pElementizer->GetType() == type_dat_byte || |
|||
g_pElementizer->GetType() == type_dat_word || |
|||
g_pElementizer->GetType() == type_dat_long || |
|||
g_pElementizer->GetType() == type_dat_long_res) |
|||
{ |
|||
if (!bLocal) |
|||
{ |
|||
if (!IncrementAsmLocal()) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
if (pass == 0) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_siad]; |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() == type_end) |
|||
{ |
|||
continue; |
|||
} |
|||
} |
|||
|
|||
if (g_pElementizer->GetType() == type_size) |
|||
{ |
|||
if (!CompileDatBlocks_Data(bEof, pass, bSymbol, bResSymbol, size)) |
|||
{ |
|||
return false; |
|||
} |
|||
continue; |
|||
} |
|||
else if (g_pElementizer->GetType() == type_file) |
|||
{ |
|||
if (!CompileDatBlocks_File(bSymbol, bResSymbol, size)) |
|||
{ |
|||
return false; |
|||
} |
|||
continue; |
|||
} |
|||
else if (g_pElementizer->GetType() == type_asm_dir) |
|||
{ |
|||
if (!CompileDatBlocks_AsmDirective(bSymbol, bResSymbol, size)) |
|||
{ |
|||
return false; |
|||
} |
|||
continue; |
|||
} |
|||
else if (g_pElementizer->GetType() == type_asm_cond) |
|||
{ |
|||
if (!CompileDatBlocks_AsmCondition(bEof, pass, bSymbol, bResSymbol, size)) |
|||
{ |
|||
return false; |
|||
} |
|||
continue; |
|||
} |
|||
else if (CompileDatBlocks_CheckInstruction()) |
|||
{ |
|||
if (!CompileDatBlocks_AsmInstruction(bEof, pass, bSymbol, bResSymbol, size, if_always)) |
|||
{ |
|||
return false; |
|||
} |
|||
continue; |
|||
} |
|||
|
|||
if (g_pElementizer->GetType() == type_block) |
|||
{ |
|||
g_pElementizer->Backup(); |
|||
if (pass == 0) |
|||
{ |
|||
CompileDatBlocks_EnterInfo(datstart, objstart); |
|||
} |
|||
break; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eaunbwlo]; |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
if (infoflag != 0 && pass == 0) |
|||
{ |
|||
CompileDatBlocks_EnterInfo(datstart, objstart); |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,755 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// CompileExpression.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" |
|||
|
|||
//
|
|||
//************************************************************************
|
|||
//* Expression Compiler *
|
|||
//************************************************************************
|
|||
//
|
|||
// Basic expression syntax rules: i.e. 4000/(||x*5)//127)+1
|
|||
//
|
|||
// Any one of these... Must be followed by any one of these...
|
|||
// ------------------------------------------------------------------
|
|||
// term binary operator
|
|||
// ) )
|
|||
// <end>
|
|||
//
|
|||
// Any one of these... Must be followed by any one of these... *
|
|||
// ------------------------------------------------------------------
|
|||
// unary operator term
|
|||
// binary operator unary operator
|
|||
// ( (
|
|||
//
|
|||
// * initial element of an expression
|
|||
//
|
|||
|
|||
// forward declarations
|
|||
bool CompileTerm(); |
|||
bool CompileSubExpression(int precedence); |
|||
bool CompileTopExpression(); |
|||
|
|||
// Compile expression with sub-expressions
|
|||
bool CompileExpression() |
|||
{ |
|||
if (!CompileTopExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool CompileTopExpression() |
|||
{ |
|||
if (!CompileSubExpression(11)) |
|||
{ |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool CompileSubExpression_Term() |
|||
{ |
|||
// get next element ignoring any leading +'s
|
|||
bool bEof = false; |
|||
do |
|||
{ |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
} while (g_pElementizer->GetType() == type_binary && g_pElementizer->GetOpType() == op_add); |
|||
|
|||
if (!g_pElementizer->NegConToCon()) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pElementizer->SubToNeg(); |
|||
|
|||
int opType = g_pElementizer->GetOpType(); |
|||
|
|||
switch (g_pElementizer->GetType()) |
|||
{ |
|||
case type_atat: |
|||
if (!CompileSubExpression(0)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj(0x97)) // memop byte+index+pbase+address
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj(0)) // address 0
|
|||
{ |
|||
return false; |
|||
} |
|||
break; |
|||
|
|||
case type_unary: |
|||
if (!CompileSubExpression(g_pElementizer->GetValue())) // value = precedence for type_unary
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj((unsigned char)opType | 0xE0)) // math
|
|||
{ |
|||
return false; |
|||
} |
|||
break; |
|||
|
|||
case type_left: |
|||
if (!CompileTopExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_right)) |
|||
{ |
|||
return false; |
|||
} |
|||
break; |
|||
|
|||
default: |
|||
if (!CompileTerm()) |
|||
{ |
|||
return false; |
|||
} |
|||
break; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool CompileSubExpression(int precedence) |
|||
{ |
|||
precedence--; |
|||
if (precedence < 0) |
|||
{ |
|||
if (!CompileSubExpression_Term()) |
|||
{ |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
else |
|||
{ |
|||
if (!CompileSubExpression(precedence)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
for (;;) |
|||
{ |
|||
bool bEof = false; |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() != type_binary) |
|||
{ |
|||
g_pElementizer->Backup(); |
|||
break; |
|||
} |
|||
// if we got here then it's type_binary (so the value is the precedence)
|
|||
if (g_pElementizer->GetValue() != precedence) |
|||
{ |
|||
g_pElementizer->Backup(); |
|||
break; |
|||
} |
|||
int opType = g_pElementizer->GetOpType(); |
|||
if (!CompileSubExpression(precedence)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj((unsigned char)(opType | 0xE0))) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
////////////////////////////////////////////////////////////////
|
|||
|
|||
//
|
|||
// CompileTerm functions
|
|||
//
|
|||
|
|||
// compile constant(constantexpression)
|
|||
bool CompileTerm_ConExp() |
|||
{ |
|||
if (!g_pElementizer->GetElement(type_left)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!GetTryValue(true, false)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!CompileConstant(GetResult())) |
|||
{ |
|||
return false; |
|||
} |
|||
return g_pElementizer->GetElement(type_right); |
|||
} |
|||
|
|||
// compile string("constantstring")
|
|||
bool CompileTerm_ConStr() |
|||
{ |
|||
if (g_pCompilerData->str_enable == false) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_snah]; |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_left)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!StringConstant_GetIndex()) // get index in g_pCompilerData->str_index
|
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// get the string into the string constant buffer
|
|||
for (;;) |
|||
{ |
|||
if (!GetTryValue(true, false)) |
|||
{ |
|||
return false; |
|||
} |
|||
int value = GetResult(); |
|||
if (g_pCompilerData->intMode == 2 || value == 0 || value > 0xFF) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_scmr]; |
|||
return false; |
|||
} |
|||
if (!StringConstant_EnterChar((unsigned char)(value & 0xFF))) // add character to string constant buffer
|
|||
{ |
|||
return false; |
|||
} |
|||
// more characters?
|
|||
bool bComma = false; |
|||
if (!GetCommaOrRight(bComma)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!bComma) |
|||
{ |
|||
// got right ')'
|
|||
break; |
|||
} |
|||
} |
|||
StringConstant_EnterChar(0); // enter 0 terminator into string constant buffer
|
|||
|
|||
if (!EnterObj(0x87)) // (memcp byte+pbase+address)
|
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
StringConstant_EnterPatch(); // enter string constant patch address
|
|||
|
|||
// enter two address bytes (patched later)
|
|||
if (!EnterObj(0x80)) |
|||
{ |
|||
return false; |
|||
} |
|||
return EnterObj(0); |
|||
} |
|||
|
|||
// compile float(integer)/round(float)/trunc(float)
|
|||
bool CompileTerm_FloatRoundTrunc() |
|||
{ |
|||
g_pElementizer->Backup(); // backup to float/round/trunc
|
|||
|
|||
if (!GetTryValue(true, false)) |
|||
{ |
|||
return false; |
|||
} |
|||
return CompileConstant(GetResult()); |
|||
} |
|||
|
|||
bool CompileTerm_Sub(unsigned char anchor, int value) |
|||
{ |
|||
if (!EnterObj(anchor)) // drop anchor
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!CompileParameters((value & 0x0000FF00) >> 8)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj(0x05)) // call sub
|
|||
{ |
|||
return false; |
|||
} |
|||
return EnterObj((unsigned char)(value & 0xFF)); // index of sub
|
|||
} |
|||
|
|||
// compile obj[].pub
|
|||
bool CompileTerm_ObjPub(unsigned char anchor, int value) |
|||
{ |
|||
if (!EnterObj(anchor)) // drop anchor
|
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// check for [index]
|
|||
bool bIndex = false; |
|||
int expSourcePtr = 0; |
|||
if (!CheckIndex(bIndex, expSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!g_pElementizer->GetElement(type_dot)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// lookup the pub symbol
|
|||
if (!GetObjSymbol(type_objpub, (char)((value & 0x0000FF00) >> 8))) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
int objPubValue = g_pElementizer->GetValue(); |
|||
|
|||
// compile any parameters the pub has
|
|||
if (!CompileParameters((objPubValue & 0x0000FF00) >> 8)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
unsigned char byteCode = 0x06; // call obj.pub
|
|||
if (bIndex) |
|||
{ |
|||
if (!CompileOutOfSequenceExpression(expSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
byteCode = 0x07; // call obj[].pub
|
|||
} |
|||
if (!EnterObj(byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!EnterObj((unsigned char)(value & 0xFF))) // index of obj
|
|||
{ |
|||
return false; |
|||
} |
|||
return EnterObj((unsigned char)(objPubValue & 0xFF)); // index of objpub
|
|||
} |
|||
|
|||
// compile obj[].pub\obj[]#con
|
|||
bool CompileTerm_ObjPubCon(int value) |
|||
{ |
|||
if (!g_pElementizer->CheckElement(type_pound)) // check for obj#con
|
|||
{ |
|||
// not obj#con, so do obj[].pub
|
|||
return CompileTerm_ObjPub(0, value); |
|||
} |
|||
// lookup the symbol to get the value to compile
|
|||
if (!GetObjSymbol(type_objcon, (char)((value & 0x0000FF00) >> 8))) |
|||
{ |
|||
return false; |
|||
} |
|||
return CompileConstant(g_pElementizer->GetValue()); |
|||
} |
|||
|
|||
// compile \sub or \obj
|
|||
bool CompileTerm_Try(unsigned char anchor) |
|||
{ |
|||
bool bEof = false; |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() == type_sub) |
|||
{ |
|||
return CompileTerm_Sub(anchor, g_pElementizer->GetValue()); |
|||
} |
|||
else if (g_pElementizer->GetType() == type_obj) |
|||
{ |
|||
return CompileTerm_ObjPub(anchor, g_pElementizer->GetValue()); |
|||
} |
|||
|
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_easoon]; |
|||
return false; |
|||
} |
|||
|
|||
bool CompileLook(int column, int param) |
|||
{ |
|||
column = column; // stop warning
|
|||
|
|||
param &= 0xFF; // we only care about the bottom byte
|
|||
|
|||
unsigned char byteCode = 0x35; // constant 0
|
|||
if (param < 0x80) // zero based?
|
|||
{ |
|||
byteCode += 1; // not, so make it a constant 1
|
|||
} |
|||
if (!EnterObj(byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!BlockStack_CompileConstant()) // enter address constant
|
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!g_pElementizer->GetElement(type_left)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!CompileExpression()) // compile primary value
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_colon)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
for (;;) |
|||
{ |
|||
bool bRange = false; |
|||
if (!CompileRange(bRange)) // compile (next) value/range
|
|||
{ |
|||
return false; |
|||
} |
|||
byteCode = (unsigned char)param; |
|||
if (bRange) |
|||
{ |
|||
byteCode |= 2; |
|||
} |
|||
if (!EnterObj(byteCode & 0x7F)) |
|||
{ |
|||
return false; |
|||
} |
|||
bool bComma = false; |
|||
if (!GetCommaOrRight(bComma)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!bComma) |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (!EnterObj(0x0F)) // lookdone
|
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
BlockStack_Write(0, g_pCompilerData->obj_ptr); // set address
|
|||
return true; |
|||
} |
|||
|
|||
// compile 'lookup'/'lookdown'
|
|||
// this one compiles like a block (see InstructionBlockCompiler.cpp stuff)
|
|||
bool CompileTerm_Look(int value) |
|||
{ |
|||
if (!BlockNest_New(type_i_look, 1)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!OptimizeBlock(0, value, &CompileLook)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
BlockNest_End(); |
|||
return true; |
|||
} |
|||
|
|||
bool CompileTerm_ClkMode() |
|||
{ |
|||
if (!EnterObj(0x38)) // constant 4
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj(4)) |
|||
{ |
|||
return false; |
|||
} |
|||
return EnterObj(0x80); // read byte[]
|
|||
} |
|||
|
|||
bool CompileTerm_ClkFreq() |
|||
{ |
|||
if (!EnterObj(0x35)) // constant 0
|
|||
{ |
|||
return false; |
|||
} |
|||
return EnterObj(0xC0); // read long[]
|
|||
} |
|||
|
|||
bool CompileTerm_ChipVer() |
|||
{ |
|||
if (!EnterObj(0x34)) // constant -1
|
|||
{ |
|||
return false; |
|||
} |
|||
return EnterObj(0x80); // read byte[]
|
|||
} |
|||
|
|||
bool CompileTerm_CogId() |
|||
{ |
|||
if (!EnterObj(0x3F)) // reg op
|
|||
{ |
|||
return false; |
|||
} |
|||
return EnterObj(0x89); // read id
|
|||
} |
|||
|
|||
bool CompileTerm_Inst(int value) |
|||
{ |
|||
if (!CompileParameters((value & 0xFF) >> 6)) |
|||
{ |
|||
return false; |
|||
} |
|||
return EnterObj((unsigned char)(value & 0x3F)); // instruction
|
|||
} |
|||
|
|||
bool CompileTerm_CogNew(int value) |
|||
{ |
|||
// see if first param is a sub
|
|||
if (!g_pElementizer->GetElement(type_left)) |
|||
{ |
|||
return false; |
|||
} |
|||
bool bEof = false; |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() == type_sub) |
|||
{ |
|||
int subConstant = g_pElementizer->GetValue(); |
|||
|
|||
if (!g_pCompilerData->bFinalCompile && g_pCompilerData->bUnusedMethodElimination) |
|||
{ |
|||
AddCogNewOrInit(g_pCompilerData->current_filename, subConstant & 0x000000FF); |
|||
} |
|||
|
|||
// it is a sub, so compile as cognew(subname(params),stack)
|
|||
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; |
|||
} |
|||
return EnterObj((unsigned char)(value & 0x3F)); // coginit
|
|||
} |
|||
|
|||
// it is not a sub, so backup and compile as cognew(address, parameter)
|
|||
g_pElementizer->Backup(); |
|||
g_pElementizer->Backup(); |
|||
|
|||
if (!EnterObj(0x34)) // constant -1
|
|||
{ |
|||
return false; |
|||
} |
|||
return CompileTerm_Inst(value); |
|||
} |
|||
|
|||
// compile @var
|
|||
bool CompileTerm_At() |
|||
{ |
|||
unsigned char varType = 0; |
|||
unsigned char varSize = 0; |
|||
int varAddress = 0; |
|||
int varIndexSourcePtr = 0; |
|||
if (!GetVariable(varType, varSize, varAddress, varIndexSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (varType == type_reg || varType == type_spr) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eamvaa]; |
|||
return false; |
|||
} |
|||
return CompileVariable(3, 0, varType, varSize, varAddress, varIndexSourcePtr); |
|||
} |
|||
|
|||
bool CompileTerm() |
|||
{ |
|||
int type = g_pElementizer->GetType(); |
|||
int value = g_pElementizer->GetValue(); |
|||
|
|||
switch(type) |
|||
{ |
|||
case type_con: |
|||
case type_con_float: |
|||
return CompileConstant(value); |
|||
case type_conexp: |
|||
return CompileTerm_ConExp(); |
|||
case type_constr: |
|||
return CompileTerm_ConStr(); |
|||
case type_float: |
|||
case type_round: |
|||
case type_trunc: |
|||
return CompileTerm_FloatRoundTrunc(); |
|||
case type_back: |
|||
return CompileTerm_Try(0x02); |
|||
case type_sub: |
|||
return CompileTerm_Sub(0, value); |
|||
case type_obj: |
|||
return CompileTerm_ObjPubCon(value); |
|||
case type_i_look: |
|||
return CompileTerm_Look(value); |
|||
case type_i_clkmode: |
|||
return CompileTerm_ClkMode(); |
|||
case type_i_clkfreq: |
|||
return CompileTerm_ClkFreq(); |
|||
case type_i_chipver: |
|||
return CompileTerm_ChipVer(); |
|||
case type_i_cogid: |
|||
return CompileTerm_CogId(); |
|||
case type_i_cognew: |
|||
return CompileTerm_CogNew(value); |
|||
case type_i_ar: // instruction always-returns
|
|||
case type_i_cr: // instruction can-return
|
|||
return CompileTerm_Inst(value); |
|||
case type_at: // @var
|
|||
return CompileTerm_At(); |
|||
case type_inc: // assign pre-inc w/push ++var
|
|||
return CompileVariable_PreIncOrDec(0xA0); |
|||
case type_dec: // assign pre-dec w/push --var
|
|||
return CompileVariable_PreIncOrDec(0xB0); |
|||
case type_til: // assign sign-extern byte w/push ~var
|
|||
return CompileVariable_PreSignExtendOrRandom(0x90); |
|||
case type_tiltil: // assign sign-extern word w/push ~~var
|
|||
return CompileVariable_PreSignExtendOrRandom(0x94); |
|||
case type_rnd: // assign random forward w/push ?var
|
|||
return CompileVariable_PreSignExtendOrRandom(0x88); |
|||
} |
|||
|
|||
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_eaet]; |
|||
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 w/push var++
|
|||
return CompileVariable_IncOrDec(0xA8, varType, varSize, varAddress, varIndexSourcePtr); |
|||
case type_dec: // assign post-dec w/push var--
|
|||
return CompileVariable_IncOrDec(0xB8, varType, varSize, varAddress, varIndexSourcePtr); |
|||
case type_rnd: // assign random reverse w/push var?
|
|||
return CompileVariable_Assign(0x8C, varType, varSize, varAddress, varIndexSourcePtr); |
|||
case type_til: // assign post-clear w/push var~
|
|||
return CompileVariable_Assign(0x98, varType, varSize, varAddress, varIndexSourcePtr); |
|||
case type_tiltil: // assign post-set w/push var~~
|
|||
return CompileVariable_Assign(0x9C, varType, varSize, varAddress, varIndexSourcePtr); |
|||
case type_assign: // assign write w/push var :=
|
|||
return CompileVariable_Expression(0x80, varType, varSize, varAddress, varIndexSourcePtr); |
|||
} |
|||
|
|||
unsigned char varOperator = 0x80; // assign write w/push
|
|||
// var binaryop?
|
|||
if (type == type_binary) |
|||
{ |
|||
varOperator = 0xC0; // assign math w/swapargs w/push
|
|||
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
|
|||
return CompileVariable(0, varOperator, varType, varSize, varAddress, varIndexSourcePtr); |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,404 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,768 @@ |
|||
///////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
|
|||
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|||
// See end of file for terms of use. //
|
|||
// //
|
|||
///////////////////////////////////////////////////////////////
|
|||
//
|
|||
// CompileSpin.cpp
|
|||
//
|
|||
|
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
#include "CompileSpin.h" |
|||
#include "PropellerCompiler.h" |
|||
#include "objectheap.h" |
|||
#include "textconvert.h" |
|||
#include "preprocess.h" |
|||
#include "Utilities.h" |
|||
|
|||
#define ObjFileStackLimit 16 |
|||
#define ListLimit 2000000 |
|||
#define DocLimit 2000000 |
|||
|
|||
static struct preprocess s_preprocessor; |
|||
CompilerData* s_pCompilerData = 0; |
|||
static int s_nObjStackPtr = 0; |
|||
static bool s_bFinalCompile; |
|||
|
|||
static CompilerConfig s_compilerConfig; |
|||
static LoadFileFunc s_pLoadFileFunc = 0; |
|||
static FreeFileBufferFunc s_pFreeFileBufferFunc = 0; |
|||
static unsigned char* s_pCompileResultBuffer = 0; |
|||
|
|||
static Heirarchy s_objectHeirarchy; |
|||
|
|||
class ObjectNode : public HeirarchyNode |
|||
{ |
|||
public: |
|||
char* m_pFullPath; |
|||
|
|||
ObjectNode() |
|||
: m_pFullPath(0) |
|||
{ |
|||
} |
|||
}; |
|||
|
|||
static bool GetPASCIISource(char* pFilename) |
|||
{ |
|||
// read in file to temp buffer, convert to PASCII, and assign to s_pCompilerData->source
|
|||
int nLength = 0; |
|||
char* pRawBuffer = s_pLoadFileFunc(pFilename, &nLength, &s_pCompilerData->current_file_path); |
|||
if (pRawBuffer) |
|||
{ |
|||
char* pBuffer = 0; |
|||
if (s_compilerConfig.bUsePreprocessor) |
|||
{ |
|||
memoryfile mfile; |
|||
mfile.buffer = pRawBuffer; |
|||
mfile.length = nLength; |
|||
mfile.readoffset = 0; |
|||
pp_push_file_struct(&s_preprocessor, &mfile, pFilename); |
|||
pp_run(&s_preprocessor); |
|||
pBuffer = pp_finish(&s_preprocessor); |
|||
nLength = (int)strlen(pBuffer); |
|||
if (nLength == 0) |
|||
{ |
|||
free(pBuffer); |
|||
pBuffer = 0; |
|||
} |
|||
s_pFreeFileBufferFunc(pRawBuffer); |
|||
} |
|||
else |
|||
{ |
|||
pBuffer = pRawBuffer; |
|||
} |
|||
|
|||
char* pPASCIIBuffer = new char[nLength+1]; |
|||
memset(pPASCIIBuffer, 0, nLength + 1); |
|||
if (!UnicodeToPASCII(pBuffer, nLength, pPASCIIBuffer, s_compilerConfig.bUsePreprocessor)) |
|||
{ |
|||
printf("Unrecognized text encoding format!\n"); |
|||
delete [] pPASCIIBuffer; |
|||
if (s_compilerConfig.bUsePreprocessor) |
|||
{ |
|||
free(pBuffer); |
|||
} |
|||
else |
|||
{ |
|||
s_pFreeFileBufferFunc(pRawBuffer); |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
// clean up any previous buffer
|
|||
if (s_pCompilerData->source) |
|||
{ |
|||
delete [] s_pCompilerData->source; |
|||
} |
|||
|
|||
s_pCompilerData->source = pPASCIIBuffer; |
|||
|
|||
if (s_compilerConfig.bUsePreprocessor) |
|||
{ |
|||
free(pBuffer); |
|||
} |
|||
else |
|||
{ |
|||
s_pFreeFileBufferFunc(pRawBuffer); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
s_pCompilerData->source = NULL; |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
static void CleanupMemory(bool bUnusedMethodData = true) |
|||
{ |
|||
delete s_objectHeirarchy.m_pRoot; |
|||
s_objectHeirarchy.m_pRoot = 0; |
|||
|
|||
if ( s_pCompilerData ) |
|||
{ |
|||
delete [] s_pCompilerData->list; |
|||
delete [] s_pCompilerData->doc; |
|||
delete [] s_pCompilerData->obj; |
|||
delete [] s_pCompilerData->source; |
|||
} |
|||
CleanObjectHeap(); |
|||
if (bUnusedMethodData) |
|||
{ |
|||
CleanUpUnusedMethodData(); |
|||
} |
|||
Cleanup(); |
|||
if (s_pCompileResultBuffer != 0) |
|||
{ |
|||
delete [] s_pCompileResultBuffer; |
|||
s_pCompileResultBuffer = 0; |
|||
} |
|||
} |
|||
|
|||
void PrintError(const char* pFilename, const char* pErrorString) |
|||
{ |
|||
int lineNumber = 1; |
|||
int column = 1; |
|||
int offsetToStartOfLine = -1; |
|||
int offsetToEndOfLine = -1; |
|||
int offendingItemStart = 0; |
|||
int offendingItemEnd = 0; |
|||
|
|||
GetErrorInfo(lineNumber, column, offsetToStartOfLine, offsetToEndOfLine, offendingItemStart, offendingItemEnd); |
|||
|
|||
printf("%s(%d:%d) : error : %s\n", pFilename, lineNumber, column, pErrorString); |
|||
|
|||
if ( offendingItemStart == offendingItemEnd && s_pCompilerData->source[offendingItemStart] == 0 ) |
|||
{ |
|||
printf("Line:\nEnd Of File\nOffending Item: N/A\n"); |
|||
} |
|||
else |
|||
{ |
|||
char* errorLine = 0; |
|||
char* errorItem = 0; |
|||
|
|||
if (offendingItemEnd - offendingItemStart > 0) |
|||
{ |
|||
errorLine = new char[(offsetToEndOfLine - offsetToStartOfLine) + 1]; |
|||
strncpy(errorLine, &s_pCompilerData->source[offsetToStartOfLine], offsetToEndOfLine - offsetToStartOfLine); |
|||
errorLine[offsetToEndOfLine - offsetToStartOfLine] = 0; |
|||
} |
|||
|
|||
if (offendingItemEnd - offendingItemStart > 0) |
|||
{ |
|||
errorItem = new char[(offendingItemEnd - offendingItemStart) + 1]; |
|||
strncpy(errorItem, &s_pCompilerData->source[offendingItemStart], offendingItemEnd - offendingItemStart); |
|||
errorItem[offendingItemEnd - offendingItemStart] = 0; |
|||
} |
|||
|
|||
printf("Line:\n%s\nOffending Item: %s\n", errorLine ? errorLine : "N/A", errorItem ? errorItem : "N/A"); |
|||
|
|||
delete [] errorLine; |
|||
delete [] errorItem; |
|||
} |
|||
} |
|||
|
|||
static bool CheckForCircularReference(ObjectNode* pObjectNode) |
|||
{ |
|||
ObjectNode* pCurrentNode = pObjectNode; |
|||
while (pCurrentNode->m_pParent) |
|||
{ |
|||
ObjectNode* pParent = (ObjectNode*)(pCurrentNode->m_pParent); |
|||
if (strcmp(pObjectNode->m_pFullPath, pParent->m_pFullPath) == 0) |
|||
{ |
|||
return true; |
|||
} |
|||
pCurrentNode = pParent; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
static bool CompileRecursively(char* pFilename, int& nCompileIndex, ObjectNode* pParentNode) |
|||
{ |
|||
nCompileIndex++; |
|||
if (s_nObjStackPtr > 0 && (!s_compilerConfig.bQuiet || s_compilerConfig.bFileTreeOutputOnly)) |
|||
{ |
|||
// only do this if UME is off or if it's the final compile when UME is on
|
|||
if (!s_compilerConfig.bUnusedMethodElimination || s_pCompilerData->bFinalCompile) |
|||
{ |
|||
char spaces[] = " \0"; |
|||
printf("%s|-%s\n", &spaces[32-(s_nObjStackPtr<<1)], pFilename); |
|||
} |
|||
} |
|||
s_nObjStackPtr++; |
|||
if (s_nObjStackPtr > ObjFileStackLimit) |
|||
{ |
|||
printf("%s : error : Object nesting exceeds limit of %d levels.\n", pFilename, ObjFileStackLimit); |
|||
return false; |
|||
} |
|||
|
|||
void *definestate = 0; |
|||
if (s_compilerConfig.bUsePreprocessor) |
|||
{ |
|||
definestate = pp_get_define_state(&s_preprocessor); |
|||
} |
|||
if (!GetPASCIISource(pFilename)) |
|||
{ |
|||
printf("%s : error : Can not find/open file.\n", pFilename); |
|||
return false; |
|||
} |
|||
|
|||
if (!s_pCompilerData->bFinalCompile && s_compilerConfig.bUnusedMethodElimination) |
|||
{ |
|||
AddObjectName(pFilename, nCompileIndex); |
|||
} |
|||
|
|||
strcpy(s_pCompilerData->current_filename, pFilename); |
|||
char* pExtension = strstr(s_pCompilerData->current_filename, ".spin"); |
|||
if (pExtension != 0) |
|||
{ |
|||
*pExtension = 0; |
|||
} |
|||
|
|||
ObjectNode* pObjectNode = new ObjectNode(); |
|||
pObjectNode->m_pFullPath = s_pCompilerData->current_file_path; |
|||
pObjectNode->m_pParent = pParentNode; |
|||
s_objectHeirarchy.AddNode(pObjectNode, pParentNode); |
|||
if (CheckForCircularReference(pObjectNode)) |
|||
{ |
|||
printf("%s : error : Illegal Circular Reference\n", pFilename); |
|||
return false; |
|||
} |
|||
|
|||
// first pass on object
|
|||
const char* pErrorString = Compile1(); |
|||
if (pErrorString != 0) |
|||
{ |
|||
PrintError(pFilename, pErrorString); |
|||
return false; |
|||
} |
|||
|
|||
if (s_pCompilerData->obj_files > 0) |
|||
{ |
|||
char filenames[file_limit*256]; |
|||
|
|||
int numObjects = s_pCompilerData->obj_files; |
|||
for (int i = 0; i < numObjects; i++) |
|||
{ |
|||
// copy the obj filename appending .spin if it doesn't have it.
|
|||
strcpy(&filenames[i<<8], &(s_pCompilerData->obj_filenames[i<<8])); |
|||
if (strstr(&filenames[i<<8], ".spin") == NULL) |
|||
{ |
|||
strcat(&filenames[i<<8], ".spin"); |
|||
} |
|||
} |
|||
|
|||
for (int i = 0; i < numObjects; i++) |
|||
{ |
|||
if (!CompileRecursively(&filenames[i<<8], nCompileIndex, pObjectNode)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// redo first pass on parent object
|
|||
if (s_compilerConfig.bUsePreprocessor) |
|||
{ |
|||
// undo any defines in sub-objects
|
|||
pp_restore_define_state(&s_preprocessor, definestate); |
|||
} |
|||
if (!GetPASCIISource(pFilename)) |
|||
{ |
|||
printf("%s : error : Can not find/open file.\n", pFilename); |
|||
return false; |
|||
} |
|||
|
|||
strcpy(s_pCompilerData->current_filename, pFilename); |
|||
pExtension = strstr(s_pCompilerData->current_filename, ".spin"); |
|||
if (pExtension != 0) |
|||
{ |
|||
*pExtension = 0; |
|||
} |
|||
pErrorString = Compile1(); |
|||
if (pErrorString != 0) |
|||
{ |
|||
PrintError(pFilename, pErrorString); |
|||
return false; |
|||
} |
|||
|
|||
if (!CopyObjectsFromHeap(s_pCompilerData, filenames)) |
|||
{ |
|||
printf("%s : error : Object files exceed 128k.\n", pFilename); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// load all DAT files
|
|||
if (s_pCompilerData->dat_files > 0) |
|||
{ |
|||
int p = 0; |
|||
for (int i = 0; i < s_pCompilerData->dat_files; i++) |
|||
{ |
|||
// Get DAT's Files
|
|||
|
|||
// Get name information
|
|||
char filename[256]; |
|||
strcpy(&filename[0], &(s_pCompilerData->dat_filenames[i<<8])); |
|||
|
|||
// Load file and add to dat_data buffer
|
|||
s_pCompilerData->dat_lengths[i] = -1; |
|||
char* pFilePath = 0; |
|||
char* pBuffer = s_pLoadFileFunc(&filename[0], &s_pCompilerData->dat_lengths[i], &pFilePath); |
|||
|
|||
if (s_pCompilerData->dat_lengths[i] == -1) |
|||
{ |
|||
s_pCompilerData->dat_lengths[i] = 0; |
|||
printf("Cannot find/open dat file: %s \n", &filename[0]); |
|||
return false; |
|||
} |
|||
if (p + s_pCompilerData->dat_lengths[i] > data_limit) |
|||
{ |
|||
printf("%s : error : DAT files exceed 128k.\n", pFilename); |
|||
return false; |
|||
} |
|||
memcpy(&(s_pCompilerData->dat_data[p]), pBuffer, s_pCompilerData->dat_lengths[i]); |
|||
s_pFreeFileBufferFunc(pBuffer); |
|||
s_pCompilerData->dat_offsets[i] = p; |
|||
p += s_pCompilerData->dat_lengths[i]; |
|||
} |
|||
} |
|||
|
|||
// second pass of object
|
|||
pErrorString = Compile2(); |
|||
if (pErrorString != 0) |
|||
{ |
|||
PrintError(pFilename, pErrorString); |
|||
return false; |
|||
} |
|||
|
|||
// only do this check if UME is off or if it's the final compile when UME is on
|
|||
if (!s_compilerConfig.bUnusedMethodElimination || s_pCompilerData->bFinalCompile) |
|||
{ |
|||
// Check to make sure object fits into 32k (or eeprom size if specified as larger than 32k)
|
|||
unsigned int i = 0x10 + s_pCompilerData->psize + s_pCompilerData->vsize + (s_pCompilerData->stack_requirement << 2); |
|||
if ((s_pCompilerData->compile_mode == 0) && (i > s_pCompilerData->eeprom_size)) |
|||
{ |
|||
printf("%s : error : Object exceeds runtime memory limit by %d longs.\n", pFilename, (i - s_pCompilerData->eeprom_size) >> 2); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// save this object in the heap
|
|||
if (!AddObjectToHeap(pFilename, s_pCompilerData)) |
|||
{ |
|||
printf("%s : error : Object Heap Overflow.\n", pFilename); |
|||
return false; |
|||
} |
|||
s_nObjStackPtr--; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
static bool ComposeRAM(unsigned char** ppBuffer, int& bufferSize) |
|||
{ |
|||
if (!s_compilerConfig.bDATonly) |
|||
{ |
|||
unsigned int varsize = s_pCompilerData->vsize; // variable size (in bytes)
|
|||
unsigned int codsize = s_pCompilerData->psize; // code size (in bytes)
|
|||
unsigned int pubaddr = *((unsigned short*)&(s_pCompilerData->obj[8])); // address of first public method
|
|||
unsigned int publocs = *((unsigned short*)&(s_pCompilerData->obj[10])); // number of stack variables (locals), in bytes, for the first public method
|
|||
unsigned int pbase = 0x0010; // base of object code
|
|||
unsigned int vbase = pbase + codsize; // variable base = object base + code size
|
|||
unsigned int dbase = vbase + varsize + 8; // data base = variable base + variable size + 8
|
|||
unsigned int pcurr = pbase + pubaddr; // Current program start = object base + public address (first public method)
|
|||
unsigned int dcurr = dbase + 4 + (s_pCompilerData->first_pub_parameters << 2) + publocs; // current data stack pointer = data base + 4 + FirstParams*4 + publocs
|
|||
|
|||
if (s_compilerConfig.bBinary) |
|||
{ |
|||
// reset ram
|
|||
*ppBuffer = new unsigned char[vbase]; |
|||
memset(*ppBuffer, 0, vbase); |
|||
bufferSize = vbase; |
|||
} |
|||
else |
|||
{ |
|||
if (vbase + 8 > s_compilerConfig.eeprom_size) |
|||
{ |
|||
printf("ERROR: eeprom size exceeded by %d longs.\n", (vbase + 8 - s_compilerConfig.eeprom_size) >> 2); |
|||
return false; |
|||
} |
|||
// reset ram
|
|||
*ppBuffer = new unsigned char[s_compilerConfig.eeprom_size]; |
|||
memset(*ppBuffer, 0, s_compilerConfig.eeprom_size); |
|||
bufferSize = s_compilerConfig.eeprom_size; |
|||
(*ppBuffer)[dbase-8] = 0xFF; |
|||
(*ppBuffer)[dbase-7] = 0xFF; |
|||
(*ppBuffer)[dbase-6] = 0xF9; |
|||
(*ppBuffer)[dbase-5] = 0xFF; |
|||
(*ppBuffer)[dbase-4] = 0xFF; |
|||
(*ppBuffer)[dbase-3] = 0xFF; |
|||
(*ppBuffer)[dbase-2] = 0xF9; |
|||
(*ppBuffer)[dbase-1] = 0xFF; |
|||
} |
|||
|
|||
// set clock frequency and clock mode
|
|||
*((int*)&((*ppBuffer)[0])) = s_pCompilerData->clkfreq; |
|||
(*ppBuffer)[4] = s_pCompilerData->clkmode; |
|||
|
|||
// set interpreter parameters
|
|||
((unsigned short*)&((*ppBuffer)[4]))[1] = (unsigned short)pbase; // always 0x0010
|
|||
((unsigned short*)&((*ppBuffer)[4]))[2] = (unsigned short)vbase; |
|||
((unsigned short*)&((*ppBuffer)[4]))[3] = (unsigned short)dbase; |
|||
((unsigned short*)&((*ppBuffer)[4]))[4] = (unsigned short)pcurr; |
|||
((unsigned short*)&((*ppBuffer)[4]))[5] = (unsigned short)dcurr; |
|||
|
|||
// set code
|
|||
memcpy(&((*ppBuffer)[pbase]), &(s_pCompilerData->obj[4]), codsize); |
|||
|
|||
// install ram checksum byte
|
|||
unsigned char sum = 0; |
|||
for (unsigned int i = 0; i < vbase; i++) |
|||
{ |
|||
sum = sum + (*ppBuffer)[i]; |
|||
} |
|||
(*ppBuffer)[5] = (unsigned char)((-(sum+2028)) ); |
|||
} |
|||
else |
|||
{ |
|||
unsigned int objsize = *((unsigned short*)&(s_pCompilerData->obj[4])); |
|||
if (s_pCompilerData->psize > 65535) |
|||
{ |
|||
objsize = s_pCompilerData->psize; |
|||
} |
|||
unsigned int size = objsize - 4 - (s_pCompilerData->obj[7] * 4); |
|||
*ppBuffer = new unsigned char[size]; |
|||
bufferSize = size; |
|||
memcpy(&((*ppBuffer)[0]), &(s_pCompilerData->obj[8 + (s_pCompilerData->obj[7] * 4)]), size); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
static void DumpSymbols() |
|||
{ |
|||
for (int i = 0; i < s_pCompilerData->info_count; i++) |
|||
{ |
|||
char szTemp[256]; |
|||
szTemp[0] = '*'; |
|||
szTemp[1] = 0; |
|||
int length = 0; |
|||
int start = 0; |
|||
if (s_pCompilerData->info_type[i] == info_pub || s_pCompilerData->info_type[i] == info_pri) |
|||
{ |
|||
length = s_pCompilerData->info_data3[i] - s_pCompilerData->info_data2[i]; |
|||
start = s_pCompilerData->info_data2[i]; |
|||
} |
|||
else if (s_pCompilerData->info_type[i] != info_dat && s_pCompilerData->info_type[i] != info_dat_symbol) |
|||
{ |
|||
length = s_pCompilerData->info_finish[i] - s_pCompilerData->info_start[i]; |
|||
start = s_pCompilerData->info_start[i]; |
|||
} |
|||
|
|||
if (length > 0 && length < 256) |
|||
{ |
|||
strncpy(szTemp, &s_pCompilerData->source[start], length); |
|||
szTemp[length] = 0; |
|||
} |
|||
|
|||
switch(s_pCompilerData->info_type[i]) |
|||
{ |
|||
case info_con: |
|||
printf("CON, %s, %d\n", szTemp, s_pCompilerData->info_data0[i]); |
|||
break; |
|||
case info_con_float: |
|||
printf("CONF, %s, %f\n", szTemp, *((float*)&(s_pCompilerData->info_data0[i]))); |
|||
break; |
|||
case info_pub_param: |
|||
{ |
|||
char szTemp2[256]; |
|||
szTemp2[0] = '*'; |
|||
szTemp2[1] = 0; |
|||
length = s_pCompilerData->info_data3[i] - s_pCompilerData->info_data2[i]; |
|||
start = s_pCompilerData->info_data2[i]; |
|||
if (length > 0 && length < 256) |
|||
{ |
|||
strncpy(szTemp2, &s_pCompilerData->source[start], length); |
|||
szTemp2[length] = 0; |
|||
} |
|||
printf("PARAM, %s, %s, %d, %d\n", szTemp2, szTemp, s_pCompilerData->info_data0[i], s_pCompilerData->info_data1[i]); |
|||
} |
|||
break; |
|||
case info_pub: |
|||
printf("PUB, %s, %d, %d\n", szTemp, s_pCompilerData->info_data4[i] & 0xFFFF, s_pCompilerData->info_data4[i] >> 16); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
static void DumpList() |
|||
{ |
|||
size_t listOffset = 0; |
|||
while (listOffset < s_pCompilerData->list_length) |
|||
{ |
|||
char* pTemp = strstr(&(s_pCompilerData->list[listOffset]), "\r"); |
|||
if (pTemp) |
|||
{ |
|||
*pTemp = 0; |
|||
} |
|||
printf("%s\n", &(s_pCompilerData->list[listOffset])); |
|||
if (pTemp) |
|||
{ |
|||
*pTemp = 0x0D; |
|||
listOffset += (pTemp - &(s_pCompilerData->list[listOffset])) + 1; |
|||
} |
|||
else |
|||
{ |
|||
listOffset += strlen(&(s_pCompilerData->list[listOffset])); |
|||
} |
|||
} |
|||
} |
|||
|
|||
static void DumpDoc() |
|||
{ |
|||
size_t docOffset = 0; |
|||
while (docOffset < s_pCompilerData->doc_length) |
|||
{ |
|||
char* pTemp = strstr(&(s_pCompilerData->doc[docOffset]), "\r"); |
|||
if (pTemp) |
|||
{ |
|||
*pTemp = 0; |
|||
} |
|||
printf("%s\n", &(s_pCompilerData->doc[docOffset])); |
|||
if (pTemp) |
|||
{ |
|||
*pTemp = 0x0D; |
|||
docOffset += (pTemp - &(s_pCompilerData->doc[docOffset])) + 1; |
|||
} |
|||
else |
|||
{ |
|||
docOffset += strlen(&(s_pCompilerData->doc[docOffset])); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|||
|
|||
void InitCompiler(CompilerConfig* pCompilerConfig, LoadFileFunc pLoadFileFunc, FreeFileBufferFunc pFreeFileBufferFunc) |
|||
{ |
|||
s_nObjStackPtr = 0; |
|||
s_pCompilerData = 0; |
|||
s_bFinalCompile = false; |
|||
s_pCompileResultBuffer = 0; |
|||
|
|||
if (pCompilerConfig) |
|||
{ |
|||
s_compilerConfig = *pCompilerConfig; |
|||
} |
|||
|
|||
s_pLoadFileFunc = pLoadFileFunc; |
|||
s_pFreeFileBufferFunc = pFreeFileBufferFunc; |
|||
|
|||
pp_setFileFunctions(pLoadFileFunc, pFreeFileBufferFunc); |
|||
pp_init(&s_preprocessor, s_compilerConfig.bAlternatePreprocessorMode); |
|||
pp_setcomments(&s_preprocessor, "\'", "{", "}"); |
|||
} |
|||
|
|||
void SetDefine(const char* pName, const char* pValue) |
|||
{ |
|||
pp_define(&s_preprocessor, pName, pValue); |
|||
} |
|||
|
|||
unsigned char* CompileSpin(char* pFilename, int* pnResultLength) |
|||
{ |
|||
*pnResultLength = 0; |
|||
|
|||
if (s_compilerConfig.bFileTreeOutputOnly) |
|||
{ |
|||
printf("%s\n", pFilename); |
|||
} |
|||
|
|||
if (s_compilerConfig.bUnusedMethodElimination) |
|||
{ |
|||
InitUnusedMethodData(); |
|||
} |
|||
|
|||
int nOriginalSize = 0; |
|||
|
|||
restart_compile: |
|||
s_pCompilerData = InitStruct(); |
|||
s_pCompilerData->bUnusedMethodElimination = s_compilerConfig.bUnusedMethodElimination; |
|||
s_pCompilerData->bFinalCompile = s_bFinalCompile; |
|||
|
|||
s_pCompilerData->list = new char[ListLimit]; |
|||
s_pCompilerData->list_limit = ListLimit; |
|||
memset(s_pCompilerData->list, 0, ListLimit); |
|||
|
|||
if (s_compilerConfig.bDocMode && !s_compilerConfig.bDATonly) |
|||
{ |
|||
s_pCompilerData->doc = new char[DocLimit]; |
|||
s_pCompilerData->doc_limit = DocLimit; |
|||
memset(s_pCompilerData->doc, 0, DocLimit); |
|||
} |
|||
else |
|||
{ |
|||
s_pCompilerData->doc = 0; |
|||
s_pCompilerData->doc_limit = 0; |
|||
} |
|||
s_pCompilerData->bDATonly = s_compilerConfig.bDATonly; |
|||
s_pCompilerData->bBinary = s_compilerConfig.bBinary; |
|||
s_pCompilerData->eeprom_size = s_compilerConfig.eeprom_size; |
|||
|
|||
// allocate space for obj based on eeprom size command line option
|
|||
s_pCompilerData->obj_limit = s_compilerConfig.eeprom_size > min_obj_limit ? s_compilerConfig.eeprom_size : min_obj_limit; |
|||
s_pCompilerData->obj = new unsigned char[s_pCompilerData->obj_limit]; |
|||
|
|||
// copy filename into obj_title, and chop off the .spin
|
|||
strcpy(s_pCompilerData->obj_title, pFilename); |
|||
char* pExtension = strstr(&s_pCompilerData->obj_title[0], ".spin"); |
|||
if (pExtension != 0) |
|||
{ |
|||
*pExtension = 0; |
|||
} |
|||
|
|||
int nCompileIndex = 0; |
|||
if (!CompileRecursively(pFilename, nCompileIndex, 0)) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
if (!s_compilerConfig.bQuiet) |
|||
{ |
|||
// only do this if UME is off or if it's the final compile when UME is on
|
|||
if (!s_compilerConfig.bUnusedMethodElimination || s_bFinalCompile) |
|||
{ |
|||
printf("Done.\n"); |
|||
} |
|||
} |
|||
|
|||
if (!s_compilerConfig.bFileTreeOutputOnly && !s_compilerConfig.bFileListOutputOnly && !s_compilerConfig.bDumpSymbols) |
|||
{ |
|||
if (!s_bFinalCompile && s_compilerConfig.bUnusedMethodElimination) |
|||
{ |
|||
nOriginalSize = s_pCompilerData->psize; |
|||
FindUnusedMethods(s_pCompilerData); |
|||
s_bFinalCompile = true; |
|||
CleanupMemory(false); |
|||
goto restart_compile; |
|||
} |
|||
int bufferSize = 0; |
|||
if (!ComposeRAM(&s_pCompileResultBuffer, bufferSize)) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
if (!s_compilerConfig.bQuiet) |
|||
{ |
|||
if (s_compilerConfig.bUnusedMethodElimination) |
|||
{ |
|||
printf("Unused Method Elimination:\n"); |
|||
if ((nOriginalSize - s_pCompilerData->psize) > 0) |
|||
{ |
|||
if (s_compilerConfig.bVerbose) |
|||
{ |
|||
if (s_pCompilerData->unused_obj_files) |
|||
{ |
|||
printf("Unused Objects:\n"); |
|||
for(int i = 0; i < s_pCompilerData->unused_obj_files; i++) |
|||
{ |
|||
printf("%s\n", &(s_pCompilerData->obj_unused[i<<8])); |
|||
} |
|||
} |
|||
if (s_pCompilerData->unused_methods) |
|||
{ |
|||
printf("Unused Methods:\n"); |
|||
for(int i = 0; i < s_pCompilerData->unused_methods; i++) |
|||
{ |
|||
printf("%s\n", &(s_pCompilerData->method_unused[i*symbol_limit])); |
|||
} |
|||
} |
|||
if (s_pCompilerData->unused_methods || s_pCompilerData->unused_obj_files) |
|||
{ |
|||
printf("---------------\n"); |
|||
} |
|||
} |
|||
printf("%5d methods removed\n%5d objects removed\n%5d bytes saved\n", s_pCompilerData->unused_methods, s_pCompilerData->unused_obj_files, nOriginalSize - s_pCompilerData->psize ); |
|||
} |
|||
else |
|||
{ |
|||
printf("Nothing removed.\n"); |
|||
} |
|||
printf("--------------------------\n"); |
|||
} |
|||
printf("Program size is %d bytes\n", bufferSize); |
|||
} |
|||
*pnResultLength = bufferSize; |
|||
} |
|||
|
|||
if (s_compilerConfig.bDumpSymbols) |
|||
{ |
|||
DumpSymbols(); |
|||
} |
|||
|
|||
if (s_compilerConfig.bVerbose && !s_compilerConfig.bQuiet && !s_compilerConfig.bDATonly) |
|||
{ |
|||
DumpList(); |
|||
} |
|||
|
|||
if (s_compilerConfig.bDocMode && s_compilerConfig.bVerbose && !s_compilerConfig.bQuiet && !s_compilerConfig.bDATonly) |
|||
{ |
|||
DumpDoc(); |
|||
} |
|||
|
|||
return s_pCompileResultBuffer; |
|||
} |
|||
|
|||
void ShutdownCompiler() |
|||
{ |
|||
pp_clear_define_state(&s_preprocessor); |
|||
CleanupMemory(); |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,76 @@ |
|||
///////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
|
|||
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|||
// See end of file for terms of use. //
|
|||
// //
|
|||
///////////////////////////////////////////////////////////////
|
|||
//
|
|||
// CompileSpin.h
|
|||
//
|
|||
#ifndef _COMPILESPIN_H_ |
|||
#define _COMPILESPIN_H_ |
|||
|
|||
typedef char* (*LoadFileFunc)(const char* pFilename, int* pnLength, char** ppFilePath); |
|||
typedef void (*FreeFileBufferFunc)(char* pBuffer); |
|||
|
|||
struct CompilerConfig |
|||
{ |
|||
CompilerConfig() |
|||
: bVerbose(false) |
|||
, bQuiet(false) |
|||
, bFileTreeOutputOnly(false) |
|||
, bFileListOutputOnly(false) |
|||
, bDumpSymbols(false) |
|||
, bUsePreprocessor(true) |
|||
, bAlternatePreprocessorMode(false) |
|||
, bUnusedMethodElimination(false) |
|||
, bDocMode(false) |
|||
, bDATonly(false) |
|||
, bBinary(true) |
|||
, eeprom_size(32768) |
|||
{ |
|||
} |
|||
|
|||
bool bVerbose; |
|||
bool bQuiet; |
|||
bool bFileTreeOutputOnly; |
|||
bool bFileListOutputOnly; |
|||
bool bDumpSymbols; |
|||
bool bUsePreprocessor; |
|||
bool bAlternatePreprocessorMode; |
|||
bool bUnusedMethodElimination; |
|||
bool bDocMode; |
|||
bool bDATonly; |
|||
bool bBinary; |
|||
unsigned int eeprom_size; |
|||
}; |
|||
|
|||
|
|||
void InitCompiler(CompilerConfig* pCompilerConfig, LoadFileFunc pLoadFileFunc, FreeFileBufferFunc pFreeFileBufferFunc); |
|||
void SetDefine(const char* pName, const char* pValue); |
|||
unsigned char* CompileSpin(char* pFilename, int* pnResultLength); |
|||
void ShutdownCompiler(); |
|||
|
|||
#endif // _COMPILESPIN_H_
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,686 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// CompileUtilities.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" |
|||
|
|||
bool SkipBlock(int column) |
|||
{ |
|||
int savedObjPtr = g_pCompilerData->obj_ptr; |
|||
bool savedStringPatchEnable = g_pCompilerData->str_patch_enable; |
|||
g_pCompilerData->str_patch_enable = false; |
|||
if (!CompileBlock(column)) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pCompilerData->str_patch_enable = savedStringPatchEnable; |
|||
g_pCompilerData->obj_ptr = savedObjPtr; |
|||
return true; |
|||
} |
|||
|
|||
bool SkipRange() |
|||
{ |
|||
int savedObjPtr = g_pCompilerData->obj_ptr; |
|||
bool savedStringPatchEnable = g_pCompilerData->str_patch_enable; |
|||
g_pCompilerData->str_patch_enable = false; |
|||
bool bRange; |
|||
if (!CompileRange(bRange)) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pCompilerData->str_patch_enable = savedStringPatchEnable; |
|||
g_pCompilerData->obj_ptr = savedObjPtr; |
|||
return true; |
|||
} |
|||
|
|||
bool SkipExpression() |
|||
{ |
|||
int savedObjPtr = g_pCompilerData->obj_ptr; |
|||
bool savedStringPatchEnable = g_pCompilerData->str_patch_enable; |
|||
g_pCompilerData->str_patch_enable = false; |
|||
if (!CompileExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pCompilerData->str_patch_enable = savedStringPatchEnable; |
|||
g_pCompilerData->obj_ptr = savedObjPtr; |
|||
return true; |
|||
} |
|||
|
|||
bool CheckIndex(bool& bIndex, int& expSourcePtr) |
|||
{ |
|||
bIndex = false; |
|||
if (g_pElementizer->CheckElement(type_leftb)) |
|||
{ |
|||
expSourcePtr = g_pElementizer->GetSourcePtr(); |
|||
if (!SkipExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_rightb)) |
|||
{ |
|||
return false; |
|||
} |
|||
bIndex = true; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool CheckIndexRange(bool& bIndex, int& expSourcePtr) |
|||
{ |
|||
bIndex = false; |
|||
if (g_pElementizer->CheckElement(type_leftb)) |
|||
{ |
|||
expSourcePtr = g_pElementizer->GetSourcePtr(); |
|||
if (!SkipExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->CheckElement(type_dotdot)) |
|||
{ |
|||
if (!SkipExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
if (!g_pElementizer->GetElement(type_rightb)) |
|||
{ |
|||
return false; |
|||
} |
|||
bIndex = true; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool CheckVariable_AddressExpression(int& expSourcePtr) |
|||
{ |
|||
bool bIndex = false; |
|||
if (!CheckIndex(bIndex, expSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!bIndex) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eleftb]; |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool CheckVariable(bool& bVariable, unsigned char& type, unsigned char& size, int& address, int& indexSourcePtr) |
|||
{ |
|||
address = g_pElementizer->GetValue(); |
|||
indexSourcePtr = 0; |
|||
|
|||
unsigned char varType = (unsigned char)(g_pElementizer->GetType() & 0xFF); |
|||
|
|||
if (varType >= type_var_byte && varType <= type_var_long) |
|||
{ |
|||
type = type_var_byte; |
|||
// adjust address base on the var size
|
|||
if (varType < type_var_long) |
|||
{ |
|||
address += g_pCompilerData->var_long; |
|||
} |
|||
if (varType == type_var_byte) |
|||
{ |
|||
address += g_pCompilerData->var_word; |
|||
} |
|||
} |
|||
else if (varType >= type_dat_byte && varType <= type_dat_long) |
|||
{ |
|||
type = type_dat_byte; |
|||
} |
|||
else if (varType >= type_loc_byte && varType <= type_loc_long) |
|||
{ |
|||
type = type_loc_byte; |
|||
} |
|||
else |
|||
{ |
|||
type = varType; |
|||
if (varType == type_size) |
|||
{ |
|||
size = (unsigned char)(g_pElementizer->GetValue() & 0xFF); |
|||
if (!CheckVariable_AddressExpression(address)) |
|||
{ |
|||
return false; |
|||
} |
|||
bool bIndex = false; |
|||
if (!CheckIndex(bIndex, indexSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
bVariable = true; |
|||
return true; |
|||
} |
|||
else |
|||
{ |
|||
size = 2; |
|||
if (varType == type_spr) |
|||
{ |
|||
if (!CheckVariable_AddressExpression(address)) |
|||
{ |
|||
return false; |
|||
} |
|||
bVariable = true; |
|||
return true; |
|||
} |
|||
else if (varType == type_reg) |
|||
{ |
|||
bool bIndex = false; |
|||
if (!CheckIndexRange(bIndex, indexSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (bIndex) |
|||
{ |
|||
size = 3; |
|||
} |
|||
bVariable = true; |
|||
return true; |
|||
} |
|||
else |
|||
{ |
|||
bVariable = false; |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
// if we got here then it's a var/dat/loc type
|
|||
// set size
|
|||
size = varType; |
|||
size -= type; |
|||
bool bIndex = false; |
|||
if (!CheckIndex(bIndex, indexSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!bIndex) |
|||
{ |
|||
// check for .byte/word/long{[index]}
|
|||
if (g_pElementizer->CheckElement(type_dot)) |
|||
{ |
|||
bool bEof = false; |
|||
if (!g_pElementizer->GetNext(bEof)) // get byte/word/long
|
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() != type_size) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_ebwol]; |
|||
return false; |
|||
} |
|||
if (size < (g_pElementizer->GetValue() & 0xFF)) // new size must be same or smaller
|
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_sombs]; |
|||
return false; |
|||
} |
|||
size = (g_pElementizer->GetValue() & 0xFF); // update size
|
|||
|
|||
bool bIndexCheck = false; |
|||
if (!CheckIndex(bIndexCheck, indexSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
bVariable = true; |
|||
return true; |
|||
} |
|||
|
|||
bool GetVariable(unsigned char& type, unsigned char& size, int& address, int& indexSourcePtr) |
|||
{ |
|||
bool bEof = false; |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
bool bVariable = false; |
|||
if (!CheckVariable(bVariable, type, size, address, indexSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!bVariable) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eav]; |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool CompileVariable(unsigned char vOperation, unsigned char vOperator, unsigned char type, unsigned char size, int address, int indexSourcePtr) |
|||
{ |
|||
// compile and index(s)
|
|||
if (type != type_reg) |
|||
{ |
|||
if (type == type_spr || type == type_size) |
|||
{ |
|||
if (!CompileOutOfSequenceExpression(address)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
if (type != type_spr) |
|||
{ |
|||
if (indexSourcePtr != 0) |
|||
{ |
|||
if (!CompileOutOfSequenceExpression(indexSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
unsigned char byteCode = 0; |
|||
|
|||
if (type == type_spr) |
|||
{ |
|||
byteCode = 0x24 | vOperation; |
|||
} |
|||
else if (type == type_reg) |
|||
{ |
|||
byteCode = 0x3F; |
|||
if (size != 2) |
|||
{ |
|||
bool bRange = false; |
|||
if (!CompileOutOfSequenceRange(indexSourcePtr, bRange)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (bRange) |
|||
{ |
|||
byteCode = 0x3E; |
|||
} |
|||
else |
|||
{ |
|||
byteCode = 0x3D; |
|||
} |
|||
} |
|||
if (!EnterObj(byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
// byteCode = 1 in high bit, bottom 2 bits of vOperation in next two bits, then bottom 5 bits of address
|
|||
byteCode = 0x80 | ((vOperation & 3) << 5) | (address & 0x1F); |
|||
} |
|||
else |
|||
{ |
|||
if ((type != type_var_byte && type != type_loc_byte) || size != 2 || address >= 8*4 || indexSourcePtr != 0) |
|||
{ |
|||
// not compact
|
|||
byteCode = 0x80 | (size << 5); |
|||
if (indexSourcePtr != 0) |
|||
{ |
|||
byteCode |= 0x10; |
|||
} |
|||
byteCode |= vOperation; |
|||
if (type != type_size) |
|||
{ |
|||
if (type == type_dat_byte) |
|||
{ |
|||
byteCode += 4; |
|||
} |
|||
else if (type == type_var_byte) |
|||
{ |
|||
byteCode += 8; |
|||
} |
|||
else if (type == type_loc_byte) |
|||
{ |
|||
byteCode += 12; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_internal]; |
|||
return false; |
|||
} |
|||
if (!EnterObj(byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (address > 0x7F) |
|||
{ |
|||
// two byte address
|
|||
byteCode = (unsigned char)(address >> 8) | 0x80; |
|||
if (!EnterObj(byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
byteCode = (unsigned char)address; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// compact
|
|||
byteCode = (type == type_var_byte) ? 0x40 : 0x60; |
|||
byteCode |= (unsigned char)address; |
|||
byteCode |= vOperation; |
|||
} |
|||
} |
|||
|
|||
if (!EnterObj(byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (vOperation == 2) // if assign
|
|||
{ |
|||
if (!EnterObj(vOperator)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool CompileVariable_Assign(unsigned char vOperator, unsigned char type, unsigned char size, int address, int indexSourcePtr) |
|||
{ |
|||
return CompileVariable(2, vOperator, type, size, address, indexSourcePtr); |
|||
} |
|||
|
|||
bool CompileVariable_Expression(unsigned char vOperator, unsigned char type, unsigned char size, int address, int indexSourcePtr) |
|||
{ |
|||
if (!CompileExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
return CompileVariable(2, vOperator, type, size, address, indexSourcePtr); |
|||
} |
|||
|
|||
bool CompileVariable_PreSignExtendOrRandom(unsigned char vOperator) |
|||
{ |
|||
unsigned char varType = 0; |
|||
unsigned char varSize = 0; |
|||
int varAddress = 0; |
|||
int varIndexSourcePtr = 0; |
|||
if (!GetVariable(varType, varSize, varAddress, varIndexSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return CompileVariable_Assign(vOperator, varType, varSize, varAddress, varIndexSourcePtr); |
|||
} |
|||
|
|||
bool CompileVariable_IncOrDec(unsigned char vOperator, unsigned char type, unsigned char size, int address, int indexSourcePtr) |
|||
{ |
|||
return CompileVariable(2, vOperator | (((size + 1) & 3) << 1), type, size, address, indexSourcePtr); |
|||
} |
|||
|
|||
bool CompileVariable_PreIncOrDec(unsigned char vOperator) |
|||
{ |
|||
unsigned char varType = 0; |
|||
unsigned char varSize = 0; |
|||
int varAddress = 0; |
|||
int varIndexSourcePtr = 0; |
|||
if (!GetVariable(varType, varSize, varAddress, varIndexSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return CompileVariable_IncOrDec(vOperator, varType, varSize, varAddress, varIndexSourcePtr); |
|||
} |
|||
|
|||
bool CompileParameters(int numParameters) |
|||
{ |
|||
if (numParameters > 0) |
|||
{ |
|||
if (!g_pElementizer->GetElement(type_left)) // (
|
|||
{ |
|||
return false; |
|||
} |
|||
for (int i = 0; i < numParameters; i++) |
|||
{ |
|||
if (!CompileExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
if (i < (numParameters - 1)) |
|||
{ |
|||
if (!g_pElementizer->GetElement(type_comma)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
if (!g_pElementizer->GetElement(type_right)) // )
|
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool CompileConstant(int value) |
|||
{ |
|||
if (value >= -1 && value <= 1) |
|||
{ |
|||
// constant is -1, 0, or 1, so compiles to a single bytecode
|
|||
unsigned char byteCode = (unsigned char)(value+1) | 0x34; |
|||
if (!EnterObj(byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
// see if it's a mask
|
|||
// masks can be: only one bit on (e.g. 0x00008000),
|
|||
// all bits on except one (e.g. 0xFFFF7FFF),
|
|||
// all bits on up to a bit then all zeros (e.g. 0x0000FFFF),
|
|||
// or all bits off up to a bit then all ones (e.g. 0xFFFF0000)
|
|||
for (unsigned char i = 0; i < 128; i++) |
|||
{ |
|||
int testVal = 2; |
|||
testVal <<= (i & 0x1F); // mask i, so that we only actually shift 0 to 31
|
|||
|
|||
if (i & 0x20) // i in range 32 to 63 or 96 to 127
|
|||
{ |
|||
testVal--; |
|||
} |
|||
if (i& 0x40) // i in range 64 to 127
|
|||
{ |
|||
testVal = ~testVal; |
|||
} |
|||
|
|||
if (testVal == value) |
|||
{ |
|||
if (!EnterObj(0x37)) // (constant mask)
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj(i)) |
|||
{ |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
// handle constants with upper 2 or 3 bytes being 0xFFs, using 'not'
|
|||
if ((value & 0xFFFFFF00) == 0xFFFFFF00) |
|||
{ |
|||
// one byte constant using 'not'
|
|||
if (!EnterObj(0x38)) |
|||
{ |
|||
return false; |
|||
} |
|||
unsigned char byteCode = (unsigned char)(value & 0xFF); |
|||
if (!EnterObj(~byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj(0xE7)) // (bitwise bot)
|
|||
{ |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
else if ((value & 0xFFFF0000) == 0xFFFF0000) |
|||
{ |
|||
// two byte constant using 'not'
|
|||
if (!EnterObj(0x39)) |
|||
{ |
|||
return false; |
|||
} |
|||
unsigned char byteCode = (unsigned char)((value >> 8) & 0xFF); |
|||
if (!EnterObj(~byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
byteCode = (unsigned char)(value & 0xFF); |
|||
if (!EnterObj(~byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj(0xE7)) // (bitwise bot)
|
|||
{ |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
// 1 to 4 byte constant
|
|||
unsigned char size = 1; |
|||
if (value & 0xFF000000) |
|||
{ |
|||
size = 4; |
|||
} |
|||
else if (value & 0x00FF0000) |
|||
{ |
|||
size = 3; |
|||
} |
|||
else if (value & 0x0000FF00) |
|||
{ |
|||
size = 2; |
|||
} |
|||
unsigned char byteCode = 0x37 + size; // (constant 1..4 bytes)
|
|||
if (!EnterObj(byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
for (unsigned char i = size; i > 0; i--) |
|||
{ |
|||
byteCode = (unsigned char)((value >> ((i - 1) * 8)) & 0xFF); |
|||
if (!EnterObj(byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool CompileOutOfSequenceExpression(int sourcePtr) |
|||
{ |
|||
int savedSourcePtr = g_pElementizer->GetSourcePtr(); |
|||
g_pElementizer->SetSourcePtr(sourcePtr); |
|||
if (!CompileExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pElementizer->SetSourcePtr(savedSourcePtr); |
|||
return true; |
|||
} |
|||
|
|||
bool CompileOutOfSequenceRange(int sourcePtr, bool& bRange) |
|||
{ |
|||
int savedSourcePtr = g_pElementizer->GetSourcePtr(); |
|||
g_pElementizer->SetSourcePtr(sourcePtr); |
|||
if (!CompileRange(bRange)) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pElementizer->SetSourcePtr(savedSourcePtr); |
|||
return true; |
|||
} |
|||
|
|||
// compiles either a value or a range and sets the bRange flag accordingly
|
|||
bool CompileRange(bool& bRange) |
|||
{ |
|||
if (!CompileExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (g_pElementizer->CheckElement(type_dotdot)) |
|||
{ |
|||
if (!CompileExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
bRange = true; |
|||
} |
|||
else |
|||
{ |
|||
bRange = false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
// Compile relative address
|
|||
bool CompileAddress(int address) |
|||
{ |
|||
address -= g_pCompilerData->obj_ptr; // make relative address
|
|||
address--; // compensate for single-byte
|
|||
|
|||
if ((address < 0 && abs(address) <= 64) || (address >= 0 && address < 64)) |
|||
{ |
|||
// single byte, enter
|
|||
address &= 0x007F; |
|||
} |
|||
else |
|||
{ |
|||
// double byte, compensate and enter
|
|||
address--; |
|||
if (!EnterObj((unsigned char)((address >> 8) | 0x80))) |
|||
{ |
|||
return false; |
|||
} |
|||
address &= 0x00FF; |
|||
} |
|||
|
|||
return EnterObj((unsigned char)address); |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,80 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// CompileUtilities.h
|
|||
//
|
|||
|
|||
#ifndef _COMPILEUTILITIES_H_ |
|||
#define _COMPILEUTILITIES_H_ |
|||
|
|||
extern bool SkipBlock(int column); |
|||
extern bool SkipRange(); |
|||
extern bool SkipExpression(); |
|||
extern bool CheckIndex(bool& bIndex, int& expSourcePtr); |
|||
extern bool CheckIndexRange(bool& bIndex, int& expSourcePtr); |
|||
extern bool CheckVariable(bool& bVariable, unsigned char& type, unsigned char& size, int& address, int& indexSourcePtr); |
|||
extern bool GetVariable(unsigned char& type, unsigned char& size, int& address, int& indexSourcePtr); |
|||
extern bool CompileVariable(unsigned char vOperation, unsigned char vOperator, unsigned char type, unsigned char size, int address, int indexSourcePtr); |
|||
extern bool CompileVariable_Assign(unsigned char vOperator, unsigned char type, unsigned char size, int address, int indexSourcePtr); |
|||
extern bool CompileVariable_Expression(unsigned char vOperator, unsigned char type, unsigned char size, int address, int indexSourcePtr); |
|||
extern bool CompileVariable_PreSignExtendOrRandom(unsigned char vOperator); |
|||
extern bool CompileVariable_IncOrDec(unsigned char vOperator, unsigned char type, unsigned char size, int address, int indexSourcePtr); |
|||
extern bool CompileVariable_PreIncOrDec(unsigned char vOperator); |
|||
extern bool CompileParameters(int numParameters); |
|||
extern bool CompileConstant(int value); |
|||
extern bool CompileOutOfSequenceExpression(int sourcePtr); |
|||
extern bool CompileOutOfSequenceRange(int sourcePtr, bool& bRange); |
|||
extern bool CompileRange(bool& bRange); |
|||
extern bool CompileAddress(int address); |
|||
|
|||
// these are in InstructionBlockCompiler.cpp
|
|||
extern bool CompileBlock(int column); |
|||
extern bool OptimizeBlock(int column, int param, bool (*pCompileFunction)(int, int)); |
|||
|
|||
extern bool CompileInstruction(); // in CompileInstruction.cpp
|
|||
extern bool CompileExpression(); // in CompileExpression.cpp
|
|||
|
|||
// these are in StringConstantRoutines.cpp
|
|||
extern void StringConstant_PreProcess(); |
|||
extern bool StringConstant_GetIndex(); |
|||
extern bool StringConstant_EnterChar(unsigned char theChar); |
|||
extern void StringConstant_EnterPatch(); |
|||
extern bool StringConstant_PostProcess(); |
|||
|
|||
// these are int BlockNestStackRoutines.cpp
|
|||
extern bool BlockNest_New(unsigned char type, int stackSize); |
|||
extern void BlockNest_Redo(unsigned char type); |
|||
extern void BlockNest_End(); |
|||
extern void BlockStack_Write(int address, int value); |
|||
extern int BlockStack_Read(int address); |
|||
extern bool BlockStack_CompileAddress(int address); |
|||
extern bool BlockStack_CompileConstant(); |
|||
|
|||
#endif // _COMPILEUTILITIES_H_
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,338 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// DistillObjects.cpp
|
|||
//
|
|||
// called Object Distiller in the asm code
|
|||
//
|
|||
|
|||
#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" |
|||
|
|||
bool DistillSetup_Enter(unsigned short value) |
|||
{ |
|||
if (g_pCompilerData->dis_ptr == distiller_limit) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_odo]; |
|||
return false; |
|||
} |
|||
g_pCompilerData->dis[g_pCompilerData->dis_ptr++] = value; |
|||
return true; |
|||
} |
|||
|
|||
// create a table of all objects with their offsets and sub objects
|
|||
// each entry contains:
|
|||
// id, offset, number sub objects, [sub object ids]
|
|||
bool DistillSetup_Record(short id, unsigned short offset, unsigned short& subObjectId) |
|||
{ |
|||
if (!DistillSetup_Enter(id)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!DistillSetup_Enter(offset)) |
|||
{ |
|||
return false; |
|||
} |
|||
unsigned short numSubObjects = (unsigned short)(g_pCompilerData->obj[offset+3]); |
|||
if (!DistillSetup_Enter(numSubObjects)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (numSubObjects > 0) |
|||
{ |
|||
short startingSubObjectId = subObjectId; |
|||
for (short i = 0; i < numSubObjects; i++) |
|||
{ |
|||
if (!DistillSetup_Enter(subObjectId++)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
unsigned short nextSubObjects = (unsigned short)(g_pCompilerData->obj[offset+2]); |
|||
for (short i = 0; i < numSubObjects; i++) |
|||
{ |
|||
unsigned short offsetAdjust = *((unsigned short*)&(g_pCompilerData->obj[offset + ((nextSubObjects + i) * 4)])); |
|||
if (!DistillSetup_Record(startingSubObjectId + i, offset + offsetAdjust, subObjectId)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool DistillSetup() |
|||
{ |
|||
g_pCompilerData->dis_ptr = 0; |
|||
unsigned short subObjectId = 1; |
|||
if (!DistillSetup_Record(0, 0, subObjectId)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// Clear all the objects table of offsets to their sub objects
|
|||
// this needs to be done so that objects will binary compare with each other properly
|
|||
// these offsets get replaced in the reconnect step
|
|||
int disPtr = 0; |
|||
while (disPtr < g_pCompilerData->dis_ptr) |
|||
{ |
|||
// do we have sub objects?
|
|||
unsigned short numSubObjects = g_pCompilerData->dis[disPtr + 2]; |
|||
if (numSubObjects > 0) |
|||
{ |
|||
unsigned short offset = g_pCompilerData->dis[disPtr + 1]; |
|||
|
|||
disPtr += numSubObjects; |
|||
|
|||
unsigned short offsetAdjust = (unsigned short)(g_pCompilerData->obj[offset + 2]); |
|||
unsigned char* pObj = &(g_pCompilerData->obj[offset + (offsetAdjust * 4)]); |
|||
for (int i = 0; i < numSubObjects; i++) |
|||
{ |
|||
*((unsigned short*)&pObj[0]) = 0; |
|||
pObj += 4; |
|||
} |
|||
} |
|||
|
|||
disPtr += 3; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
// update all objects of the given id to the new id
|
|||
// also flags them as "distilled" with the upper bit being on
|
|||
void DistillEliminate_Update(unsigned short objectId, int newDisPtr) |
|||
{ |
|||
int disPtr = 0; |
|||
|
|||
while (disPtr < g_pCompilerData->dis_ptr) |
|||
{ |
|||
disPtr += 3; |
|||
unsigned short numSubObjects = g_pCompilerData->dis[disPtr - 1]; |
|||
if (numSubObjects > 0) |
|||
{ |
|||
for (int i = 0; i < numSubObjects; i++) |
|||
{ |
|||
if ((g_pCompilerData->dis[disPtr] & 0x7FFF) == objectId) |
|||
{ |
|||
g_pCompilerData->dis[disPtr] = (g_pCompilerData->dis[newDisPtr] | 0x8000); |
|||
} |
|||
disPtr++; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
void DistillEliminate() |
|||
{ |
|||
int disPtr = 0; |
|||
|
|||
while (disPtr < g_pCompilerData->dis_ptr) |
|||
{ |
|||
unsigned short numSubObjects = g_pCompilerData->dis[disPtr + 2]; |
|||
if (numSubObjects > 0) |
|||
{ |
|||
int i; |
|||
for (i = 0; i < numSubObjects; i++) |
|||
{ |
|||
if ((g_pCompilerData->dis[disPtr + 3 + i] & 0x8000) == 0) |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
if (i < numSubObjects) |
|||
{ |
|||
// point to next object record
|
|||
disPtr += (3 + numSubObjects); |
|||
continue; |
|||
} |
|||
} |
|||
|
|||
// search for any matching objects
|
|||
int newDisPtr = disPtr; |
|||
// point to next object record
|
|||
newDisPtr += (3 + numSubObjects); |
|||
|
|||
bool bRestart = false; |
|||
while (newDisPtr < g_pCompilerData->dis_ptr) |
|||
{ |
|||
unsigned short newNumSubObjects = g_pCompilerData->dis[newDisPtr + 2]; |
|||
|
|||
if (numSubObjects != newNumSubObjects) |
|||
{ |
|||
// point to next object record
|
|||
newDisPtr += (3 + newNumSubObjects); |
|||
continue; |
|||
} |
|||
if (newNumSubObjects > 0) |
|||
{ |
|||
int i; |
|||
for (i = 0; i < newNumSubObjects; i++) |
|||
{ |
|||
if (g_pCompilerData->dis[disPtr + 3 + i] != g_pCompilerData->dis[newDisPtr + 3 + i]) |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
if (i < newNumSubObjects) |
|||
{ |
|||
// point to next object record
|
|||
newDisPtr += (3 + newNumSubObjects); |
|||
continue; |
|||
} |
|||
} |
|||
// compare the object binaries
|
|||
unsigned char* pObj = &(g_pCompilerData->obj[g_pCompilerData->dis[disPtr+1]]); |
|||
unsigned short objLength = *((unsigned short*)pObj); |
|||
if (memcmp(pObj, &(g_pCompilerData->obj[g_pCompilerData->dis[newDisPtr+1]]), (size_t)objLength) != 0) |
|||
{ |
|||
// point to next object record
|
|||
newDisPtr += (3 + newNumSubObjects); |
|||
continue; |
|||
} |
|||
|
|||
// the objects match, so update all related sub-object id's
|
|||
DistillEliminate_Update(g_pCompilerData->dis[disPtr], newDisPtr); |
|||
DistillEliminate_Update(g_pCompilerData->dis[newDisPtr], newDisPtr); |
|||
|
|||
// remove redundant object record from list
|
|||
g_pCompilerData->dis_ptr -= (3 + numSubObjects); |
|||
memmove(&g_pCompilerData->dis[disPtr], &g_pCompilerData->dis[disPtr + (3 + numSubObjects)], (g_pCompilerData->dis_ptr - disPtr) * 2); |
|||
|
|||
// restart elimination from beginning
|
|||
bRestart = true; |
|||
} |
|||
if (bRestart) |
|||
{ |
|||
disPtr = 0; |
|||
} |
|||
else |
|||
{ |
|||
// point to next object record
|
|||
disPtr += (3 + numSubObjects); |
|||
continue; |
|||
} |
|||
} |
|||
} |
|||
|
|||
static unsigned char s_rebuildBuffer[min_obj_limit]; |
|||
void DistillRebuild() |
|||
{ |
|||
int disPtr = 0; |
|||
unsigned short rebuildPtr = 0; |
|||
while (disPtr < g_pCompilerData->dis_ptr) |
|||
{ |
|||
// copy the object from obj into the rebuild buffer
|
|||
unsigned char* pObj = &(g_pCompilerData->obj[g_pCompilerData->dis[disPtr + 1]]); |
|||
unsigned short objLength = *((unsigned short*)pObj); |
|||
memcpy(&(s_rebuildBuffer[rebuildPtr]), pObj, (size_t)objLength); |
|||
|
|||
// fixup the distiller record
|
|||
g_pCompilerData->dis[disPtr+1] = rebuildPtr; |
|||
|
|||
rebuildPtr += objLength; |
|||
|
|||
// point to the next object record
|
|||
disPtr += (3 + g_pCompilerData->dis[disPtr + 2]); |
|||
} |
|||
|
|||
// copy the rebuilt data back into obj
|
|||
g_pCompilerData->obj_ptr = rebuildPtr; |
|||
memcpy(&g_pCompilerData->obj[0], &s_rebuildBuffer[0], (size_t)rebuildPtr); |
|||
} |
|||
|
|||
void DistillReconnect(int disPtr = 0) |
|||
{ |
|||
unsigned short numSubObjects = g_pCompilerData->dis[disPtr + 2]; |
|||
if (numSubObjects > 0) |
|||
{ |
|||
// this objects offset in the obj
|
|||
unsigned short objectOffset = g_pCompilerData->dis[disPtr + 1]; |
|||
// the offset (number of longs) to the sub-object offset list within this obj
|
|||
unsigned char subObjectOffsetListPtr = g_pCompilerData->obj[objectOffset + 2]; |
|||
// pointer to the sub-object offset list for this obj
|
|||
unsigned short* pSubObjectOffsetList = (unsigned short*)&(g_pCompilerData->obj[objectOffset + (subObjectOffsetListPtr * 4)]); |
|||
|
|||
for (int i = 0; i < numSubObjects; i++) |
|||
{ |
|||
unsigned short subObjectId = g_pCompilerData->dis[disPtr + 3 + i] & 0x7FFF; |
|||
|
|||
// find offset of sub-object
|
|||
int scanDisPtr = 0; |
|||
for (;;) |
|||
{ |
|||
if (g_pCompilerData->dis[scanDisPtr] == subObjectId) |
|||
{ |
|||
break; |
|||
} |
|||
scanDisPtr += (3 + g_pCompilerData->dis[scanDisPtr + 2]); |
|||
} |
|||
|
|||
// enter relative offset of sub-object
|
|||
pSubObjectOffsetList[i*2] = g_pCompilerData->dis[scanDisPtr + 1] - objectOffset; |
|||
|
|||
// call recursively to reconnect and sub-objects' sub-objects
|
|||
DistillReconnect(scanDisPtr); |
|||
} |
|||
} |
|||
} |
|||
|
|||
bool DistillObjects() |
|||
{ |
|||
int saved_obj_ptr = g_pCompilerData->obj_ptr; |
|||
|
|||
if (!DistillSetup()) |
|||
{ |
|||
return false; |
|||
} |
|||
DistillEliminate(); |
|||
DistillRebuild(); |
|||
DistillReconnect(); |
|||
|
|||
g_pCompilerData->distilled_longs = (saved_obj_ptr - g_pCompilerData->obj_ptr) >> 2; |
|||
|
|||
char tempStr[64]; |
|||
sprintf(tempStr, "\rDistilled longs: %d", g_pCompilerData->distilled_longs); |
|||
if (!PrintString(tempStr)) |
|||
{ |
|||
return false; |
|||
} |
|||
return PrintChr(13); |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,810 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// Elementizer.cpp
|
|||
//
|
|||
|
|||
#include <string.h> |
|||
#include "PropellerCompilerInternal.h" |
|||
#include "Elementizer.h" |
|||
#include "SymbolEngine.h" |
|||
#include "ErrorStrings.h" |
|||
#include "Utilities.h" |
|||
|
|||
// private
|
|||
|
|||
// set elementizer data from the currently set symbol entry
|
|||
void Elementizer::SetFromSymbolEntry() |
|||
{ |
|||
if (m_pSymbolEntry) |
|||
{ |
|||
m_type = m_pSymbolEntry->m_data.type; |
|||
m_value = m_pSymbolEntry->m_data.value; |
|||
m_value_2 = m_pSymbolEntry->m_data.value_2; |
|||
if (m_pSymbolEntry->m_data.dual) |
|||
{ |
|||
m_dual = true; |
|||
m_asm = m_pSymbolEntry->m_data.operator_type_or_asm; |
|||
} |
|||
else |
|||
{ |
|||
m_dual = false; |
|||
m_opType = m_pSymbolEntry->m_data.operator_type_or_asm; |
|||
|
|||
// fixup for AND and OR to have asm also
|
|||
if (m_type == type_binary && m_opType == op_log_and) |
|||
{ |
|||
m_asm = 0x18 + 0x40; |
|||
} |
|||
if (m_type == type_binary && m_opType == op_log_or) |
|||
{ |
|||
m_asm = 0x1A + 0x40; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
m_type = 0; |
|||
m_value = 0; |
|||
m_value_2 = 0; |
|||
m_asm = -1; |
|||
m_opType = -1; |
|||
} |
|||
} |
|||
|
|||
// public
|
|||
|
|||
// reset to start of source
|
|||
void Elementizer::Reset() |
|||
{ |
|||
m_sourceOffset = 0; |
|||
m_sourceFlags = 0; |
|||
} |
|||
|
|||
// get the next element in source, returns true no error, bEof will be set to true if eof is hit
|
|||
bool Elementizer::GetNext(bool& bEof) |
|||
{ |
|||
// update back data
|
|||
m_backOffsets[m_backIndex&0x03] = m_sourceOffset; |
|||
m_backFlags[m_backIndex&0x03] = m_sourceFlags; |
|||
m_backIndex++; |
|||
|
|||
// default to type_undefined
|
|||
m_type = 0; |
|||
m_value = 0; |
|||
m_value_2 = 0; |
|||
m_asm = -1; |
|||
m_opType = -1; |
|||
m_pSymbolEntry = 0; |
|||
|
|||
// no error, and not end of file
|
|||
int error = error_none; |
|||
bEof = false; |
|||
bool bDocComment = false; |
|||
int constantBase = 0; |
|||
|
|||
// setup source and symbol pointers
|
|||
char* pSource = m_pCompilerData->source; |
|||
int sourceStart = m_sourceOffset; |
|||
|
|||
m_currentSymbol[0] = 0; |
|||
int symbolOffset = 0; |
|||
bool bConstantOverflow = false; |
|||
|
|||
for (;;) |
|||
{ |
|||
char currentChar = pSource[m_sourceOffset++]; |
|||
|
|||
// parse
|
|||
if (constantBase > 0) |
|||
{ |
|||
// this handles reading in a constant of base 2, 4, 10, or 16
|
|||
// the constantBase value is set based on prefix characters handled below
|
|||
|
|||
if (currentChar == '_') |
|||
{ |
|||
// skip over _'s
|
|||
continue; |
|||
} |
|||
char digitValue; |
|||
if (!CheckDigit(currentChar, digitValue, (char)constantBase)) |
|||
{ |
|||
char notUsed; |
|||
char nextChar = pSource[m_sourceOffset]; |
|||
bool bNextCharDigit = CheckDigit(nextChar, notUsed, (char)constantBase); |
|||
|
|||
if ((constantBase == 10 && |
|||
(currentChar == '.' && bNextCharDigit)) || |
|||
currentChar == 'e' || currentChar == 'E') |
|||
{ |
|||
// handle float
|
|||
bConstantOverflow = false; |
|||
m_sourceOffset = sourceStart; |
|||
if (GetFloat(pSource, m_sourceOffset, m_value)) |
|||
{ |
|||
m_sourceOffset--; // back up to point at last digit
|
|||
m_type = type_con_float; |
|||
} |
|||
else |
|||
{ |
|||
error = error_fpcmbw; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// done with this constant
|
|||
m_sourceOffset--; // back up to point at last digit
|
|||
m_type = type_con; |
|||
} |
|||
constantBase = 0; |
|||
break; |
|||
} |
|||
else |
|||
{ |
|||
// multiply accumulate the constant
|
|||
unsigned int oldValue = m_value; |
|||
m_value *= constantBase; |
|||
|
|||
// check for overflow
|
|||
if (((unsigned int)m_value / constantBase) != oldValue) |
|||
{ |
|||
bConstantOverflow = true; |
|||
} |
|||
|
|||
m_value += digitValue; |
|||
} |
|||
continue; |
|||
} |
|||
else if (m_sourceFlags != 0) |
|||
{ |
|||
// old string? (continue parsing a string)
|
|||
|
|||
// for strings, m_sourceFlags will start out 0, and then cycle between 1 and 2 for
|
|||
// each character of the string, when it is 1, a type_comma is returned, when it is
|
|||
// 2 the next character is returned
|
|||
|
|||
// return a comma element between each character of the string
|
|||
if (m_sourceFlags == 1) |
|||
{ |
|||
m_sourceFlags++; |
|||
m_sourceOffset--; |
|||
m_type = type_comma; |
|||
break; |
|||
} |
|||
|
|||
// reset flag
|
|||
m_sourceFlags = 0; |
|||
|
|||
// check for errors
|
|||
if (currentChar == '\"') |
|||
{ |
|||
error = error_es; |
|||
break; |
|||
} |
|||
else if (currentChar == 0) |
|||
{ |
|||
m_sourceOffset--; // back up from eof
|
|||
error = error_eatq; |
|||
break; |
|||
} |
|||
else if (currentChar == 13) |
|||
{ |
|||
error = error_eatq; |
|||
break; |
|||
} |
|||
|
|||
// return the character
|
|||
m_value = currentChar; |
|||
|
|||
// check the next character, if it's not a " then setup so the next
|
|||
// call returns a type_comma, if it is a ", then we are done with this string
|
|||
// and we leave the offset pointing after the "
|
|||
currentChar = pSource[m_sourceOffset++]; |
|||
if (currentChar != '\"') |
|||
{ |
|||
m_sourceOffset--; |
|||
m_sourceFlags++; |
|||
} |
|||
|
|||
// return the character constant
|
|||
m_type = type_con; |
|||
break; |
|||
} |
|||
else if (currentChar == '\"') |
|||
{ |
|||
// new string (start parsing a string)
|
|||
|
|||
// we got here because m_sourceFlags was 0 and the character is a "
|
|||
|
|||
// get first character of string
|
|||
currentChar = pSource[m_sourceOffset++]; |
|||
|
|||
// check for errors
|
|||
if (currentChar == '\"') |
|||
{ |
|||
error = error_es; |
|||
break; |
|||
} |
|||
else if (currentChar == 0) |
|||
{ |
|||
m_sourceOffset--; // back up from eof
|
|||
error = error_eatq; |
|||
break; |
|||
} |
|||
else if (currentChar == 13) |
|||
{ |
|||
error = error_eatq; |
|||
break; |
|||
} |
|||
|
|||
// return the character in value
|
|||
m_value = currentChar & 0x000000FF; |
|||
|
|||
// check the next character, it's it's not a " then setup so the next
|
|||
// call returns a type_comma, if it is a " then it means it's a one character
|
|||
// string and we leave the offset pointing after the "
|
|||
currentChar = pSource[m_sourceOffset++]; |
|||
if (currentChar != '\"') |
|||
{ |
|||
m_sourceOffset--; // back up, so this character will be read after the type_comma
|
|||
m_sourceFlags = 1; // cause the next call to return a type_comma
|
|||
} |
|||
|
|||
// return the character constant
|
|||
m_type = type_con; |
|||
break; |
|||
} |
|||
else if (currentChar == 0) |
|||
{ |
|||
// eof
|
|||
m_type = type_end; |
|||
bEof = true; |
|||
m_sourceOffset--; |
|||
sourceStart = m_sourceOffset; |
|||
break; |
|||
} |
|||
else if (currentChar == 13) |
|||
{ |
|||
// eol
|
|||
m_type = type_end; |
|||
break; |
|||
} |
|||
else if (currentChar <= ' ') |
|||
{ |
|||
// space or tab?
|
|||
sourceStart = m_sourceOffset; |
|||
continue; |
|||
} |
|||
else if (currentChar == '\'') |
|||
{ |
|||
// comment
|
|||
// read until end of line or file, handle doc comment
|
|||
if (pSource[m_sourceOffset] == '\'') |
|||
{ |
|||
m_sourceOffset++; // skip over second '
|
|||
bDocComment = true; |
|||
g_pCompilerData->doc_flag = true; |
|||
} |
|||
for (;;) |
|||
{ |
|||
currentChar = pSource[m_sourceOffset++]; |
|||
if (currentChar == 0) |
|||
{ |
|||
m_sourceOffset--; // back up from eof
|
|||
m_type = type_end; |
|||
bEof = true; |
|||
break; |
|||
} |
|||
if (bDocComment) |
|||
{ |
|||
DocPrint(currentChar); |
|||
} |
|||
if (currentChar == 13) |
|||
{ |
|||
m_type = type_end; |
|||
break; |
|||
} |
|||
} |
|||
break; |
|||
} |
|||
else if (currentChar == '{') |
|||
{ |
|||
// brace comment
|
|||
// read the whole comment, handling doc comments as needed
|
|||
int braceCommentLevel = 1; |
|||
if (pSource[m_sourceOffset] == '{') |
|||
{ |
|||
m_sourceOffset++; // skip over second {
|
|||
bDocComment = true; |
|||
g_pCompilerData->doc_flag = true; |
|||
if (pSource[m_sourceOffset] == 13) |
|||
{ |
|||
m_sourceOffset++; // skip over end if present
|
|||
} |
|||
} |
|||
for (;;) |
|||
{ |
|||
currentChar = pSource[m_sourceOffset++]; |
|||
if (currentChar == 0) |
|||
{ |
|||
if (bDocComment) |
|||
{ |
|||
error = error_erbb; |
|||
} |
|||
else |
|||
{ |
|||
error = error_erb; |
|||
} |
|||
m_sourceOffset--; // back up from eof
|
|||
sourceStart = m_sourceOffset; |
|||
break; |
|||
} |
|||
else if (!bDocComment && currentChar == '{') |
|||
{ |
|||
braceCommentLevel++; |
|||
} |
|||
else if (currentChar == '}') |
|||
{ |
|||
if (bDocComment && pSource[m_sourceOffset] == '}') |
|||
{ |
|||
m_sourceOffset++; // skip over second }
|
|||
break; |
|||
} |
|||
else if (!bDocComment) |
|||
{ |
|||
braceCommentLevel--; |
|||
if (braceCommentLevel < 1) |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
else if (bDocComment) |
|||
{ |
|||
DocPrint(currentChar); |
|||
} |
|||
} |
|||
if (error == error_none) |
|||
{ |
|||
sourceStart = m_sourceOffset; |
|||
continue; |
|||
} |
|||
else |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
else if (currentChar == '}') |
|||
{ |
|||
// unmatched brace comment end
|
|||
error = error_bmbpbb; |
|||
break; |
|||
} |
|||
else if (currentChar == '%') |
|||
{ |
|||
// binary
|
|||
currentChar = pSource[m_sourceOffset++]; |
|||
char temp; |
|||
if (currentChar == '%') |
|||
{ |
|||
// double binary
|
|||
currentChar = pSource[m_sourceOffset++]; |
|||
if (!CheckDigit(currentChar, temp, 4)) |
|||
{ |
|||
error = error_idbn; |
|||
break; |
|||
} |
|||
constantBase = 4; |
|||
} |
|||
else |
|||
{ |
|||
if (!CheckDigit(currentChar, temp, 2)) |
|||
{ |
|||
error = error_idbn; |
|||
break; |
|||
} |
|||
constantBase = 2; |
|||
} |
|||
m_sourceOffset--; // back up to first digit
|
|||
// constantBase is now set, so loop back around to read in the constant
|
|||
continue; |
|||
} |
|||
else if (currentChar == '$') |
|||
{ |
|||
// hex
|
|||
currentChar = pSource[m_sourceOffset++]; |
|||
char temp; |
|||
if (!CheckDigit(currentChar, temp, 16)) |
|||
{ |
|||
m_sourceOffset--; |
|||
m_type = type_asm_org; |
|||
break; |
|||
} |
|||
constantBase = 16; |
|||
m_sourceOffset--; // back up to first digit
|
|||
// constantBase is now set, so loop back around to read in the constant
|
|||
continue; |
|||
} |
|||
else if (currentChar >= '0' && currentChar <= '9') |
|||
{ |
|||
// dec
|
|||
constantBase = 10; |
|||
m_sourceOffset--; // back up to first digit
|
|||
// constantBase is now set, so loop back around to read in the constant
|
|||
continue; |
|||
} |
|||
else |
|||
{ |
|||
// symbol
|
|||
currentChar = Uppercase(currentChar); |
|||
if (CheckWordChar(currentChar)) |
|||
{ |
|||
// do word symbol
|
|||
while(CheckWordChar(currentChar) && symbolOffset <= symbol_limit) |
|||
{ |
|||
m_currentSymbol[symbolOffset++] = currentChar; |
|||
currentChar = Uppercase(pSource[m_sourceOffset++]); |
|||
} |
|||
if (symbolOffset > symbol_limit) |
|||
{ |
|||
error = error_sexc; |
|||
} |
|||
else |
|||
{ |
|||
// back up so we point at last char of symbol
|
|||
m_sourceOffset--; |
|||
// terminate symbol
|
|||
m_currentSymbol[symbolOffset] = 0; |
|||
m_pSymbolEntry = m_pSymbolEngine->FindSymbol(m_currentSymbol); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// try non-word symbol (one or two char operators)
|
|||
m_currentSymbol[symbolOffset++] = currentChar; |
|||
currentChar = pSource[m_sourceOffset++]; |
|||
|
|||
bool bDoOneChar = false; |
|||
bool bDoTwoChar = false; |
|||
|
|||
// if the next char is not whitespace or eol
|
|||
if (currentChar > ' ') |
|||
{ |
|||
// three char symbol
|
|||
|
|||
// assign second char into symbol
|
|||
m_currentSymbol[symbolOffset++] = currentChar; |
|||
|
|||
// read third char into symbol
|
|||
m_currentSymbol[symbolOffset++] = pSource[m_sourceOffset++]; |
|||
|
|||
// terminate symbol
|
|||
m_currentSymbol[symbolOffset] = 0; |
|||
|
|||
m_pSymbolEntry = m_pSymbolEngine->FindSymbol(m_currentSymbol); |
|||
if (m_pSymbolEntry == 0) |
|||
{ |
|||
bDoTwoChar = true; |
|||
symbolOffset--; |
|||
} |
|||
} |
|||
|
|||
if (bDoTwoChar) |
|||
{ |
|||
// two char symbol
|
|||
|
|||
// back up so we point at last char of symbol
|
|||
m_sourceOffset--; |
|||
|
|||
// terminate symbol
|
|||
m_currentSymbol[symbolOffset] = 0; |
|||
|
|||
m_pSymbolEntry = m_pSymbolEngine->FindSymbol(m_currentSymbol); |
|||
if (m_pSymbolEntry == 0) |
|||
{ |
|||
bDoOneChar = true; |
|||
symbolOffset--; |
|||
} |
|||
} |
|||
|
|||
if (bDoOneChar || currentChar <= ' ') |
|||
{ |
|||
// one char symbol
|
|||
|
|||
// back up so we point at last char of symbol
|
|||
m_sourceOffset--; |
|||
|
|||
// terminate symbol
|
|||
m_currentSymbol[symbolOffset] = 0; |
|||
|
|||
m_pSymbolEntry = m_pSymbolEngine->FindSymbol(m_currentSymbol); |
|||
if (m_pSymbolEntry == 0) |
|||
{ |
|||
error = error_uc; |
|||
} |
|||
} |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (bConstantOverflow) |
|||
{ |
|||
error = error_ce32b; |
|||
} |
|||
|
|||
// update pointers
|
|||
m_pCompilerData->source_start = sourceStart; |
|||
m_pCompilerData->source_finish = m_sourceOffset; |
|||
|
|||
// if we got a symbol, then set the type, value, etc.
|
|||
if (m_type == 0 && m_pSymbolEntry) |
|||
{ |
|||
SetFromSymbolEntry(); |
|||
} |
|||
|
|||
if (error != error_none) |
|||
{ |
|||
m_pCompilerData->error = true; |
|||
m_pCompilerData->error_msg = g_pErrorStrings[error]; |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
// if the next element is type, then return true, else false, retains value
|
|||
bool Elementizer::GetElement(int type) |
|||
{ |
|||
int value = m_value; // save current value
|
|||
|
|||
bool bEof = false; |
|||
GetNext(bEof); |
|||
|
|||
if (GetType() != type) |
|||
{ |
|||
m_pCompilerData->error = true; |
|||
int errorNum = 0; |
|||
switch (type) |
|||
{ |
|||
case type_left: errorNum = error_eleft; break; |
|||
case type_right: errorNum = error_eright; break; |
|||
case type_rightb: errorNum = error_erightb; break; |
|||
case type_comma: errorNum = error_ecomma; break; |
|||
case type_pound: errorNum = error_epound; break; |
|||
case type_colon: errorNum = error_ecolon; break; |
|||
case type_dot: errorNum = error_edot; break; |
|||
case type_sub: errorNum = error_easn; break; |
|||
case type_end: errorNum = error_eeol; break; |
|||
} |
|||
m_pCompilerData->error_msg = g_pErrorStrings[errorNum]; |
|||
return false; |
|||
} |
|||
|
|||
m_value = value; // restore saved value
|
|||
|
|||
return true; |
|||
} |
|||
|
|||
// check if next element is of the given type, if so return true, if not, backup and return false
|
|||
bool Elementizer::CheckElement(int type) |
|||
{ |
|||
bool bEof = false; |
|||
GetNext(bEof); |
|||
if (GetType() == type) |
|||
{ |
|||
return true; |
|||
} |
|||
Backup(); |
|||
return false; |
|||
} |
|||
|
|||
// scan for the next block element of type, returns true if no error, , bEof will be set to true if eof is hit
|
|||
bool Elementizer::GetNextBlock(int type, bool& bEof) |
|||
{ |
|||
bool bFound = false; |
|||
while(bFound == false) |
|||
{ |
|||
if (GetNext(bEof) == false || bEof == true) |
|||
{ |
|||
break; |
|||
} |
|||
if (GetType() == type_block && GetValue() == type) |
|||
{ |
|||
if (GetColumn() != 1) |
|||
{ |
|||
m_pCompilerData->error = true; |
|||
m_pCompilerData->error_msg = g_pErrorStrings[error_bdmbifc]; |
|||
return false; |
|||
} |
|||
bFound = true; |
|||
} |
|||
} |
|||
// if we found the block or we hit eof, then we got no error so return true
|
|||
return (bFound || bEof); |
|||
} |
|||
|
|||
// returns column of most recent Element gotten
|
|||
int Elementizer::GetColumn() |
|||
{ |
|||
char* pSource = m_pCompilerData->source; |
|||
int sourceStart = m_pCompilerData->source_start; |
|||
if (sourceStart == 0) |
|||
{ |
|||
// we are at the start of the source, so return 1
|
|||
return 1; |
|||
} |
|||
|
|||
// back up until we hit a CR character
|
|||
while(pSource[sourceStart] != 13 && sourceStart > 0) |
|||
{ |
|||
sourceStart--; |
|||
} |
|||
|
|||
// advance forward one, (off of the CR)
|
|||
sourceStart++; |
|||
|
|||
if (sourceStart == m_pCompilerData->source_start) |
|||
{ |
|||
// we are at the start of the line, so return 1
|
|||
return 1; |
|||
} |
|||
|
|||
// adjust source pointer to start of line
|
|||
pSource += sourceStart; |
|||
// adjust sourceStart such that it is how many characters we backed up
|
|||
sourceStart = m_pCompilerData->source_start - sourceStart; |
|||
|
|||
// count the characters we backed up over, accounting for tabs (tabs are 8 chars)
|
|||
int column = 0; |
|||
for (int i = 0; i < sourceStart; i++) |
|||
{ |
|||
if (pSource[i] == 9) |
|||
{ |
|||
column |= 7; |
|||
} |
|||
column++; |
|||
} |
|||
|
|||
return column + 1; |
|||
} |
|||
|
|||
int Elementizer::GetCurrentLineNumber(int &offsetToStartOfLine, int& offsetToEndOfLine) |
|||
{ |
|||
int lineCount = 1; |
|||
|
|||
char* pSource = m_pCompilerData->source; |
|||
int scanEnd = m_pCompilerData->source_start; |
|||
offsetToStartOfLine = -1; |
|||
while (scanEnd > 0) |
|||
{ |
|||
if (pSource[--scanEnd] == 13) |
|||
{ |
|||
if (offsetToStartOfLine == -1) |
|||
{ |
|||
offsetToStartOfLine = scanEnd+1; |
|||
} |
|||
lineCount++; |
|||
} |
|||
} |
|||
if (offsetToStartOfLine == -1) |
|||
{ |
|||
offsetToStartOfLine = 0; |
|||
} |
|||
scanEnd = m_pCompilerData->source_start; |
|||
while (pSource[scanEnd] != 0) |
|||
{ |
|||
if (pSource[scanEnd] == 13 || pSource[scanEnd] == 0) |
|||
{ |
|||
break; |
|||
} |
|||
scanEnd++; |
|||
} |
|||
offsetToEndOfLine = scanEnd; |
|||
|
|||
return lineCount; |
|||
} |
|||
|
|||
// backup to the previous element
|
|||
void Elementizer::Backup() |
|||
{ |
|||
m_backIndex--; |
|||
m_sourceOffset = m_backOffsets[m_backIndex&0x03]; |
|||
m_sourceFlags = m_backFlags[m_backIndex&0x03]; |
|||
} |
|||
|
|||
void Elementizer::ObjConToCon() |
|||
{ |
|||
m_type -= (type_objcon - type_con); |
|||
} |
|||
|
|||
void Elementizer::DatResToLong() |
|||
{ |
|||
if (m_type == type_dat_long_res) |
|||
{ |
|||
m_type = type_dat_long; |
|||
} |
|||
} |
|||
|
|||
bool Elementizer::SubToNeg() |
|||
{ |
|||
if (m_type == type_binary && m_opType == op_sub) |
|||
{ |
|||
m_type = type_unary; |
|||
m_opType = op_neg; |
|||
m_value = 0; |
|||
m_value_2 = 0; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
bool Elementizer::NegConToCon() |
|||
{ |
|||
if (m_type == type_binary && m_opType == op_sub) |
|||
{ |
|||
int savedValue = m_value; |
|||
bool bEof = false; |
|||
if (!GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (m_type == type_con) |
|||
{ |
|||
m_value = -m_value; |
|||
} |
|||
else if (m_type == type_con_float) |
|||
{ |
|||
m_value |= 0x80000000; |
|||
} |
|||
else |
|||
{ |
|||
Backup(); |
|||
m_type = type_binary; |
|||
m_asm = -1; |
|||
m_opType = op_sub; |
|||
m_value = savedValue; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool Elementizer::FindSymbol(const char* symbol) |
|||
{ |
|||
m_pSymbolEntry = m_pSymbolEngine->FindSymbol(symbol); |
|||
SetFromSymbolEntry(); |
|||
return true; |
|||
} |
|||
|
|||
void Elementizer::BackupSymbol() |
|||
{ |
|||
strcpy(m_pCompilerData->symbolBackup, m_currentSymbol); |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,122 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// Elementizer.h
|
|||
//
|
|||
|
|||
#ifndef _ELEMENTIZER_H_ |
|||
#define _ELEMENTIZER_H_ |
|||
|
|||
struct CompilerDataInternal; |
|||
class SymbolEngine; |
|||
class SymbolTableEntry; |
|||
|
|||
const int state_stack_limit = 32; |
|||
|
|||
class Elementizer |
|||
{ |
|||
CompilerDataInternal* m_pCompilerData; |
|||
SymbolEngine* m_pSymbolEngine; |
|||
|
|||
int m_sourceOffset; |
|||
unsigned char m_sourceFlags; |
|||
|
|||
SymbolTableEntry* m_pSymbolEntry; |
|||
int m_type; |
|||
int m_value; |
|||
int m_value_2; |
|||
int m_opType; |
|||
int m_asm; |
|||
bool m_dual; |
|||
|
|||
unsigned char m_backIndex; |
|||
int m_backOffsets[4]; |
|||
unsigned char m_backFlags[4]; |
|||
|
|||
char m_currentSymbol[symbol_limit+2]; |
|||
|
|||
void SetFromSymbolEntry(); |
|||
|
|||
public: |
|||
Elementizer(CompilerDataInternal* pCompilerData, SymbolEngine* pSymbolEngine) |
|||
: m_pCompilerData(pCompilerData) |
|||
, m_pSymbolEngine(pSymbolEngine) |
|||
, m_sourceOffset(0) |
|||
, m_sourceFlags(0) |
|||
, m_backIndex(0) |
|||
{ |
|||
for(int i = 0; i < 4; i++) |
|||
{ |
|||
m_backOffsets[i] = 0; |
|||
m_backFlags[0] = 0; |
|||
} |
|||
} |
|||
|
|||
void Reset(); // reset to start of source
|
|||
|
|||
bool GetNext(bool& bEof); // get the next element in source, returns true no error, bEof will be set to true if eof is hit
|
|||
bool GetElement(int type); // if the next element is type, then return true, else false, retains value
|
|||
bool CheckElement(int type); // check if next element is of the given type, if so return true, if not, backup and return false
|
|||
bool GetNextBlock(int type, bool& bEof); // scan for the next block element of type, returns true if no error, , bEof will be set to true if eof is hit
|
|||
bool FindSymbol(const char* symbol); // lookup a symbol in the symbol table and set it as the current element
|
|||
void Backup(); // backup to the previous element
|
|||
|
|||
void BackupSymbol(); // copy the current symbol into g_pCompilerData->symbolBackup
|
|||
|
|||
int GetColumn(); // returns column of the element pointed to by g_pCompilerData->source_start
|
|||
|
|||
int GetSourcePtr() // used to save the current source pointer so it can be put back
|
|||
{ |
|||
return m_sourceOffset; |
|||
} |
|||
void SetSourcePtr(int value) // used to set the source pointer back to a previously saved value
|
|||
{ |
|||
m_sourceOffset = value; |
|||
} |
|||
|
|||
int GetType() { return m_type; } // symbol's type
|
|||
int GetValue() { return m_value; } // only valid if m_type != type_undefined
|
|||
int GetValue2() { return m_value_2; } // only valid if m_type != type_undefined
|
|||
int GetOpType() { return m_opType; } // only valid for operator symbols
|
|||
int GetAsm() { return m_asm; } // only valid for dual symbols + op_log_and & op_log_or
|
|||
bool IsDual() { return m_dual; } // true if is a dual symbol
|
|||
char* GetCurrentSymbol() // returns the string for the symbol
|
|||
{ |
|||
return &(m_currentSymbol[0]); |
|||
} |
|||
int GetCurrentLineNumber(int &offsetToStartOfLine, int& offsetToEndOfLine); |
|||
|
|||
bool SubToNeg(); // convert a sub to a neg
|
|||
void ObjConToCon(); // convert type_objcon_xx to type_con_xx
|
|||
void DatResToLong(); // convert type_dat_long_res to type_dat_long
|
|||
bool NegConToCon(); // convert -constant to constant
|
|||
}; |
|||
|
|||
#endif // _ELEMENTIZER_H_
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,154 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// ErrorStrings.cpp
|
|||
//
|
|||
|
|||
const char* g_pErrorStrings[] = |
|||
{ |
|||
"Address is not long", |
|||
"Address is out of range", |
|||
"\"}\" must be preceeded by \"{\" to form a comment", |
|||
"Block designator must be in first column", |
|||
"Blocknest stack overflow", |
|||
"Cannot compute square root of negative floating-point number", |
|||
"Constant exceeds 32 bits", |
|||
"_CLKFREQ or _XINFREQ must be specified", |
|||
"CALL symbol must not exceed 252 characters", |
|||
"_CLKFREQ/_XINFREQ not allowed with RCFAST/RCSLOW", |
|||
"_CLKFREQ/_XINFREQ specified without _CLKMODE", |
|||
"Divide by zero", |
|||
"Destination register cannot exceed $1FF", |
|||
"Expected an assembly effect or end of line", |
|||
"Expected an assembly effect", |
|||
"Expected an assembly instruction", |
|||
"Expected a binary operator or \")\"", |
|||
"Expected a constant name", |
|||
"Expected a constant, unary operator, or \"(\"", |
|||
"Expected a DAT symbol", |
|||
"Expected an expression term", |
|||
"Expected an instruction or variable", |
|||
"Expected a local symbol", |
|||
"Expected a memory variable after \"@\"", |
|||
"Expected a subroutine name", |
|||
"Expected a subroutine or object name", |
|||
"Expected a terminating quote", |
|||
"Expected a unique object name", |
|||
"Expected a variable", |
|||
"Expected a unique constant name or \"#\"", |
|||
"Expected a unique name, BYTE, WORD, LONG, or assembly instruction", |
|||
"Expected a unique parameter name", |
|||
"Expected a unique result name", |
|||
"Expected a unique subroutine name", |
|||
"Expected a unique variable name", |
|||
"Expected BYTE, WORD, or LONG", |
|||
"Expected \",\" or end of line", |
|||
"Expected \":\"", |
|||
"Expected \",\"", |
|||
"Expected \",\" or \")\"", |
|||
"Either _CLKFREQ or _XINFREQ must be specified, but not both", |
|||
"Expected \".\"", |
|||
"Expected end of line", |
|||
"Expected \"=\" \"[\" \",\" or end of line", |
|||
"Expected FROM", |
|||
"Expression is too complex", |
|||
"Expected \"(\"", |
|||
"Expected \"[\"", |
|||
"Expected PRECOMPILE or ARCHIVE", |
|||
"Expected \"|\" or end of line", |
|||
"Expected \"#\"", |
|||
"Expected \"}\"", |
|||
"Expected \"}}\"", |
|||
"Expected \")\"", |
|||
"Expected \"]\"", |
|||
"Empty string", |
|||
"Expected STEP or end of line", |
|||
"Expected TO", |
|||
"Filename too long", |
|||
"Floating-point constant must be within +/- 3.4e+38", |
|||
"Floating-point not allowed in integer expression", |
|||
"Floating-point overflow", |
|||
"Invalid binary number", |
|||
"Invalid _CLKMODE specified", |
|||
"Invalid double-binary number", |
|||
"Internal DAT file not found", |
|||
"Invalid filename character", |
|||
"Invalid filename, use \"FilenameInQuotes\"", |
|||
"Integer not allowed in floating-point expression", |
|||
"Internal", |
|||
"Integer operator not allowed in floating-point expression", |
|||
"Limit of 64 cases exceeded", |
|||
"Limit of 8 nested blocks exceeded", |
|||
"Limit of 32 unique objects exceeded", |
|||
"Limit of 32 unique DAT files exceeded", |
|||
"Limit of 32 unique PRECOMPILE files exceeded", |
|||
"Limit of 32 unique ARCHIVE files exceeded", |
|||
"List is too large", |
|||
"Limit of 1,048,576 DAT symbols exceeded", |
|||
"Limit of 16 ELSEIFs exceeded", |
|||
"Limit of 4096 local variables exceeded", |
|||
"Limit of 15 parameters exceeded", |
|||
"Limit of 256 subroutines + objects exceeded", |
|||
"Memory instructions cannot use WR/NR", |
|||
"No cases encountered", |
|||
"No PUB routines found", |
|||
"Object count must be from 1 to 255", |
|||
"Object distiller overflow", |
|||
"Origin exceeds FIT limit", |
|||
"Object exceeds 128k (before distilling)", |
|||
"Origin exceeds $1F0 limit", |
|||
"\"$\" is not allowed here", |
|||
"OTHER must be last case", |
|||
"PUB/CON list overflow", |
|||
"?_RET address is not long", |
|||
"?_RET address is out of range", |
|||
"Register is not allowed here", |
|||
"RES is not allowed in ORGX mode", |
|||
"_STACK and _FREE must sum to under 8k", |
|||
"Symbols _CLKMODE, _CLKFREQ, _XINFREQ can only be used as integer constants", |
|||
"String characters must range from 1 to 255", |
|||
"Symbol _DEBUG can only be used as an integer constant", |
|||
"Symbol exceeds 256 characters", |
|||
"Symbol is already defined", |
|||
"STRING not allowed here", |
|||
"Size override must be larger", |
|||
"Size override must be smaller", |
|||
"Source register/constant cannot exceed $1FF", |
|||
"Symbols _STACK and _FREE can only be used as integer constants", |
|||
"Symbol table is full", |
|||
"This instruction is only allowed within a REPEAT block", |
|||
"Too many string constants", |
|||
"Too many string constant characters", |
|||
"Too much variable space is declared", |
|||
"Unrecognized character", |
|||
"Undefined ?_RET symbol", |
|||
"Undefined symbol", |
|||
"Variable needs an operator" |
|||
}; |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,162 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// ErrorStrings.h
|
|||
//
|
|||
|
|||
#ifndef _ERROR_STRINGS_H_ |
|||
#define _ERROR_STRINGS_H_ |
|||
|
|||
enum errorType |
|||
{ |
|||
error_none = -1, |
|||
error_ainl = 0, |
|||
error_aioor, |
|||
error_bmbpbb, |
|||
error_bdmbifc, |
|||
error_bnso, |
|||
error_ccsronfp, |
|||
error_ce32b, |
|||
error_coxmbs, |
|||
error_csmnexc, |
|||
error_cxnawrc, |
|||
error_cxswcm, |
|||
error_dbz, |
|||
error_drcex, |
|||
error_eaaeoeol, |
|||
error_eaasme, |
|||
error_eaasmi, |
|||
error_eaboor, |
|||
error_eacn, |
|||
error_eacuool, |
|||
error_eads, |
|||
error_eaet, |
|||
error_eaiov, |
|||
error_eals, |
|||
error_eamvaa, |
|||
error_easn, |
|||
error_easoon, |
|||
error_eatq, |
|||
error_eauon, |
|||
error_eav, |
|||
error_eaucnop, |
|||
error_eaunbwlo, |
|||
error_eaupn, |
|||
error_eaurn, |
|||
error_eausn, |
|||
error_eauvn, |
|||
error_ebwol, |
|||
error_ecoeol, |
|||
error_ecolon, |
|||
error_ecomma, |
|||
error_ecor, |
|||
error_ecoxmbs, |
|||
error_edot, |
|||
error_eeol, |
|||
error_eelcoeol, |
|||
error_efrom, |
|||
error_eitc, |
|||
error_eleft, |
|||
error_eleftb, |
|||
error_epoa, |
|||
error_epoeol, |
|||
error_epound, |
|||
error_erb, |
|||
error_erbb, |
|||
error_eright, |
|||
error_erightb, |
|||
error_es, |
|||
error_esoeol, |
|||
error_eto, |
|||
error_ftl, |
|||
error_fpcmbw, |
|||
error_fpnaiie, |
|||
error_fpo, |
|||
error_ibn, |
|||
error_icms, |
|||
error_idbn, |
|||
error_idfnf, |
|||
error_ifc, |
|||
error_ifufiq, |
|||
error_inaifpe, |
|||
error_internal, |
|||
error_ionaifpe, |
|||
error_loxce, |
|||
error_loxnbe, |
|||
error_loxuoe, |
|||
error_loxudfe, |
|||
error_loxupfe, |
|||
error_loxuafe, |
|||
error_litl, |
|||
error_loxdse, |
|||
error_loxee, |
|||
error_loxlve, |
|||
error_loxpe, |
|||
error_loxspoe, |
|||
error_micuwn, |
|||
error_nce, |
|||
error_nprf, |
|||
error_ocmbf1tx, |
|||
error_odo, |
|||
error_oefl, |
|||
error_oex, |
|||
error_oexl, |
|||
error_oinah, |
|||
error_omblc, |
|||
error_pclo, |
|||
error_rainl, |
|||
error_raioor, |
|||
error_rinah, |
|||
error_rinaiom, |
|||
error_safms, |
|||
error_sccx, |
|||
error_scmr, |
|||
error_sdcobu, |
|||
error_sexc, |
|||
error_siad, |
|||
error_snah, |
|||
error_sombl, |
|||
error_sombs, |
|||
error_srccex, |
|||
error_ssaf, |
|||
error_stif, |
|||
error_tioawarb, |
|||
error_tmsc, |
|||
error_tmscc, |
|||
error_tmvsid, |
|||
error_uc, |
|||
error_urs, |
|||
error_us, |
|||
error_vnao |
|||
}; |
|||
|
|||
extern const char* g_pErrorStrings[]; |
|||
|
|||
#endif // _ERROR_STRINGS_H_
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,977 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// ExpressionResolver.cpp
|
|||
//
|
|||
|
|||
#include <string.h> |
|||
#include <math.h> |
|||
#include "Utilities.h" |
|||
#include "PropellerCompilerInternal.h" |
|||
#include "SymbolEngine.h" |
|||
#include "Elementizer.h" |
|||
#include "ErrorStrings.h" |
|||
|
|||
//bool GetTryValue(bool bMustResolve, bool bInteger, bool bOperandMode = false); // declared in Utilities.h
|
|||
|
|||
//////////////////////////////////////////
|
|||
// declarations of internal functions
|
|||
//
|
|||
|
|||
void ResolveExpression(); |
|||
void ResolveSubExpression(int precedence); |
|||
void GetTerm(int& precedence); |
|||
|
|||
bool CheckUndefined(bool& bUndefined); |
|||
bool CheckDat(); |
|||
bool CheckConstant(bool& bConstant); |
|||
bool GetObjSymbol(int type, char id); |
|||
|
|||
bool PreviewOp(); |
|||
bool PerformPush(); |
|||
bool PerformBinary(); |
|||
bool PerformOp(); |
|||
|
|||
//////////////////////////////////////////
|
|||
// exported functions
|
|||
//
|
|||
|
|||
// only valid after calling GetTryValue() with bMustResolve set to true and it returned true
|
|||
int GetResult() |
|||
{ |
|||
return g_pCompilerData->mathStack[g_pCompilerData->mathCurrent - 1]; |
|||
} |
|||
|
|||
// if this succeeds and bMustResolve it true then, the result is in g_pCompilerData->mathStack[g_pCompilerData->mathCurrent-1]
|
|||
bool GetTryValue(bool bMustResolve, bool bInteger, bool bOperandMode) |
|||
{ |
|||
g_pCompilerData->intMode = bInteger ? 1 : 0; |
|||
g_pCompilerData->bMustResolve = bMustResolve; |
|||
g_pCompilerData->bOperandMode = bOperandMode; |
|||
g_pCompilerData->mathCurrent = 0; |
|||
g_pCompilerData->bUndefined = false; |
|||
g_pCompilerData->currentOp = 0; |
|||
|
|||
bool bEof = false; |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
int save_start = g_pCompilerData->source_start; |
|||
g_pElementizer->Backup(); |
|||
|
|||
// results are put into g_pCompilerData
|
|||
ResolveExpression(); |
|||
|
|||
if (g_pCompilerData->error) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
g_pElementizer->Backup(); |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pCompilerData->source_start = save_start; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
//////////////////////////////////////////
|
|||
// internal function definitions
|
|||
//
|
|||
|
|||
void ResolveExpression() |
|||
{ |
|||
g_pCompilerData->precedence = 11; |
|||
ResolveSubExpression(g_pCompilerData->precedence - 1); |
|||
} |
|||
|
|||
void ResolveSubExpression(int precedence) |
|||
{ |
|||
if (precedence < 0) |
|||
{ |
|||
GetTerm(precedence); |
|||
} |
|||
else |
|||
{ |
|||
ResolveSubExpression(precedence - 1); |
|||
} |
|||
|
|||
if (g_pCompilerData->error) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
bool bEof = false; |
|||
|
|||
while (!bEof) |
|||
{ |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return; |
|||
} |
|||
if (g_pElementizer->GetType() != type_binary) |
|||
{ |
|||
g_pElementizer->Backup(); |
|||
return; |
|||
} |
|||
if (!PreviewOp()) |
|||
{ |
|||
return; |
|||
} |
|||
if (precedence != g_pElementizer->GetValue()) |
|||
{ |
|||
g_pElementizer->Backup(); |
|||
return; |
|||
} |
|||
g_pCompilerData->savedOp[g_pCompilerData->currentOp] = g_pElementizer->GetOpType(); |
|||
g_pCompilerData->currentOp++; |
|||
int save_start = g_pCompilerData->source_start; |
|||
int save_finish = g_pCompilerData->source_finish; |
|||
ResolveSubExpression(precedence - 1); |
|||
if (g_pCompilerData->error) |
|||
{ |
|||
return; |
|||
} |
|||
g_pCompilerData->source_start = save_start; |
|||
g_pCompilerData->source_finish = save_finish; |
|||
if (!PerformBinary()) |
|||
{ |
|||
return; |
|||
} |
|||
g_pCompilerData->currentOp--; |
|||
} |
|||
} |
|||
|
|||
void GetTerm(int& precedence) |
|||
{ |
|||
bool bEof = false; |
|||
|
|||
// skip over any leading +'s
|
|||
do |
|||
{ |
|||
g_pElementizer->GetNext(bEof); |
|||
if (g_pElementizer->GetType() == type_binary && g_pElementizer->GetOpType() == op_add) |
|||
{ |
|||
continue; |
|||
} |
|||
break; |
|||
} while (!bEof); |
|||
|
|||
bool bConstant = false; |
|||
if (!CheckConstant(bConstant)) |
|||
{ |
|||
if (g_pCompilerData->error) |
|||
{ |
|||
return; |
|||
} |
|||
} |
|||
if (bConstant) |
|||
{ |
|||
PerformPush(); |
|||
return; |
|||
} |
|||
|
|||
if (g_pElementizer->SubToNeg()) |
|||
{ |
|||
precedence = 0; |
|||
} |
|||
|
|||
if (g_pElementizer->GetType() == type_unary) |
|||
{ |
|||
if (!PreviewOp()) |
|||
{ |
|||
return; |
|||
} |
|||
precedence = g_pElementizer->GetValue(); // for unary types, value = precedence
|
|||
int save_start = g_pCompilerData->source_start; |
|||
int save_finish = g_pCompilerData->source_finish; |
|||
g_pCompilerData->savedOp[g_pCompilerData->currentOp] = g_pElementizer->GetOpType(); |
|||
g_pCompilerData->currentOp++; |
|||
ResolveSubExpression(precedence - 1); |
|||
if (g_pCompilerData->error) |
|||
{ |
|||
return; |
|||
} |
|||
g_pCompilerData->source_start = save_start; |
|||
g_pCompilerData->source_finish = save_finish; |
|||
if (!PerformOp()) |
|||
{ |
|||
return; |
|||
} |
|||
g_pCompilerData->currentOp--; |
|||
} |
|||
else if (g_pElementizer->GetType() == type_left) |
|||
{ |
|||
ResolveExpression(); |
|||
if (!g_pElementizer->GetElement(type_right)) |
|||
{ |
|||
return; |
|||
} |
|||
} |
|||
else if (g_pCompilerData->bMustResolve) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eacuool]; |
|||
// when we return from here, the calling code will return due to error = true
|
|||
} |
|||
} |
|||
|
|||
bool CheckUndefined(bool& bUndefined) |
|||
{ |
|||
if (g_pElementizer->GetType() == type_undefined) |
|||
{ |
|||
g_pCompilerData->bUndefined = bUndefined = true; |
|||
|
|||
int save_start = g_pCompilerData->source_start; |
|||
int save_finish = g_pCompilerData->source_finish; |
|||
if(g_pElementizer->CheckElement(type_pound)) |
|||
{ |
|||
int length = 0; |
|||
if (!GetSymbol(&length)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (length == 0) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eacn]; |
|||
return false; |
|||
} |
|||
} |
|||
g_pCompilerData->source_start = save_start; |
|||
g_pCompilerData->source_finish = save_finish; |
|||
|
|||
if (g_pCompilerData->bMustResolve) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_us]; |
|||
return false; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
bUndefined = false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool CheckDat() |
|||
{ |
|||
if (g_pCompilerData->bOperandMode) |
|||
{ |
|||
g_pElementizer->DatResToLong(); |
|||
} |
|||
if ((g_pElementizer->GetType() == type_dat_byte) || |
|||
(g_pElementizer->GetType() == type_dat_word) || |
|||
(g_pElementizer->GetType() == type_dat_long)) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
bool CheckConstant(bool& bConstant) |
|||
{ |
|||
bConstant = true; |
|||
|
|||
if (g_pElementizer->GetType() == type_con) |
|||
{ |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_fpnaiie]; |
|||
return false; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->intMode = 1; |
|||
} |
|||
g_pCompilerData->intermediateResult = g_pElementizer->GetValue(); |
|||
return true; |
|||
} |
|||
else if (g_pElementizer->GetType() == type_con_float) |
|||
{ |
|||
if (g_pCompilerData->intMode == 1) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_inaifpe]; |
|||
return false; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->intMode = 2; |
|||
} |
|||
g_pCompilerData->intermediateResult = g_pElementizer->GetValue(); |
|||
return true; |
|||
} |
|||
else if (g_pElementizer->GetType() == type_float) |
|||
{ |
|||
if (g_pCompilerData->intMode == 1) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_inaifpe]; |
|||
return false; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->intMode = 2; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_left)) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pCompilerData->intMode = 1; |
|||
ResolveExpression(); // integer mode
|
|||
g_pCompilerData->intMode = 2; |
|||
if (!g_pElementizer->GetElement(type_right)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
int value = g_pCompilerData->mathStack[g_pCompilerData->mathCurrent - 1]; |
|||
g_pCompilerData->mathCurrent--; |
|||
float fValue = (float)(value); |
|||
g_pCompilerData->intermediateResult = *(int*)(&fValue); |
|||
return true; |
|||
} |
|||
else if (g_pElementizer->GetType() == type_round) |
|||
{ |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_fpnaiie]; |
|||
return false; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->intMode = 1; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_left)) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pCompilerData->intMode = 2; |
|||
ResolveExpression(); // float mode
|
|||
g_pCompilerData->intMode = 1; |
|||
if (!g_pElementizer->GetElement(type_right)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// convert float to rounded integer
|
|||
int value = g_pCompilerData->mathStack[g_pCompilerData->mathCurrent - 1]; |
|||
g_pCompilerData->mathCurrent--; |
|||
float fValue = *(float*)(&value); |
|||
g_pCompilerData->intermediateResult = (int)(fValue + 0.5f); |
|||
return true; |
|||
} |
|||
else if (g_pElementizer->GetType() == type_trunc) |
|||
{ |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_fpnaiie]; |
|||
return false; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->intMode = 1; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_left)) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pCompilerData->intMode = 2; |
|||
ResolveExpression(); // float mode
|
|||
g_pCompilerData->intMode = 1; |
|||
if (!g_pElementizer->GetElement(type_right)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// convert float to truncated integer
|
|||
int value = g_pCompilerData->mathStack[g_pCompilerData->mathCurrent - 1]; |
|||
g_pCompilerData->mathCurrent--; |
|||
float fValue = *(float*)(&value); |
|||
g_pCompilerData->intermediateResult = (int)(fValue); |
|||
return true; |
|||
} |
|||
|
|||
if (g_pCompilerData->bOperandMode) |
|||
{ |
|||
bool bLocal = false; |
|||
if (!CheckLocal(bLocal)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
bool bUndefined = false; |
|||
if (!CheckUndefined(bUndefined)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (bUndefined) |
|||
{ |
|||
if (!g_pCompilerData->bMustResolve) |
|||
{ |
|||
g_pCompilerData->intermediateResult = 0; |
|||
} |
|||
return true; |
|||
} |
|||
else if (g_pElementizer->GetType() == type_asm_org) |
|||
{ |
|||
if (g_pCompilerData->bOperandMode) |
|||
{ |
|||
g_pCompilerData->intermediateResult = g_pCompilerData->cog_org >> 2; |
|||
return true; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_oinah]; |
|||
return false; |
|||
} |
|||
} |
|||
else if (g_pElementizer->GetType() == type_reg) |
|||
{ |
|||
if (g_pCompilerData->bOperandMode) |
|||
{ |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_fpnaiie]; |
|||
return false; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->intMode = 1; |
|||
} |
|||
g_pCompilerData->intermediateResult = g_pElementizer->GetValue(); |
|||
g_pCompilerData->intermediateResult |= 0x1E0; |
|||
return true; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_rinah]; |
|||
return false; |
|||
} |
|||
} |
|||
else if (g_pElementizer->GetType() == type_obj) |
|||
{ |
|||
if (!g_pElementizer->GetElement(type_pound)) |
|||
{ |
|||
return false; |
|||
} |
|||
char id = (g_pElementizer->GetValue() & 0x0000FF00) >> 8; |
|||
if (!GetObjSymbol(type_objcon, id)) |
|||
{ |
|||
return false; |
|||
} |
|||
return CheckConstant(bConstant); |
|||
} |
|||
else if (g_pElementizer->GetType() == type_at) |
|||
{ |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_fpnaiie]; |
|||
return false; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->intMode = 1; |
|||
} |
|||
bool bEof = false; |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (CheckDat()) |
|||
{ |
|||
g_pCompilerData->intermediateResult = g_pElementizer->GetValue(); |
|||
return true; |
|||
} |
|||
bool bUndefinedCheck = false; |
|||
if (!CheckUndefined(bUndefinedCheck)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (bUndefinedCheck) |
|||
{ |
|||
if (!g_pCompilerData->bMustResolve) |
|||
{ |
|||
g_pCompilerData->intermediateResult = 0; |
|||
} |
|||
bConstant = false; |
|||
return true; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eads]; |
|||
return false; |
|||
} |
|||
} |
|||
else if (CheckDat()) |
|||
{ |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_fpnaiie]; |
|||
return false; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->intMode = 1; |
|||
} |
|||
if (g_pCompilerData->bOperandMode) |
|||
{ |
|||
// use org address in value 2
|
|||
g_pCompilerData->intermediateResult = g_pElementizer->GetValue2(); |
|||
|
|||
// check for valid long address
|
|||
if ((g_pCompilerData->intermediateResult & 0x03) != 0) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_ainl]; |
|||
return false; |
|||
} |
|||
|
|||
// convert to long index
|
|||
g_pCompilerData->intermediateResult >>= 2; |
|||
|
|||
if (g_pCompilerData->intermediateResult >= 0x1F0) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_aioor]; |
|||
return false; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->intermediateResult = g_pElementizer->GetValue(); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bConstant = false; |
|||
return true; |
|||
} |
|||
|
|||
bool PreviewOp() |
|||
{ |
|||
int i = g_pElementizer->GetOpType(); |
|||
int check = 0x00AACD8F; // 00000000 10101010 11001101 10001111
|
|||
check >>= i; |
|||
if (check & 1) |
|||
{ |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
// integer only op while in float mode
|
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_ionaifpe]; |
|||
return false; |
|||
} |
|||
|
|||
// force integer mode
|
|||
g_pCompilerData->intMode = 1; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool PerformPush() |
|||
{ |
|||
if (g_pCompilerData->mathCurrent > 9) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eitc]; |
|||
return false; |
|||
} |
|||
|
|||
g_pCompilerData->mathStack[g_pCompilerData->mathCurrent] = g_pCompilerData->intermediateResult; |
|||
g_pCompilerData->mathCurrent++; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool PerformBinary() |
|||
{ |
|||
g_pCompilerData->mathCurrent--; |
|||
return PerformOp(); |
|||
} |
|||
|
|||
bool PerformOp() |
|||
{ |
|||
if (g_pCompilerData->bUndefined) |
|||
{ |
|||
g_pCompilerData->mathStack[g_pCompilerData->mathCurrent-1] = 0; |
|||
return true; |
|||
} |
|||
|
|||
int value1 = g_pCompilerData->mathStack[g_pCompilerData->mathCurrent - 1]; |
|||
int value2 = g_pCompilerData->mathStack[g_pCompilerData->mathCurrent]; |
|||
|
|||
float fValue1 = *((float*)(&value1)); |
|||
float fValue2 = *((float*)(&value2)); |
|||
|
|||
int result = 0; |
|||
float fResult = 0.0f; |
|||
|
|||
switch(g_pCompilerData->savedOp[g_pCompilerData->currentOp-1]) |
|||
{ |
|||
case op_ror: |
|||
result = ror(value1, (value2 & 0xFF)); |
|||
break; |
|||
|
|||
case op_rol: |
|||
result = rol(value1, (value2 & 0xFF)); |
|||
break; |
|||
|
|||
case op_shr: |
|||
result = (unsigned int)value1 >> (value2 & 0xFF); |
|||
break; |
|||
|
|||
case op_shl: |
|||
result = value1 << (value2 & 0xFF); |
|||
break; |
|||
|
|||
case op_min: // limit minimum
|
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
fResult = (fValue1 < fValue2) ? fValue2 : fValue1; |
|||
} |
|||
else |
|||
{ |
|||
result = (value1 < value2) ? value2 : value1; |
|||
} |
|||
break; |
|||
|
|||
case op_max: // limit maximum
|
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
fResult = (fValue1 > fValue2) ? fValue2 : fValue1; |
|||
} |
|||
else |
|||
{ |
|||
result = (value1 > value2) ? value2 : value1; |
|||
} |
|||
break; |
|||
|
|||
case op_neg: |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
// float neg (using xor)
|
|||
fResult = -fValue1; |
|||
} |
|||
else |
|||
{ |
|||
result = -value1; |
|||
} |
|||
break; |
|||
|
|||
case op_not: |
|||
result = ~value1; |
|||
break; |
|||
|
|||
case op_and: |
|||
result = value1 & value2; |
|||
break; |
|||
|
|||
case op_abs: |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
// float abs
|
|||
fResult = (float)fabs(fValue1); |
|||
} |
|||
else |
|||
{ |
|||
result = (value1 < 0) ? -value1 : value1; |
|||
} |
|||
break; |
|||
|
|||
case op_or: |
|||
result = value1 | value2; |
|||
break; |
|||
|
|||
case op_xor: |
|||
result = value1 ^ value2; |
|||
break; |
|||
|
|||
case op_add: |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
// float add
|
|||
fResult = fValue1 + fValue2; |
|||
} |
|||
else |
|||
{ |
|||
result = value1 + value2; |
|||
} |
|||
break; |
|||
|
|||
case op_sub: |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
// float sub
|
|||
fResult = fValue1 - fValue2; |
|||
} |
|||
else |
|||
{ |
|||
result = value1 - value2; |
|||
} |
|||
break; |
|||
|
|||
case op_sar: |
|||
result = value1 >> (value2 & 0xFF); |
|||
break; |
|||
|
|||
case op_rev: |
|||
value2 &= 0xFF; |
|||
result = 0; |
|||
for (int i = 0; i < value2; i++) |
|||
{ |
|||
result <<= 1; |
|||
result |= (value1 & 0x01); |
|||
value1 >>= 1; |
|||
} |
|||
break; |
|||
|
|||
case op_log_and: |
|||
if (value1 != 0) |
|||
{ |
|||
value1 = 0xFFFFFFFF; |
|||
} |
|||
if (value2 != 0) |
|||
{ |
|||
value2 = 0xFFFFFFFF; |
|||
} |
|||
result = value1 & value2; |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
if (result != 0) |
|||
{ |
|||
fResult = 1.0f; |
|||
} |
|||
else |
|||
{ |
|||
fResult = 0.0f; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case op_ncd: |
|||
result = 32; |
|||
while(!(value1 & 0x80000000) && result > 0) |
|||
{ |
|||
result--; |
|||
value1 <<= 1; |
|||
} |
|||
break; |
|||
|
|||
case op_log_or: |
|||
if (value1 != 0) |
|||
{ |
|||
value1 = 0xFFFFFFFF; |
|||
} |
|||
if (value2 != 0) |
|||
{ |
|||
value2 = 0xFFFFFFFF; |
|||
} |
|||
result = value1 | value2; |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
if (result != 0) |
|||
{ |
|||
fResult = 1.0f; |
|||
} |
|||
else |
|||
{ |
|||
fResult = 0.0f; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case op_dcd: |
|||
result = 1; |
|||
result <<= (value1 & 0xFF); |
|||
break; |
|||
|
|||
case op_mul: |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
// float mul
|
|||
fResult = fValue1 * fValue2; |
|||
} |
|||
else |
|||
{ |
|||
result = value1 * value2; |
|||
} |
|||
break; |
|||
|
|||
case op_scl: |
|||
{ |
|||
// calculate the upper 32bits of the 64bit result of multiplying two 32bit numbers
|
|||
// I did it this way to avoid using compiler specific stuff.
|
|||
int a = (value1 >> 16) & 0xffff; |
|||
int b = value1 & 0xffff; |
|||
int c = (value2 >> 16) & 0xffff; |
|||
int d = value2 & 0xffff; |
|||
int x = a * d + c * b; |
|||
int y = (((b * d) >> 16) & 0xffff) + x; |
|||
result = (y >> 16) & 0xffff; |
|||
result += a * c; |
|||
} |
|||
break; |
|||
|
|||
case op_div: |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
// float div
|
|||
fResult = fValue1 / fValue2; |
|||
} |
|||
else |
|||
{ |
|||
result = value1 / value2; |
|||
} |
|||
break; |
|||
|
|||
case op_rem: // remainder (mod)
|
|||
result = value1 % value2; |
|||
break; |
|||
|
|||
case op_sqr: // sqrt
|
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
// float sqrt
|
|||
if (fValue1 < 0.0f) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_ccsronfp]; |
|||
return false; |
|||
} |
|||
fResult = (float)sqrt(fValue1); |
|||
} |
|||
else |
|||
{ |
|||
for (result = 0; value1 >= (2*result)+1; value1 -= (2*result++)+1); |
|||
} |
|||
break; |
|||
|
|||
case op_cmp_b: |
|||
case op_cmp_a: |
|||
case op_cmp_ne: |
|||
case op_cmp_e: |
|||
case op_cmp_be: |
|||
case op_cmp_ae: |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
// float cmp
|
|||
if (fValue1 < fValue2) |
|||
{ |
|||
result = 1; |
|||
} |
|||
else if (fValue1 > fValue2) |
|||
{ |
|||
result = 2; |
|||
} |
|||
else |
|||
{ |
|||
result = 4; |
|||
} |
|||
result &= g_pCompilerData->savedOp[g_pCompilerData->currentOp-1]; |
|||
if (result != 0) |
|||
{ |
|||
fResult = 1.0f; |
|||
} |
|||
else |
|||
{ |
|||
fResult = 0.0f; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (value1 < value2) |
|||
{ |
|||
result = 1; |
|||
} |
|||
else if (value1 > value2) |
|||
{ |
|||
result = 2; |
|||
} |
|||
else |
|||
{ |
|||
result = 4; |
|||
} |
|||
result &= g_pCompilerData->savedOp[g_pCompilerData->currentOp-1]; |
|||
if (result != 0) |
|||
{ |
|||
result = 0xFFFFFFFF; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case op_log_not: |
|||
result = !value1; |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
if (result != 0) |
|||
{ |
|||
fResult = 1.0f; |
|||
} |
|||
else |
|||
{ |
|||
fResult = 0.0f; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (result != 0) |
|||
{ |
|||
result = 0xFFFFFFFF; |
|||
} |
|||
} |
|||
break; |
|||
} |
|||
|
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
result = *(int*)(&fResult); |
|||
} |
|||
|
|||
g_pCompilerData->mathStack[g_pCompilerData->mathCurrent - 1] = result; |
|||
return true; |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,876 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// InstructionBlockCompiler.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" |
|||
|
|||
//////////////////////////////////////////
|
|||
// declarations for internal functions
|
|||
//
|
|||
|
|||
bool CompileBlock_IfOrIfNot(int column, int bIf); |
|||
bool CompileBlock_Case(int column); |
|||
bool CompileBlock_Repeat(int column); |
|||
|
|||
static int s_column = 0; |
|||
|
|||
//////////////////////////////////////////
|
|||
// exported functions
|
|||
//
|
|||
|
|||
bool CompileTopBlock() |
|||
{ |
|||
g_pCompilerData->bnest_ptr = 0; |
|||
g_pCompilerData->bstack_ptr = 0; |
|||
StringConstant_PreProcess(); |
|||
|
|||
if (!CompileBlock(0)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// enter a return into obj
|
|||
if (!EnterObj(0x32)) // 0x32 = 00110010b
|
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return StringConstant_PostProcess(); |
|||
} |
|||
|
|||
bool CompileBlock(int column) |
|||
{ |
|||
bool bEof = false; |
|||
|
|||
while (!bEof) |
|||
{ |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() == type_end) |
|||
{ |
|||
continue; |
|||
} |
|||
if (g_pElementizer->GetType() == type_block) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
s_column = g_pElementizer->GetColumn(); |
|||
if (s_column <= column) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
if (g_pElementizer->GetType() == type_if) |
|||
{ |
|||
if (!CompileBlock_IfOrIfNot(s_column, true)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
else if (g_pElementizer->GetType() == type_ifnot) |
|||
{ |
|||
if (!CompileBlock_IfOrIfNot(s_column, false)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
else if (g_pElementizer->GetType() == type_case) |
|||
{ |
|||
if (!CompileBlock_Case(s_column)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
else if (g_pElementizer->GetType() == type_repeat) |
|||
{ |
|||
if (!CompileBlock_Repeat(s_column)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (!CompileInstruction()) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
g_pElementizer->Backup(); |
|||
return true; |
|||
} |
|||
|
|||
//////////////////////////////////////////
|
|||
// internal function definitions
|
|||
//
|
|||
|
|||
bool CompileIfOrIfNot_FinalJmp(int& addressCount) |
|||
{ |
|||
if (!EnterObj(0x04)) // jmp
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!BlockStack_CompileAddress(0)) |
|||
{ |
|||
return false; |
|||
} |
|||
BlockStack_Write(addressCount, g_pCompilerData->obj_ptr); |
|||
addressCount++; |
|||
return true; |
|||
} |
|||
|
|||
bool CompileIfOrIfNot_Condition(int& addressCount, unsigned char byteCode) |
|||
{ |
|||
if (!CompileExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj(byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!BlockStack_CompileAddress(addressCount)) |
|||
{ |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool CompileIfOrIfNot_ElseCondition(int& addressCount, unsigned char byteCode) |
|||
{ |
|||
if (!CompileIfOrIfNot_FinalJmp(addressCount)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (addressCount < (if_limit + 2)) |
|||
{ |
|||
return CompileIfOrIfNot_Condition(addressCount, byteCode); |
|||
} |
|||
|
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_loxee]; |
|||
return false; |
|||
} |
|||
|
|||
bool CompileIfOrIfNot(int column, int param) |
|||
{ |
|||
int addressCount = 1; |
|||
|
|||
if (!CompileIfOrIfNot_Condition(addressCount, (unsigned char)(param))) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
bool bEof = false; |
|||
|
|||
while (!bEof) |
|||
{ |
|||
if (!CompileBlock(column)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (bEof) |
|||
{ |
|||
break; |
|||
} |
|||
s_column = g_pElementizer->GetColumn(); |
|||
if (s_column < column) |
|||
{ |
|||
g_pElementizer->Backup(); |
|||
break; |
|||
} |
|||
if (g_pElementizer->GetType() == type_elseif) |
|||
{ |
|||
if (!CompileIfOrIfNot_ElseCondition(addressCount, 0x0A)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
else if (g_pElementizer->GetType() == type_elseifnot) |
|||
{ |
|||
if (!CompileIfOrIfNot_ElseCondition(addressCount, 0x0B)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
else if (g_pElementizer->GetType() == type_else) |
|||
{ |
|||
if (!CompileIfOrIfNot_FinalJmp(addressCount)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!CompileBlock(column)) |
|||
{ |
|||
return false; |
|||
} |
|||
break; |
|||
} |
|||
else |
|||
{ |
|||
g_pElementizer->Backup(); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
BlockStack_Write(addressCount, g_pCompilerData->obj_ptr); // set last address
|
|||
BlockStack_Write(0, g_pCompilerData->obj_ptr); // set final address
|
|||
return true; |
|||
} |
|||
|
|||
bool CompileBlock_IfOrIfNot(int column, int bIf) |
|||
{ |
|||
if (!BlockNest_New(type_if, if_limit+3)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!OptimizeBlock(column, bIf ? 0x0A : 0x0B, &CompileIfOrIfNot)) |
|||
{ |
|||
return false; |
|||
} |
|||
BlockNest_End(); |
|||
return true; |
|||
} |
|||
|
|||
bool CompileCase(int column, int param) |
|||
{ |
|||
param = param; // stop warning
|
|||
|
|||
if (!BlockStack_CompileConstant()) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!CompileExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
int savedSourcePtr = g_pElementizer->GetSourcePtr(); |
|||
int otherSourcePtr = 0; |
|||
bool bOther = false; |
|||
int caseCount = 0; |
|||
|
|||
bool bEof = false; |
|||
while (!bEof) |
|||
{ |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (bEof) |
|||
{ |
|||
break; |
|||
} |
|||
if (g_pElementizer->GetType() == type_end) |
|||
{ |
|||
continue; |
|||
} |
|||
s_column = g_pElementizer->GetColumn(); |
|||
g_pElementizer->Backup(); |
|||
if (s_column <= column) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
if (bOther) // if we have OTHER: it should have been the last case, so we shouldn't get here again
|
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_omblc]; |
|||
return false; |
|||
} |
|||
|
|||
if (g_pElementizer->GetType() == type_other) |
|||
{ |
|||
bOther = true; |
|||
if (!g_pElementizer->GetNext(bEof)) // get/skip 'other'
|
|||
{ |
|||
return false; |
|||
} |
|||
otherSourcePtr = g_pCompilerData->source_start; // save the pointer to the beginning of 'other'
|
|||
} |
|||
else |
|||
{ |
|||
caseCount++; |
|||
if (caseCount > case_limit) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_loxce]; |
|||
return false; |
|||
} |
|||
for (;;) |
|||
{ |
|||
bool bRange = false; |
|||
if (!CompileRange(bRange)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj(bRange ? 0x0E : 0x0D)) // enter bytecode for case range or case value into obj
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!BlockStack_CompileAddress(caseCount)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->CheckElement(type_comma)) |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
if (!g_pElementizer->GetElement(type_colon)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!SkipBlock(s_column)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
if (caseCount == 0) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_nce]; |
|||
return false; |
|||
} |
|||
|
|||
if (bOther) |
|||
{ |
|||
// set the source pointer to where the OTHER is at, then get it to set the column
|
|||
g_pElementizer->SetSourcePtr(otherSourcePtr); |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
int new_column = g_pElementizer->GetColumn(); |
|||
// skip the colon
|
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!CompileBlock(new_column)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
if (!EnterObj(0x0C)) // casedone, end of range checks
|
|||
{ |
|||
return false; |
|||
} |
|||
g_pElementizer->SetSourcePtr(savedSourcePtr); |
|||
caseCount = 0; |
|||
bOther = false; |
|||
bEof = false; |
|||
|
|||
while(!bEof) |
|||
{ |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (bEof) |
|||
{ |
|||
break; |
|||
} |
|||
if (g_pElementizer->GetType() == type_end) |
|||
{ |
|||
continue; |
|||
} |
|||
s_column = g_pElementizer->GetColumn(); |
|||
g_pElementizer->Backup(); |
|||
if (s_column <= column) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
if (g_pElementizer->GetType() == type_other) |
|||
{ |
|||
// skip over other, already compiled
|
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!SkipBlock(s_column)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// skip over range/values(s), already compiled
|
|||
for (;;) |
|||
{ |
|||
if (!SkipRange()) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->CheckElement(type_comma)) |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
caseCount++; |
|||
BlockStack_Write(caseCount, g_pCompilerData->obj_ptr); |
|||
if (!g_pElementizer->GetElement(type_colon)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!CompileBlock(s_column)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj(0x0C)) // casedone
|
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
BlockStack_Write(0, g_pCompilerData->obj_ptr); |
|||
return true; |
|||
} |
|||
|
|||
bool CompileBlock_Case(int column) |
|||
{ |
|||
if (!BlockNest_New(type_case, case_limit+1)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!OptimizeBlock(column, 0, &CompileCase)) |
|||
{ |
|||
return false; |
|||
} |
|||
BlockNest_End(); |
|||
return true; |
|||
} |
|||
|
|||
static bool s_bHasPost = false; |
|||
bool CompileRepeatPlain(int column, int param) |
|||
{ |
|||
param = param; // stop warning
|
|||
|
|||
BlockStack_Write(2, g_pCompilerData->obj_ptr); // set reverse address
|
|||
if (!s_bHasPost) |
|||
{ |
|||
BlockStack_Write(0, g_pCompilerData->obj_ptr); // set plain 'next' address
|
|||
} |
|||
if (!CompileBlock(column)) |
|||
{ |
|||
return false; |
|||
} |
|||
bool bEof = false; |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
unsigned char byteCode = 0x04; |
|||
if (!bEof) |
|||
{ |
|||
s_column = g_pElementizer->GetColumn(); |
|||
if (s_column < column) |
|||
{ |
|||
g_pElementizer->Backup(); |
|||
} |
|||
else |
|||
{ |
|||
// check for post while or until
|
|||
int postType = g_pElementizer->GetType(); |
|||
if ((postType == type_while) || |
|||
(postType == type_until)) |
|||
{ |
|||
s_bHasPost = true; |
|||
BlockStack_Write(0, g_pCompilerData->obj_ptr); // set post-while/until 'next' address
|
|||
if (!CompileExpression()) // compile post-while/until expression
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
byteCode = (postType == type_while) ? 0x0B : 0x0A; |
|||
} |
|||
else |
|||
{ |
|||
g_pElementizer->Backup(); |
|||
} |
|||
} |
|||
} |
|||
if (!EnterObj(byteCode)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!BlockStack_CompileAddress(2)) // compile reverse address
|
|||
{ |
|||
return false; |
|||
} |
|||
BlockStack_Write(1, g_pCompilerData->obj_ptr); // set 'quit' address
|
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool CompileRepeatPreWhileOrUntil(int column, int param) |
|||
{ |
|||
BlockStack_Write(0, g_pCompilerData->obj_ptr); // set 'next'/reverse address
|
|||
if (!CompileExpression()) // compile pre-while/until expression
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj((unsigned char)(param & 0xFF))) // enter the passed in bytecode (jz or jnz)
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!BlockStack_CompileAddress(1)) // compile forward address
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!CompileBlock(column)) // compile repeat-while/until block
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj(0x04)) // (jmp)
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!BlockStack_CompileAddress(0)) // compile reverse address
|
|||
{ |
|||
return false; |
|||
} |
|||
BlockStack_Write(1, g_pCompilerData->obj_ptr); // set 'quit'/forward address
|
|||
return true; |
|||
} |
|||
|
|||
bool CompileRepeatCount(int column, int param) |
|||
{ |
|||
param = param; // stop warning
|
|||
|
|||
if (!CompileExpression()) // compile count expression
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!EnterObj(0x08)) // (tjz)
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!BlockStack_CompileAddress(1)) // compile forward address
|
|||
{ |
|||
return false; |
|||
} |
|||
BlockStack_Write(2, g_pCompilerData->obj_ptr); // set reverse address
|
|||
if (!CompileBlock(column)) // compile repeat-count block
|
|||
{ |
|||
return false; |
|||
} |
|||
BlockStack_Write(0, g_pCompilerData->obj_ptr); // set 'next' address
|
|||
if (!EnterObj(0x09)) // (djnz)
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!BlockStack_CompileAddress(2)) // compile reverse address
|
|||
{ |
|||
return false; |
|||
} |
|||
BlockStack_Write(1, g_pCompilerData->obj_ptr); // set 'quit'/forward address
|
|||
return true; |
|||
} |
|||
|
|||
bool CompileRepeatVariable(int column, int param) |
|||
{ |
|||
param = param; // stop warning
|
|||
|
|||
unsigned char varType = 0; |
|||
unsigned char varSize = 0; |
|||
int varAddress = 0; |
|||
int varIndexSourcePtr = 0; |
|||
if (!GetVariable(varType, varSize, varAddress, varIndexSourcePtr)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
bool bEof = false; |
|||
if (!g_pElementizer->GetNext(bEof)) // get 'from'
|
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() != type_from) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_efrom]; |
|||
return false; |
|||
} |
|||
int fromSourcePtr = g_pElementizer->GetSourcePtr(); |
|||
g_pCompilerData->str_enable = false; |
|||
if (!CompileExpression()) // compile 'from' expression (string not allowed)
|
|||
{ |
|||
return false; |
|||
} |
|||
g_pCompilerData->str_enable = true; |
|||
|
|||
if (!CompileVariable(1, 0, varType, varSize, varAddress, varIndexSourcePtr)) // compile var write
|
|||
{ |
|||
return false; |
|||
} |
|||
BlockStack_Write(2, g_pCompilerData->obj_ptr); // set reverse address
|
|||
|
|||
if (!g_pElementizer->GetNext(bEof)) // get 'to'
|
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() != type_to) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eto]; |
|||
return false; |
|||
} |
|||
g_pCompilerData->str_enable = false; |
|||
if (!SkipExpression()) // skip 'to' expression (string not allowed)
|
|||
{ |
|||
return false; |
|||
} |
|||
g_pCompilerData->str_enable = true; |
|||
|
|||
if (!g_pElementizer->GetNext(bEof)) // check for 'step'
|
|||
{ |
|||
return false; |
|||
} |
|||
unsigned char byteCode = 0; |
|||
if (g_pElementizer->GetType() == type_step) |
|||
{ |
|||
// handle step
|
|||
int savedSourcePtr = g_pElementizer->GetSourcePtr(); |
|||
g_pCompilerData->str_enable = false; |
|||
if (!SkipExpression()) // skip 'step' expression (string not allowed)
|
|||
{ |
|||
return false; |
|||
} |
|||
g_pCompilerData->str_enable = true; |
|||
if (!g_pElementizer->GetElement(type_end)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!CompileBlock(column)) |
|||
{ |
|||
return false; |
|||
} |
|||
BlockStack_Write(0, g_pCompilerData->obj_ptr); // set 'next' address
|
|||
if (!CompileOutOfSequenceExpression(savedSourcePtr)) // compile the step expression
|
|||
{ |
|||
return false; |
|||
} |
|||
byteCode = 0x06; // (repeat-var w/step)
|
|||
} |
|||
else if (g_pElementizer->GetType() == type_end) |
|||
{ |
|||
// no step, compile block
|
|||
if (!CompileBlock(column)) |
|||
{ |
|||
return false; |
|||
} |
|||
BlockStack_Write(0, g_pCompilerData->obj_ptr); // set 'next' address
|
|||
byteCode = 0x02; // (repeat-var)
|
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_esoeol]; |
|||
return false; |
|||
} |
|||
|
|||
int savedSourcePtr = g_pElementizer->GetSourcePtr(); |
|||
g_pElementizer->SetSourcePtr(fromSourcePtr); |
|||
if (!CompileExpression()) // compile 'from' expression
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetNext(bEof)) // skip 'to'
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!CompileExpression()) // compile 'to' expression
|
|||
{ |
|||
return false; |
|||
} |
|||
g_pElementizer->SetSourcePtr(savedSourcePtr); |
|||
if (!CompileVariable_Assign(byteCode, varType, varSize, varAddress, varIndexSourcePtr)) // compile repeat-var
|
|||
{ |
|||
return false; |
|||
} |
|||
if (!BlockStack_CompileAddress(2)) // compile reverse address
|
|||
{ |
|||
return false; |
|||
} |
|||
BlockStack_Write(1, g_pCompilerData->obj_ptr); // set 'quit'/forward address
|
|||
return true; |
|||
} |
|||
|
|||
bool CompileBlock_Repeat(int column) |
|||
{ |
|||
if (!BlockNest_New(type_repeat, 3)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// determine which type of repeat
|
|||
bool (*pCompileFunc)(int, int) = 0; |
|||
int param = 0; |
|||
bool bEof = false; |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pElementizer->GetType() == type_end) |
|||
{ |
|||
// repeat
|
|||
pCompileFunc = &CompileRepeatPlain; |
|||
s_bHasPost = false; // assume it doesn't have a post while or until (will be detected)
|
|||
} |
|||
else if (g_pElementizer->GetType() == type_while) |
|||
{ |
|||
// repeat while <exp>
|
|||
pCompileFunc = &CompileRepeatPreWhileOrUntil; |
|||
param = 0x0A; |
|||
} |
|||
else if (g_pElementizer->GetType() == type_until) |
|||
{ |
|||
// repeat until <exp>
|
|||
pCompileFunc = &CompileRepeatPreWhileOrUntil; |
|||
param = 0x0B; |
|||
} |
|||
else |
|||
{ |
|||
g_pElementizer->Backup(); |
|||
int savedSourcePtr = g_pElementizer->GetSourcePtr(); |
|||
if (!SkipExpression()) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pElementizer->SetSourcePtr(savedSourcePtr); |
|||
if (g_pElementizer->GetType() == type_end) |
|||
{ |
|||
// repeat <exp>
|
|||
pCompileFunc = &CompileRepeatCount; |
|||
// redo blocknest type
|
|||
BlockNest_Redo(type_repeat_count); |
|||
} |
|||
else |
|||
{ |
|||
// repeat var from <exp> to <exp> step <exp>
|
|||
pCompileFunc = &CompileRepeatVariable; |
|||
} |
|||
} |
|||
|
|||
if (!OptimizeBlock(column, param, pCompileFunc)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
BlockNest_End(); |
|||
return true; |
|||
} |
|||
|
|||
bool OptimizeBlock(int column, int param, bool (*pCompileFunction)(int, int)) |
|||
{ |
|||
int savedSourcePtr = g_pElementizer->GetSourcePtr(); |
|||
int savedObjPtr = g_pCompilerData->obj_ptr; |
|||
int size = 0; |
|||
|
|||
for (;;) |
|||
{ |
|||
g_pElementizer->SetSourcePtr(savedSourcePtr); |
|||
g_pCompilerData->obj_ptr = savedObjPtr; |
|||
|
|||
if (!(*pCompileFunction)(column, param)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// (re)compile until same size twice
|
|||
if (size != g_pCompilerData->obj_ptr) |
|||
{ |
|||
size = g_pCompilerData->obj_ptr; |
|||
} |
|||
else |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,73 @@ |
|||
# cross compilation scheme taken from Eric Smith's spin2cpp compiler
|
|||
# if CROSS is defined, we are building a cross compiler
|
|||
# possible targets are: win32, rpi
|
|||
|
|||
ifeq ($(CC),) |
|||
CC=gcc |
|||
endif |
|||
|
|||
ifeq ($(CXX),) |
|||
CXX=g++ |
|||
endif |
|||
|
|||
ifeq ($(CROSS),win32) |
|||
CC=i686-w64-mingw32-gcc |
|||
CXX=i686-w64-mingw32-g++ |
|||
EXT=.exe |
|||
BUILD=./build-win32 |
|||
else ifeq ($(CROSS),rpi) |
|||
CC=arm-linux-gnueabihf-gcc |
|||
CXX=arm-linux-gnueabihf-g++ |
|||
EXT= |
|||
BUILD=./build-rpi |
|||
else |
|||
EXT= |
|||
BUILD=./build |
|||
endif |
|||
|
|||
OS:=$(shell uname) |
|||
|
|||
ifeq ($(OS),Darwin) |
|||
CFLAGS+=-Wall -g -Wno-self-assign |
|||
else |
|||
CFLAGS+=-Wall -g $(MSTATIC) |
|||
endif |
|||
CXXFLAGS += $(CFLAGS) |
|||
|
|||
LIBNAME=$(BUILD)/libopenspin.a |
|||
SRCDIR=. |
|||
OBJ=$(BUILD)/BlockNestStackRoutines.o \
|
|||
$(BUILD)/CompileDatBlocks.o \
|
|||
$(BUILD)/CompileExpression.o \
|
|||
$(BUILD)/CompileInstruction.o \
|
|||
$(BUILD)/CompileUtilities.o \
|
|||
$(BUILD)/DistillObjects.o \
|
|||
$(BUILD)/Elementizer.o \
|
|||
$(BUILD)/ErrorStrings.o \
|
|||
$(BUILD)/ExpressionResolver.o \
|
|||
$(BUILD)/InstructionBlockCompiler.o \
|
|||
$(BUILD)/StringConstantRoutines.o \
|
|||
$(BUILD)/SymbolEngine.o \
|
|||
$(BUILD)/Utilities.o \
|
|||
$(BUILD)/UnusedMethodUtils.o \
|
|||
$(BUILD)/PropellerCompiler.o \
|
|||
$(BUILD)/CompileSpin.o \
|
|||
$(BUILD)/flexbuf.o \
|
|||
$(BUILD)/preprocess.o \
|
|||
$(BUILD)/textconvert.o \
|
|||
$(BUILD)/objectheap.o |
|||
|
|||
|
|||
all: $(BUILD) $(LIBNAME) Makefile |
|||
|
|||
$(LIBNAME): $(OBJ) |
|||
$(AR) rs $@ $^ |
|||
|
|||
$(BUILD)/%.o: $(SRCDIR)/%.cpp |
|||
$(CXX) $(CXXFLAGS) -o $@ -c $< |
|||
|
|||
$(BUILD): |
|||
mkdir -p $(BUILD) |
|||
|
|||
clean: |
|||
rm -rf $(BUILD) |
|||
File diff suppressed because it is too large
@ -0,0 +1,193 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// PropellerCompiler.h
|
|||
//
|
|||
|
|||
#ifndef _PROPELLER_COMPILER_H_ |
|||
#define _PROPELLER_COMPILER_H_ |
|||
|
|||
#include "UnusedMethodUtils.h" |
|||
|
|||
//
|
|||
// OpenSpin code uses _stricmp() which is the VC++ name for the function.
|
|||
// this needs to be remapped to stricmp or strcasecmp depending on the compiler and OS being compiled on
|
|||
// GCC prior to version 4.8 have strcasecmp on both linux and windows
|
|||
// GCC 4.8 and newer on linux appears to still have strcasecmp, but GCC 4.8 and newer on windows does not (it has stricmp instead)
|
|||
//
|
|||
#if defined(__linux__) |
|||
// we are on linux, then always use strcasecmp
|
|||
#define _stricmp strcasecmp |
|||
#else |
|||
#if __GNUC__ |
|||
// if GCC version is 4.8 or greater use stricmp, else use strcasecmp
|
|||
#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 8 )) |
|||
#define _stricmp stricmp |
|||
#else |
|||
#define _stricmp strcasecmp |
|||
#endif |
|||
#endif |
|||
#endif |
|||
|
|||
//
|
|||
// no longer compatible with Prop Tool / Propellent
|
|||
//
|
|||
|
|||
#define language_version '0' |
|||
#define loc_limit 0x8000 |
|||
#define var_limit 0x8000 |
|||
#define min_obj_limit 0x00020000 |
|||
#define file_limit 32 |
|||
#define data_limit 0x20000 |
|||
#define info_limit 1000 |
|||
#define distiller_limit 0x4000 |
|||
#define symbol_limit 256 // was 32
|
|||
#define pubcon_list_limit 0x8000 |
|||
#define block_nest_limit 8 |
|||
#define block_stack_limit 4096 |
|||
#define case_limit 256 |
|||
#define if_limit 16 |
|||
#define str_limit 256 |
|||
#define str_buffer_limit 0x8000 |
|||
|
|||
|
|||
enum infoType |
|||
{ |
|||
info_con = 0, // data0 = value (must be followed by info_con_float)
|
|||
info_con_float, // data0 = value
|
|||
info_dat, // data0/1 = obj start/finish
|
|||
info_dat_symbol, // data0 = value, data2 = offset, data1 = size
|
|||
info_pub, // data0/1 = obj start/finish, data2/3 = name start/finish
|
|||
info_pri, // data0/1 = obj start/finish, data2/3 = name start/finish
|
|||
info_pub_param, // data0 = pub index, data3 = param index, data2/3 = pub name start/finish
|
|||
info_pri_param // data0 = pri index, data3 = param index, data2/3 = pri name start/finish
|
|||
}; |
|||
|
|||
// Propeller Compiler Interface Structure
|
|||
struct CompilerData |
|||
{ |
|||
bool error; // Compilation status; error if true, success if false
|
|||
const char* error_msg; // Pointer to error string
|
|||
|
|||
int compile_mode; // Compile Mode; 0 = normal compile, 1 = Propeller Development compile
|
|||
|
|||
char* source; // Pointer to source data
|
|||
int source_start; // Offending item start (if error)
|
|||
int source_finish; // Offending item end (+1) (if error)
|
|||
|
|||
char* list; // Pointer to list data
|
|||
unsigned int list_limit; // Max size of list data
|
|||
unsigned int list_length; // Length of list data
|
|||
|
|||
char* doc; // Pointer to document data
|
|||
unsigned int doc_limit; // Max size of document data
|
|||
unsigned int doc_length; // Length of document data
|
|||
|
|||
unsigned char* obj; // Object binary for currently being compiled obj
|
|||
int obj_ptr; // Length of Object binary
|
|||
int obj_limit; // size of buffer allocated for obj
|
|||
|
|||
int obj_files; // Number of object files referenced by source
|
|||
char obj_filenames[file_limit*256]; // Object filenames
|
|||
int obj_name_start[file_limit]; // Starting char of each filename
|
|||
int obj_name_finish[file_limit]; // Ending character (+1) of each filename
|
|||
int obj_offsets[file_limit]; // Offsets of final objects in ObjData
|
|||
int obj_lengths[file_limit]; // Lengths of final objects in ObjData
|
|||
unsigned char obj_data[data_limit]; // Final top-level object binary
|
|||
int obj_instances[file_limit]; // Instances per filename
|
|||
char obj_title[256]; // Object Filename (without path)
|
|||
|
|||
int dat_files; // Number of DAT files referenced by source
|
|||
char dat_filenames[file_limit*256]; // DAT filenames
|
|||
int dat_name_start[file_limit]; // Starting char of each filename
|
|||
int dat_name_finish[file_limit]; // Ending character (+1) of each filename
|
|||
int dat_offsets[file_limit]; // Offsets of final objects in DatData
|
|||
int dat_lengths[file_limit]; // Lengths of final objects in DatData
|
|||
unsigned char dat_data[data_limit]; // Binary data
|
|||
|
|||
int pre_files; // Number of Precompile files referenced by source
|
|||
char pre_filenames[file_limit*256]; // Precompile filenames
|
|||
int pre_name_start[file_limit]; // Starting char of each filename
|
|||
int pre_name_finish[file_limit]; // Ending character (+1) of each filename
|
|||
|
|||
int arc_files; // Number of Archive files referenced by source
|
|||
char arc_filenames[file_limit*256]; // Archive filenames
|
|||
int arc_name_start[file_limit]; // Starting char of each filename
|
|||
int arc_name_finish[file_limit]; // Ending character (+1) of each filename
|
|||
|
|||
int info_count; // Number of information records for object
|
|||
int info_start[info_limit]; // Start of source related to this info
|
|||
int info_finish[info_limit]; // End (+1) of source related to this info
|
|||
int info_type[info_limit]; // 0 = CON, 1 CON(float), 2 = DAT, 3 = DAT Symbol, 4 = PUB, 5 = PRI, 6 = PUB_PARAM, 7 = PRI_PARAM
|
|||
int info_data0[info_limit]; // Info field 0: if CON = Value, if DAT/PUB/PRI = Start addr in object, if DAT Symbol = value, if PARAM = pub/pri index
|
|||
int info_data1[info_limit]; // Info field 1: if DAT/PUB/PRI = End+1 addr in object, if DAT Symbol = size, if PARAM = param index
|
|||
int info_data2[info_limit]; // Info field 2: if PUB/PRI/PARAM = Start of pub/pri name in source, if DAT Symbol = offset (in cog)
|
|||
int info_data3[info_limit]; // Info field 3: if PUB/PRI/PARAM = End+1 of pub/pri name in source
|
|||
int info_data4[info_limit]; // Info field 4: if PUB/PRI = index|param count
|
|||
|
|||
int distilled_longs; // Total longs optimized out of object
|
|||
unsigned char first_pub_parameters; |
|||
int stack_requirement; // Stack requirement for top-level object
|
|||
|
|||
unsigned char clkmode; |
|||
int clkfreq; |
|||
int debugbaud; // 0 = no debug, > 0 = debug at DebugBaud rate
|
|||
|
|||
bool bDATonly; // only compile DAT sections (into obj)
|
|||
|
|||
// only add new stuff below here
|
|||
|
|||
bool bBinary; // true for binary, false for eeprom
|
|||
|
|||
unsigned int eeprom_size; // size of eeprom
|
|||
unsigned int vsize; // used to hold last vsize (in case it is greater than 65536)
|
|||
unsigned int psize; // used to hold last psize (in case it is greater than 65536)
|
|||
|
|||
char current_filename[256]; // name of object being compiled at the moment
|
|||
bool bUnusedMethodElimination; // true if unused method elimination is on
|
|||
bool bFinalCompile; // set to true after unused method scan complete
|
|||
|
|||
int unused_obj_files; // number of unused object files
|
|||
char obj_unused[file_limit*256]; // hold filenames of unused objects
|
|||
|
|||
int unused_methods; // number of unused methods
|
|||
char method_unused[32*file_limit*symbol_limit]; // hold names of unused methods
|
|||
|
|||
char* current_file_path; // full path of the current file being compiled (points to entries in s_filesAccessed[])
|
|||
}; |
|||
|
|||
// public functions
|
|||
extern CompilerData* InitStruct(); |
|||
extern void Cleanup(); |
|||
extern const char* Compile1(); |
|||
extern const char* Compile2(); |
|||
extern bool GetErrorInfo(int& lineNumber, int& column, int& offsetToStartOfLine, int& offsetToEndOfLine, int& offendingItemStart, int& offendingItemEnd); |
|||
|
|||
#endif // _PROPELLER_COMPILER_H_
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,134 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// PropellerCompilerInternal.h
|
|||
//
|
|||
|
|||
#ifndef _PROPELLER_COMPILER_INTERNAL_H_ |
|||
#define _PROPELLER_COMPILER_INTERNAL_H_ |
|||
|
|||
#include "PropellerCompiler.h" |
|||
|
|||
struct CompilerDataInternal : public CompilerData |
|||
{ |
|||
// this stuff is misc globals from around the asm code
|
|||
|
|||
int var_byte; |
|||
int var_word; |
|||
int var_long; |
|||
int var_ptr; |
|||
|
|||
int obj_start; |
|||
int obj_count; |
|||
|
|||
int asm_local; |
|||
|
|||
unsigned char pubcon_list[pubcon_list_limit]; |
|||
int pubcon_list_size; |
|||
|
|||
char symbolBackup[symbol_limit+2]; // used when entering a symbol into the symbol table
|
|||
|
|||
bool doc_flag; |
|||
bool doc_mode; |
|||
|
|||
int cog_org; |
|||
|
|||
int print_length; |
|||
|
|||
// these are used by EnterInfo() to fill in info_* stuff above
|
|||
// various code fills these in and then calls EnterInfo()
|
|||
// I kept it this way because at the point the code calls EnterInfo() it doesn't
|
|||
// always have the values available to just pass as parameters.
|
|||
int inf_start; // Start of source related to this info
|
|||
int inf_finish; // End (+1) of source related to this info
|
|||
int inf_type; // 0 = CON, 1 CON(float), 2 = DAT, 3 = DAT Symbol, 4 = PUB, 5 = PRI, 6 = PUB_PARAM, 7 = PRI_PARAM
|
|||
int inf_data0; // Info field 0: if CON = Value, if DAT/PUB/PRI = Start addr in object, if DAT Symbol = value, if PARAM = pub/pri index
|
|||
int inf_data1; // Info field 1: if DAT/PUB/PRI = End+1 addr in object, if DAT Symbol = size, if PARAM = param index
|
|||
int inf_data2; // Info field 2: if PUB/PRI/PARAM = Start of pub/pri name in source, if DAT Symbol = offset (in cog)
|
|||
int inf_data3; // Info field 3: if PUB/PRI/PARAM = End+1 of pub/pri name in source
|
|||
int inf_data4; // Info field 4: if PUB/PRI = index|param count
|
|||
|
|||
// used by GetFileName/AddFileName
|
|||
char filename[255]; |
|||
|
|||
// these are used by the CompileConBlocks() code
|
|||
int enum_valid; |
|||
int enum_value; |
|||
int assign_flag; |
|||
int assign_type; |
|||
int assign_value; |
|||
|
|||
// used by CompileDatBlocks code
|
|||
int orgx; |
|||
|
|||
// used by ResolveExpression code
|
|||
int intMode; // 0 = uncommitted, 1 = int mode, 2 = float mode
|
|||
int precedence; // current precedence
|
|||
bool bMustResolve; // the expression must resolve
|
|||
bool bUndefined; // the expression is undefined
|
|||
bool bOperandMode; // when dealing with a PASM operand
|
|||
int mathCurrent; // index into mathStack[]
|
|||
int mathStack[16]; // holds the intermediate values during expression resolving
|
|||
int intermediateResult; // the current intermediate result
|
|||
int currentOp; // index into savedOp[]
|
|||
int savedOp[32]; // stack of operations to perform during expression resolving
|
|||
|
|||
// used by Object Distiller (DistillObjects.cpp)
|
|||
int dis_ptr; |
|||
unsigned short dis[distiller_limit]; |
|||
|
|||
// used for string constant processing (StringConstantRoutines.cpp)
|
|||
bool str_enable; |
|||
bool str_patch_enable; |
|||
int str_count; |
|||
int str_buffer_ptr; |
|||
unsigned char str_buffer[str_buffer_limit]; |
|||
int str_source[str_limit]; |
|||
int str_patch[str_limit]; |
|||
int str_offset[str_limit]; |
|||
int str_index; |
|||
|
|||
// used by InstructionBlockCompiler.cpp & BlockNestStackRoutines.cpp
|
|||
int bnest_ptr; |
|||
unsigned char bnest_type[block_nest_limit]; |
|||
int bstack_ptr; |
|||
int bstack_base[block_nest_limit]; |
|||
int bstack[block_stack_limit]; |
|||
}; |
|||
|
|||
class Elementizer; |
|||
class SymbolEngine; |
|||
|
|||
// shared globals
|
|||
extern Elementizer* g_pElementizer; |
|||
extern CompilerDataInternal* g_pCompilerData; |
|||
extern SymbolEngine* g_pSymbolEngine; |
|||
|
|||
#endif // _PROPELLER_COMPILER_INTERNAL_H_
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,136 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// StringConstantRoutines.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" |
|||
|
|||
void StringConstant_PreProcess() |
|||
{ |
|||
g_pCompilerData->str_enable = true; |
|||
g_pCompilerData->str_patch_enable = true; |
|||
g_pCompilerData->str_count = 0; |
|||
g_pCompilerData->str_buffer_ptr = 0; |
|||
} |
|||
|
|||
bool StringConstant_GetIndex() |
|||
{ |
|||
int strIndex = 0; |
|||
for (strIndex = 0; strIndex < g_pCompilerData->str_count; strIndex++) |
|||
{ |
|||
if (g_pCompilerData->str_source[strIndex] == g_pCompilerData->source_start) |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (strIndex == g_pCompilerData->str_count) |
|||
{ |
|||
// new string constant
|
|||
if (g_pCompilerData->str_count > str_limit) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_tmsc]; |
|||
return false; |
|||
} |
|||
g_pCompilerData->str_count++; |
|||
g_pCompilerData->str_source[strIndex] = g_pCompilerData->source_start; |
|||
g_pCompilerData->str_offset[strIndex] = g_pCompilerData->str_buffer_ptr; |
|||
} |
|||
else |
|||
{ |
|||
// old
|
|||
g_pCompilerData->str_buffer_ptr = g_pCompilerData->str_offset[strIndex]; |
|||
} |
|||
|
|||
g_pCompilerData->str_index = strIndex; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool StringConstant_EnterChar(unsigned char theChar) |
|||
{ |
|||
if (g_pCompilerData->str_buffer_ptr >= str_buffer_limit) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_tmscc]; |
|||
return false; |
|||
} |
|||
g_pCompilerData->str_buffer[g_pCompilerData->str_buffer_ptr++] = theChar; |
|||
return true; |
|||
} |
|||
|
|||
void StringConstant_EnterPatch() |
|||
{ |
|||
if (g_pCompilerData->str_patch_enable) |
|||
{ |
|||
g_pCompilerData->str_patch[g_pCompilerData->str_index] = g_pCompilerData->obj_ptr; |
|||
} |
|||
} |
|||
|
|||
bool StringConstant_PostProcess() |
|||
{ |
|||
if (g_pCompilerData->str_count > 0) |
|||
{ |
|||
// patch string addresses
|
|||
int strIndex = 0; |
|||
while(g_pCompilerData->str_count > 0) |
|||
{ |
|||
int temp = g_pCompilerData->obj_ptr; |
|||
temp += g_pCompilerData->str_offset[strIndex]; |
|||
temp |= 0x8000; |
|||
//short strAddress = ((temp & 0xFF00) >> 8) | ((temp & 0x00FF) << 8); // xchg ah,al
|
|||
//*((short*)&(g_pCompilerData->obj[g_pCompilerData->str_patch[strIndex]])) = strAddress;
|
|||
g_pCompilerData->obj[g_pCompilerData->str_patch[strIndex]] = (unsigned char)((temp >> 8) & 0xFF); |
|||
g_pCompilerData->obj[g_pCompilerData->str_patch[strIndex] + 1] = (unsigned char)(temp & 0xFF); |
|||
strIndex++; |
|||
g_pCompilerData->str_count--; |
|||
} |
|||
|
|||
// enter strings into obj
|
|||
for (int i = 0; i < g_pCompilerData->str_buffer_ptr; i++) |
|||
{ |
|||
if (!EnterObj(g_pCompilerData->str_buffer[i])) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,445 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// SymbolEngine.cpp
|
|||
//
|
|||
|
|||
#include "PropellerCompilerInternal.h" |
|||
#include "SymbolEngine.h" |
|||
#include "ErrorStrings.h" |
|||
#include "Utilities.h" |
|||
#include <string.h> |
|||
|
|||
static SymbolTableEntryDataTable symbols[] = |
|||
{ |
|||
{type_left, 0, "(", 0, false}, //miscellaneous
|
|||
{type_right, 0, ")", 0, false}, |
|||
{type_leftb, 0, "[", 0, false}, |
|||
{type_rightb, 0, "]", 0, false}, |
|||
{type_comma, 0, ",", 0, false}, |
|||
{type_equal, 0, "=", 0, false}, |
|||
{type_pound, 0, "#", 0, false}, |
|||
{type_colon, 0, ":", 0, false}, |
|||
{type_back, 0, "\\", 0, false}, |
|||
{type_dot, 0, ".", 0, false}, |
|||
{type_dotdot, 0, "..", 0, false}, |
|||
{type_at, 0, "@", 0, false}, |
|||
{type_atat, 0, "@@", 0, false}, |
|||
{type_til, 0, "~", 0, false}, |
|||
{type_tiltil, 0, "~~", 0, false}, |
|||
{type_rnd, 0, "?", 0, false}, |
|||
{type_inc, 0, "++", 0, false}, |
|||
{type_dec, 0, "--", 0, false}, |
|||
{type_assign, 0, ":=", 0, false}, |
|||
{type_spr, 0, "SPR", 0, false}, |
|||
|
|||
{type_binary, 1, "->", op_ror, false}, // math operators
|
|||
{type_binary, 1, "<-", op_rol, false}, |
|||
{type_binary, 1, ">>", op_shr, false}, |
|||
{type_binary, 1, "<<", op_shl, false}, |
|||
{type_binary, 6, "#>", op_min, false}, |
|||
{type_binary, 6, "<#", op_max, false}, |
|||
// {type_unary, 0, "-", op_neg, false}, // (uses op_sub symbol)
|
|||
{type_unary, 0, "!", op_not, false}, |
|||
{type_binary, 2, "&", op_and, false}, |
|||
{type_unary, 0, "||", op_abs, false}, |
|||
{type_binary, 3, "|", op_or, false}, |
|||
{type_binary, 3, "^", op_xor, false}, |
|||
{type_binary, 5, "+", op_add, false}, |
|||
{type_binary, 5, "-", op_sub, false}, |
|||
{type_binary, 1, "~>", op_sar, false}, |
|||
{type_binary, 1, "><", op_rev, false}, |
|||
{type_binary, 9, "AND", op_log_and, false}, |
|||
{type_unary, 0, ">|", op_ncd, false}, |
|||
{type_binary, 10, "OR", op_log_or, false}, |
|||
{type_unary, 0, "|<", op_dcd, false}, |
|||
{type_binary, 4, "*", op_mul, false}, |
|||
{type_binary, 4, "**", op_scl, false}, |
|||
{type_binary, 4, "/", op_div, false}, |
|||
{type_binary, 4, "//", op_rem, false}, |
|||
{type_unary, 0, "^^", op_sqr, false}, |
|||
{type_binary, 7, "<", op_cmp_b, false}, |
|||
{type_binary, 7, ">", op_cmp_a, false}, |
|||
{type_binary, 7, "<>", op_cmp_ne, false}, |
|||
{type_binary, 7, "==", op_cmp_e, false}, |
|||
{type_binary, 7, "=<", op_cmp_be, false}, |
|||
{type_binary, 7, "=>", op_cmp_ae, false}, |
|||
{type_unary, 8, "NOT", op_log_not, false}, |
|||
|
|||
{type_float, 0, "FLOAT", 0, false}, //floating-point operators
|
|||
{type_round, 0, "ROUND", 0, false}, |
|||
{type_trunc, 0, "TRUNC", 0, false}, |
|||
|
|||
{type_conexp, 0, "CONSTANT", 0, false}, //constant and string expressions
|
|||
{type_constr, 0, "STRING", 0, false}, |
|||
|
|||
{type_block, block_con, "CON", 0, false}, //block designators
|
|||
{type_block, block_var, "VAR", 0, false}, |
|||
{type_block, block_dat, "DAT", 0, false}, |
|||
{type_block, block_obj, "OBJ", 0, false}, |
|||
{type_block, block_pub, "PUB", 0, false}, |
|||
{type_block, block_pri, "PRI", 0, false}, |
|||
{type_block, block_dev, "DEV", 0, false}, |
|||
|
|||
{type_size, 0, "BYTE", 0, false}, //sizes
|
|||
{type_size, 1, "WORD", 0, false}, |
|||
{type_size, 2, "LONG", 0, false}, |
|||
|
|||
{type_precompile, 0, "PRECOMPILE", 0, false}, //file-related
|
|||
{type_archive, 0, "ARCHIVE", 0, false}, |
|||
{type_file, 0, "FILE", 0, false}, |
|||
|
|||
{type_if, 0, "IF", 0, false}, //high-level structures
|
|||
{type_ifnot, 0, "IFNOT", 0, false}, |
|||
{type_elseif, 0, "ELSEIF", 0, false}, |
|||
{type_elseifnot, 0, "ELSEIFNOT", 0, false}, |
|||
{type_else, 0, "ELSE", 0, false}, |
|||
{type_case, 0, "CASE", 0, false}, |
|||
{type_other, 0, "OTHER", 0, false}, |
|||
{type_repeat, 0, "REPEAT", 0, false}, |
|||
{type_while, 0, "WHILE", 0, false}, |
|||
{type_until, 0, "UNTIL", 0, false}, |
|||
{type_from, 0, "FROM", 0, false}, |
|||
{type_to, 0, "TO", 0, false}, |
|||
{type_step, 0, "STEP", 0, false}, |
|||
|
|||
{type_i_next_quit, 0, "NEXT", 0, false}, //high-level instructions
|
|||
{type_i_next_quit, 1, "QUIT", 0, false}, |
|||
{type_i_abort_return, 0x30, "ABORT", 0, false}, |
|||
{type_i_abort_return, 0x32, "RETURN", 0, false}, |
|||
{type_i_look, 0x10, "LOOKUP", 0, false}, |
|||
{type_i_look, 0x10 + 0x80, "LOOKUPZ", 0, false}, |
|||
{type_i_look, 0x11, "LOOKDOWN", 0, false}, |
|||
{type_i_look, 0x11 + 0x80, "LOOKDOWNZ", 0, false}, |
|||
{type_i_clkmode, 0, "CLKMODE", 0, false}, |
|||
{type_i_clkfreq, 0, "CLKFREQ", 0, false}, |
|||
{type_i_chipver, 0, "CHIPVER", 0, false}, |
|||
{type_i_reboot, 0, "REBOOT", 0, false}, |
|||
{type_i_cognew, 0x28 + (2 * 0x40), "COGNEW", 0, false}, |
|||
{type_i_ar, 0x16 + (1 * 0x40), "STRSIZE", 0, false}, |
|||
{type_i_ar, 0x17 + (2 * 0x40), "STRCOMP", 0, false}, |
|||
{type_i_nr, 0x18 + (3 * 0x40), "BYTEFILL", 0, false}, |
|||
{type_i_nr, 0x19 + (3 * 0x40), "WORDFILL", 0, false}, |
|||
{type_i_nr, 0x1A + (3 * 0x40), "LONGFILL", 0, false}, |
|||
{type_i_nr, 0x1C + (3 * 0x40), "BYTEMOVE", 0, false}, |
|||
{type_i_nr, 0x1D + (3 * 0x40), "WORDMOVE", 0, false}, |
|||
{type_i_nr, 0x1E + (3 * 0x40), "LONGMOVE", 0, false}, |
|||
|
|||
{type_i_nr, 0x1B + (3 * 0x40), "WAITPEQ", 0x3C, true}, // dual mode instructions (spin and asm)
|
|||
{type_i_nr, 0x1F + (3 * 0x40), "WAITPNE", 0x3D, true}, |
|||
{type_i_nr, 0x23 + (1 * 0x40), "WAITCNT", 0x3E + 0x40, true}, |
|||
{type_i_nr, 0x27 + (2 * 0x40), "WAITVID", 0x3F, true}, |
|||
{type_i_nr, 0x20 + (2 * 0x40), "CLKSET", 0 + 0x80, true}, |
|||
{type_i_cogid, 0, "COGID", 1 + 0x80 + 0x40, true}, |
|||
{type_i_coginit, 0x2C + (3 * 0x40), "COGINIT", 2 + 0x80, true}, |
|||
{type_i_nr, 0x21 + (1 * 0x40), "COGSTOP", 3 + 0x80, true}, |
|||
{type_i_cr, 0x29 + (0 * 0x40), "LOCKNEW", 4 + 0x80 + 0x40, true}, |
|||
{type_i_nr, 0x22 + (1 * 0x40), "LOCKRET", 5 + 0x80, true}, |
|||
{type_i_cr, 0x2A + (1 * 0x40), "LOCKSET", 6 + 0x80, true}, |
|||
{type_i_cr, 0x2B + (1 * 0x40), "LOCKCLR", 7 + 0x80, true}, |
|||
|
|||
{type_asm_dir, dir_orgx, "ORGX", 0, false}, //assembly directives
|
|||
{type_asm_dir, dir_org, "ORG", 0, false}, |
|||
{type_asm_dir, dir_res, "RES", 0, false}, |
|||
{type_asm_dir, dir_fit, "FIT", 0, false}, |
|||
{type_asm_dir, dir_nop, "NOP", 0, false}, |
|||
|
|||
{type_asm_cond, if_nc_and_nz, "IF_NC_AND_NZ", 0, false}, //assembly conditionals
|
|||
{type_asm_cond, if_nc_and_nz, "IF_NZ_AND_NC", 0, false}, |
|||
{type_asm_cond, if_nc_and_nz, "IF_A", 0, false}, |
|||
{type_asm_cond, if_nc_and_z, "IF_NC_AND_Z", 0, false}, |
|||
{type_asm_cond, if_nc_and_z, "IF_Z_AND_NC", 0, false}, |
|||
{type_asm_cond, if_nc, "IF_NC", 0, false}, |
|||
{type_asm_cond, if_nc, "IF_AE", 0, false}, |
|||
{type_asm_cond, if_c_and_nz, "IF_C_AND_NZ", 0, false}, |
|||
{type_asm_cond, if_c_and_nz, "IF_NZ_AND_C", 0, false}, |
|||
{type_asm_cond, if_nz, "IF_NZ", 0, false}, |
|||
{type_asm_cond, if_nz, "IF_NE", 0, false}, |
|||
{type_asm_cond, if_c_ne_z, "IF_C_NE_Z", 0, false}, |
|||
{type_asm_cond, if_c_ne_z, "IF_Z_NE_C", 0, false}, |
|||
{type_asm_cond, if_nc_or_nz, "IF_NC_OR_NZ", 0, false}, |
|||
{type_asm_cond, if_nc_or_nz, "IF_NZ_OR_NC", 0, false}, |
|||
{type_asm_cond, if_c_and_z, "IF_C_AND_Z", 0, false}, |
|||
{type_asm_cond, if_c_and_z, "IF_Z_AND_C", 0, false}, |
|||
{type_asm_cond, if_c_eq_z, "IF_C_EQ_Z", 0, false}, |
|||
{type_asm_cond, if_c_eq_z, "IF_Z_EQ_C", 0, false}, |
|||
{type_asm_cond, if_z, "IF_Z", 0, false}, |
|||
{type_asm_cond, if_z, "IF_E", 0, false}, |
|||
{type_asm_cond, if_nc_or_z, "IF_NC_OR_Z", 0, false}, |
|||
{type_asm_cond, if_nc_or_z, "IF_Z_OR_NC", 0, false}, |
|||
{type_asm_cond, if_c, "IF_C", 0, false}, |
|||
{type_asm_cond, if_c, "IF_B", 0, false}, |
|||
{type_asm_cond, if_c_or_nz, "IF_C_OR_NZ", 0, false}, |
|||
{type_asm_cond, if_c_or_nz, "IF_NZ_OR_C", 0, false}, |
|||
{type_asm_cond, if_c_or_z, "IF_C_OR_Z", 0, false}, |
|||
{type_asm_cond, if_c_or_z, "IF_Z_OR_C", 0, false}, |
|||
{type_asm_cond, if_c_or_z, "IF_BE", 0, false}, |
|||
{type_asm_cond, if_always, "IF_ALWAYS", 0, false}, |
|||
{type_asm_cond, if_never, "IF_NEVER", 0, false}, |
|||
|
|||
{type_asm_inst, 0, "WRBYTE", 0, false}, //assembly instructions
|
|||
{type_asm_inst, 0x00 + 0x40, "RDBYTE", 0, false}, |
|||
{type_asm_inst, 0x01, "WRWORD", 0, false}, |
|||
{type_asm_inst, 0x01 + 0x40, "RDWORD", 0, false}, |
|||
{type_asm_inst, 0x02, "WRLONG", 0, false}, |
|||
{type_asm_inst, 0x02 + 0x40, "RDLONG", 0, false}, |
|||
{type_asm_inst, 0x03, "HUBOP", 0, false}, |
|||
{type_asm_inst, 0x04 + 0x40, "MUL", 0, false}, |
|||
{type_asm_inst, 0x05 + 0x40, "MULS", 0, false}, |
|||
{type_asm_inst, 0x06 + 0x40, "ENC", 0, false}, |
|||
{type_asm_inst, 0x07 + 0x40, "ONES", 0, false}, |
|||
{type_asm_inst, 0x08 + 0x40, "ROR", 0, false}, |
|||
{type_asm_inst, 0x09 + 0x40, "ROL", 0, false}, |
|||
{type_asm_inst, 0x0A + 0x40, "SHR", 0, false}, |
|||
{type_asm_inst, 0x0B + 0x40, "SHL", 0, false}, |
|||
{type_asm_inst, 0x0C + 0x40, "RCR", 0, false}, |
|||
{type_asm_inst, 0x0D + 0x40, "RCL", 0, false}, |
|||
{type_asm_inst, 0x0E + 0x40, "SAR", 0, false}, |
|||
{type_asm_inst, 0x0F + 0x40, "REV", 0, false}, |
|||
{type_asm_inst, 0x10 + 0x40, "MINS", 0, false}, |
|||
{type_asm_inst, 0x11 + 0x40, "MAXS", 0, false}, |
|||
{type_asm_inst, 0x12 + 0x40, "MIN", 0, false}, |
|||
{type_asm_inst, 0x13 + 0x40, "MAX", 0, false}, |
|||
{type_asm_inst, 0x14 + 0x40, "MOVS", 0, false}, |
|||
{type_asm_inst, 0x15 + 0x40, "MOVD", 0, false}, |
|||
{type_asm_inst, 0x16 + 0x40, "MOVI", 0, false}, |
|||
{type_asm_inst, 0x17 + 0x40, "JMPRET", 0, false}, |
|||
// {type_asm_inst, 0x18 + 0x40, "AND", 0, false}, //({type_binary_bool)
|
|||
{type_asm_inst, 0x19 + 0x40, "ANDN", 0, false}, |
|||
// {type_asm_inst, 0x1A + 0x40, "OR", 0, false}, //({type_binary_bool)
|
|||
{type_asm_inst, 0x1B + 0x40, "XOR", 0, false}, |
|||
{type_asm_inst, 0x1C + 0x40, "MUXC", 0, false}, |
|||
{type_asm_inst, 0x1D + 0x40, "MUXNC", 0, false}, |
|||
{type_asm_inst, 0x1E + 0x40, "MUXZ", 0, false}, |
|||
{type_asm_inst, 0x1F + 0x40, "MUXNZ", 0, false}, |
|||
{type_asm_inst, 0x20 + 0x40, "ADD", 0, false}, |
|||
{type_asm_inst, 0x21 + 0x40, "SUB", 0, false}, |
|||
{type_asm_inst, 0x22 + 0x40, "ADDABS", 0, false}, |
|||
{type_asm_inst, 0x23 + 0x40, "SUBABS", 0, false}, |
|||
{type_asm_inst, 0x24 + 0x40, "SUMC", 0, false}, |
|||
{type_asm_inst, 0x25 + 0x40, "SUMNC", 0, false}, |
|||
{type_asm_inst, 0x26 + 0x40, "SUMZ", 0, false}, |
|||
{type_asm_inst, 0x27 + 0x40, "SUMNZ", 0, false}, |
|||
{type_asm_inst, 0x28 + 0x40, "MOV", 0, false}, |
|||
{type_asm_inst, 0x29 + 0x40, "NEG", 0, false}, |
|||
{type_asm_inst, 0x2A + 0x40, "ABS", 0, false}, |
|||
{type_asm_inst, 0x2B + 0x40, "ABSNEG", 0, false}, |
|||
{type_asm_inst, 0x2C + 0x40, "NEGC", 0, false}, |
|||
{type_asm_inst, 0x2D + 0x40, "NEGNC", 0, false}, |
|||
{type_asm_inst, 0x2E + 0x40, "NEGZ", 0, false}, |
|||
{type_asm_inst, 0x2F + 0x40, "NEGNZ", 0, false}, |
|||
{type_asm_inst, 0x30, "CMPS", 0, false}, |
|||
{type_asm_inst, 0x31, "CMPSX", 0, false}, |
|||
{type_asm_inst, 0x32 + 0x40, "ADDX", 0, false}, |
|||
{type_asm_inst, 0x33 + 0x40, "SUBX", 0, false}, |
|||
{type_asm_inst, 0x34 + 0x40, "ADDS", 0, false}, |
|||
{type_asm_inst, 0x35 + 0x40, "SUBS", 0, false}, |
|||
{type_asm_inst, 0x36 + 0x40, "ADDSX", 0, false}, |
|||
{type_asm_inst, 0x37 + 0x40, "SUBSX", 0, false}, |
|||
{type_asm_inst, 0x38 + 0x40, "CMPSUB", 0, false}, |
|||
{type_asm_inst, 0x39 + 0x40, "DJNZ", 0, false}, |
|||
{type_asm_inst, 0x3A, "TJNZ", 0, false}, |
|||
{type_asm_inst, 0x3B, "TJZ", 0, false}, |
|||
{type_asm_inst, 0x15, "CALL", 0, false}, //converts to 17h (jmpret symbol_ret,#symbol)
|
|||
{type_asm_inst, 0x16, "RET", 0, false}, //converts to 17h (jmp #0)
|
|||
{type_asm_inst, 0x17, "JMP", 0, false}, |
|||
{type_asm_inst, 0x18, "TEST", 0, false}, |
|||
{type_asm_inst, 0x19, "TESTN", 0, false}, |
|||
{type_asm_inst, 0x21, "CMP", 0, false}, |
|||
{type_asm_inst, 0x33, "CMPX", 0, false}, |
|||
|
|||
{type_asm_effect, 0x04, "WZ", 0, false}, //assembly effects
|
|||
{type_asm_effect, 0x02, "WC", 0, false}, |
|||
{type_asm_effect, 0x01, "WR", 0, false}, |
|||
{type_asm_effect, 0x08, "NR", 0, false}, |
|||
|
|||
{type_reg, 0x10, "PAR", 0, false}, //registers
|
|||
{type_reg, 0x11, "CNT", 0, false}, |
|||
{type_reg, 0x12, "INA", 0, false}, |
|||
{type_reg, 0x13, "INB", 0, false}, |
|||
{type_reg, 0x14, "OUTA", 0, false}, |
|||
{type_reg, 0x15, "OUTB", 0, false}, |
|||
{type_reg, 0x16, "DIRA", 0, false}, |
|||
{type_reg, 0x17, "DIRB", 0, false}, |
|||
{type_reg, 0x18, "CTRA", 0, false}, |
|||
{type_reg, 0x19, "CTRB", 0, false}, |
|||
{type_reg, 0x1A, "FRQA", 0, false}, |
|||
{type_reg, 0x1B, "FRQB", 0, false}, |
|||
{type_reg, 0x1C, "PHSA", 0, false}, |
|||
{type_reg, 0x1D, "PHSB", 0, false}, |
|||
{type_reg, 0x1E, "VCFG", 0, false}, |
|||
{type_reg, 0x1F, "VSCL", 0, false}, |
|||
|
|||
{type_loc_long, 0, "RESULT", 0, false}, //variables
|
|||
|
|||
{type_con, 0, "FALSE", 0, false}, //constants
|
|||
{type_con, -1, "TRUE", 0, false}, |
|||
{type_con, ~0x7FFFFFFF, "NEGX", 0, false}, |
|||
{type_con, 0x7FFFFFFF, "POSX", 0, false}, |
|||
{type_con_float, 0x40490FDB, "PI", 0, false}, |
|||
|
|||
{type_con, 0x00000001, "RCFAST", 0, false}, |
|||
{type_con, 0x00000002, "RCSLOW", 0, false}, |
|||
{type_con, 0x00000004, "XINPUT", 0, false}, |
|||
{type_con, 0x00000008, "XTAL1", 0, false}, |
|||
{type_con, 0x00000010, "XTAL2", 0, false}, |
|||
{type_con, 0x00000020, "XTAL3", 0, false}, |
|||
{type_con, 0x00000040, "PLL1X", 0, false}, |
|||
{type_con, 0x00000080, "PLL2X", 0, false}, |
|||
{type_con, 0x00000100, "PLL4X", 0, false}, |
|||
{type_con, 0x00000200, "PLL8X", 0, false}, |
|||
{type_con, 0x00000400, "PLL16X", 0, false}, |
|||
|
|||
{type_undefined, 0, "*END*", 0, false} // end of table marker
|
|||
}; |
|||
|
|||
SymbolTableEntry::SymbolTableEntry(const SymbolTableEntryDataTable& data) |
|||
{ |
|||
m_data.type = data.type; |
|||
m_data.value = data.value; |
|||
m_data.value_2 = 0; |
|||
size_t nameLength = strlen(data.name)+1; |
|||
m_data.name = new char[nameLength]; |
|||
strcpy(m_data.name, data.name); |
|||
m_data.operator_type_or_asm = data.operator_type_or_asm; |
|||
m_data.dual = data.dual; |
|||
} |
|||
|
|||
SymbolEngine::SymbolEngine() |
|||
{ |
|||
m_pSymbols = new HashTable(256); |
|||
m_pUserSymbols = new HashTable(8192); |
|||
m_pTempUserSymbols = new HashTable(1024); |
|||
|
|||
// add symbols to hash table
|
|||
int index = 0; |
|||
while (strcmp(symbols[index].name, "*END*") != 0) |
|||
{ |
|||
int hashKey = m_pSymbols->GetStringHashUppercase(symbols[index].name); |
|||
m_pSymbols->Insert(hashKey, new SymbolTableEntry(symbols[index])); |
|||
index++; |
|||
} |
|||
} |
|||
|
|||
SymbolEngine::~SymbolEngine() |
|||
{ |
|||
delete m_pSymbols; |
|||
m_pSymbols = 0; |
|||
delete m_pUserSymbols; |
|||
m_pUserSymbols = 0; |
|||
delete m_pTempUserSymbols; |
|||
m_pTempUserSymbols = 0; |
|||
} |
|||
|
|||
// looks for the given symbol in the symbol table and returns a pointer to the entry
|
|||
// if the symbol is not found, then it returns 0
|
|||
SymbolTableEntry* SymbolEngine::FindSymbol(const char* pSymbolName) |
|||
{ |
|||
int hashKey = m_pSymbols->GetStringHashUppercase(pSymbolName); |
|||
|
|||
// look in automatic symbols
|
|||
HashNode* pNode = m_pSymbols->FindFirst(hashKey); |
|||
while (pNode != 0) |
|||
{ |
|||
SymbolTableEntry* pSymbol = (SymbolTableEntry*)(pNode->pValue); |
|||
if (_stricmp(pSymbol->m_data.name, pSymbolName) == 0) |
|||
{ |
|||
return pSymbol; |
|||
} |
|||
|
|||
pNode = m_pSymbols->FindNext(pNode); |
|||
} |
|||
|
|||
// didn't find it above, so look in user symbols
|
|||
pNode = m_pUserSymbols->FindFirst(hashKey); |
|||
while (pNode != 0) |
|||
{ |
|||
SymbolTableEntry* pSymbol = (SymbolTableEntry*)(pNode->pValue); |
|||
if (_stricmp(pSymbol->m_data.name, pSymbolName) == 0) |
|||
{ |
|||
return pSymbol; |
|||
} |
|||
|
|||
pNode = m_pUserSymbols->FindNext(pNode); |
|||
} |
|||
|
|||
// didn't find it above, so look in temp user symbols
|
|||
pNode = m_pTempUserSymbols->FindFirst(hashKey); |
|||
while (pNode != 0) |
|||
{ |
|||
SymbolTableEntry* pSymbol = (SymbolTableEntry*)(pNode->pValue); |
|||
if (_stricmp(pSymbol->m_data.name, pSymbolName) == 0) |
|||
{ |
|||
return pSymbol; |
|||
} |
|||
|
|||
pNode = m_pTempUserSymbols->FindNext(pNode); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
void SymbolEngine::AddSymbol(const char* pSymbolName, symbol_Type type, int value, int value_2, bool bTemp) |
|||
{ |
|||
PrintSymbol(pSymbolName, (unsigned char)type, value, value_2); |
|||
|
|||
SymbolTableEntry* pSymbol = new SymbolTableEntry; |
|||
size_t nameLength = strlen(pSymbolName)+1; |
|||
pSymbol->m_data.name = new char[nameLength]; |
|||
strcpy(pSymbol->m_data.name, pSymbolName); |
|||
pSymbol->m_data.type = type; |
|||
pSymbol->m_data.value = value; |
|||
pSymbol->m_data.value_2 = value_2; |
|||
pSymbol->m_data.dual = false; |
|||
pSymbol->m_data.operator_type_or_asm = 0; |
|||
|
|||
if (bTemp) |
|||
{ |
|||
int hashKey = m_pTempUserSymbols->GetStringHashUppercase(pSymbol->m_data.name); |
|||
m_pTempUserSymbols->Insert(hashKey, pSymbol); |
|||
} |
|||
else |
|||
{ |
|||
int hashKey = m_pUserSymbols->GetStringHashUppercase(pSymbol->m_data.name); |
|||
m_pUserSymbols->Insert(hashKey, pSymbol); |
|||
} |
|||
} |
|||
|
|||
void SymbolEngine::Reset(bool bTempsOnly) |
|||
{ |
|||
if (!bTempsOnly) |
|||
{ |
|||
delete m_pUserSymbols; |
|||
m_pUserSymbols = new HashTable(8192); |
|||
} |
|||
|
|||
delete m_pTempUserSymbols; |
|||
m_pTempUserSymbols = new HashTable(1024); |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,254 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// SymbolEngine.h
|
|||
//
|
|||
|
|||
#ifndef _SYMBOL_ENGINE_H_ |
|||
#define _SYMBOL_ENGINE_H_ |
|||
|
|||
#include "Utilities.h" |
|||
|
|||
enum symbol_Type |
|||
{ |
|||
type_undefined = 0, // (undefined symbol, must be 0)
|
|||
type_left, // (
|
|||
type_right, // )
|
|||
type_leftb, // [
|
|||
type_rightb, // ]
|
|||
type_comma, // ,
|
|||
type_equal, // =
|
|||
type_pound, // #
|
|||
type_colon, // :
|
|||
type_back, /* \ */ |
|||
type_dot, // .
|
|||
type_dotdot, // ..
|
|||
type_at, // @
|
|||
type_atat, // @@
|
|||
type_til, // ~
|
|||
type_tiltil, // ~~
|
|||
type_rnd, // ?
|
|||
type_inc, // ++
|
|||
type_dec, // --
|
|||
type_assign, // :=
|
|||
type_spr, // SPR
|
|||
type_unary, // -, !, ||, etc.
|
|||
type_binary, // +, -, *, /, etc.
|
|||
type_float, // FLOAT
|
|||
type_round, // ROUND
|
|||
type_trunc, // TRUNC
|
|||
type_conexp, // CONSTANT
|
|||
type_constr, // STRING
|
|||
type_block, // CON, VAR, DAT, OBJ, PUB, PRI
|
|||
type_size, // BYTE, WORD, LONG
|
|||
type_precompile, // PRECOMPILE
|
|||
type_archive, // ARCHIVE
|
|||
type_file, // FILE
|
|||
type_if, // IF
|
|||
type_ifnot, // IFNOT
|
|||
type_elseif, // ELSEIF
|
|||
type_elseifnot, // ELSEIFNOT
|
|||
type_else, // ELSE
|
|||
type_case, // CASE
|
|||
type_other, // OTHER
|
|||
type_repeat, // REPEAT
|
|||
type_repeat_count, // REPEAT count - different QUIT method
|
|||
type_while, // WHILE
|
|||
type_until, // UNTIL
|
|||
type_from, // FROM
|
|||
type_to, // TO
|
|||
type_step, // STEP
|
|||
type_i_next_quit, // NEXT/QUIT
|
|||
type_i_abort_return, // ABORT/RETURN
|
|||
type_i_look, // LOOKUP/LOOKDOWN
|
|||
type_i_clkmode, // CLKMODE
|
|||
type_i_clkfreq, // CLKFREQ
|
|||
type_i_chipver, // CHIPVER
|
|||
type_i_reboot, // REBOOT
|
|||
type_i_cogid, // COGID
|
|||
type_i_cognew, // COGNEW
|
|||
type_i_coginit, // COGINIT
|
|||
type_i_ar, // STRSIZE, STRCOMP - always returns value
|
|||
type_i_cr, // LOCKNEW, LOCKCLR, LOCKSET - can return value
|
|||
type_i_nr, // BYTEFILL, WORDFILL, LONGFILL, etc. - never returns value
|
|||
type_dual, // WAITPEQ, WAITPNE, etc. - type_asm_inst or type_i_???
|
|||
type_asm_org, // $ (without a hex digit following)
|
|||
type_asm_dir, // ORGX, ORG, RES, FIT, NOP
|
|||
type_asm_cond, // IF_C, IF_Z, IF_NC, etc
|
|||
type_asm_inst, // RDBYTE, RDWORD, RDLONG, etc.
|
|||
type_asm_effect, // WZ, WC, WR, NR
|
|||
type_reg, // PAR, CNT, INA, etc.
|
|||
type_con, // user constant integer (must be followed by type_con_float)
|
|||
type_con_float, // user constant float
|
|||
type_var_byte, // V0user byte var
|
|||
type_var_word, // V1user word var
|
|||
type_var_long, // V2user long var
|
|||
type_dat_byte, // D0user byte dat
|
|||
type_dat_word, // D1user word dat
|
|||
type_dat_long, // D2user long dat
|
|||
type_dat_long_res, // (D2)user res dat (must follow type_dat_long)
|
|||
type_loc_byte, // L0user byte local
|
|||
type_loc_word, // L1user word local
|
|||
type_loc_long, // L2user long local
|
|||
type_obj, // user object
|
|||
type_objpub, // user object.subroutine
|
|||
type_objcon, // user object.constant (must be followed by type_objcon_float)
|
|||
type_objcon_float, // user object.constant float
|
|||
type_sub, // user subroutine
|
|||
type_end // end-of-line c=0, end-of-file c=1
|
|||
}; |
|||
|
|||
enum block_Type |
|||
{ |
|||
block_con = 0, |
|||
block_var, |
|||
block_dat, |
|||
block_obj, |
|||
block_pub, |
|||
block_pri, |
|||
block_dev, |
|||
}; |
|||
|
|||
enum operator_Type |
|||
{ |
|||
op_ror = 0, // operator precedences (0=priority)
|
|||
op_rol, //
|
|||
op_shr, // 0= -, !, ||, >|, |<, ^^ (unary)
|
|||
op_shl, // 1= ->, <-, >>, << ~>, ><
|
|||
op_min, // 2= &
|
|||
op_max, // 3= |, ^
|
|||
op_neg, // 4= *, **, /, //
|
|||
op_not, // 5= +, -
|
|||
op_and, // 6= #>, <#
|
|||
op_abs, // 7= <, >, <>, ==, =<, =>
|
|||
op_or, // 8= NOT (unary)
|
|||
op_xor, // 9= AND
|
|||
op_add, // 10= OR
|
|||
op_sub, |
|||
op_sar, |
|||
op_rev, |
|||
op_log_and, |
|||
op_ncd, |
|||
op_log_or, |
|||
op_dcd, |
|||
op_mul, |
|||
op_scl, |
|||
op_div, |
|||
op_rem, |
|||
op_sqr, |
|||
op_cmp_b, |
|||
op_cmp_a, |
|||
op_cmp_ne, |
|||
op_cmp_e, |
|||
op_cmp_be, |
|||
op_cmp_ae, |
|||
op_log_not |
|||
}; |
|||
|
|||
enum directives_Type |
|||
{ |
|||
dir_orgx = 0, |
|||
dir_org, |
|||
dir_res, |
|||
dir_fit, |
|||
dir_nop |
|||
}; |
|||
|
|||
enum if_Type |
|||
{ |
|||
if_never = 0, |
|||
if_nc_and_nz, |
|||
if_nc_and_z, |
|||
if_nc, |
|||
if_c_and_nz, |
|||
if_nz, |
|||
if_c_ne_z, |
|||
if_nc_or_nz, |
|||
if_c_and_z, |
|||
if_c_eq_z, |
|||
if_z, |
|||
if_nc_or_z, |
|||
if_c, |
|||
if_c_or_nz, |
|||
if_c_or_z, |
|||
if_always, |
|||
}; |
|||
|
|||
struct SymbolTableEntryDataTable |
|||
{ |
|||
symbol_Type type; // what type of symbol is it?
|
|||
int value; // value is type dependant
|
|||
const char* name; // the string of the symbol
|
|||
unsigned char operator_type_or_asm; // operator type for op symbols, or asm value for dual symbols
|
|||
bool dual; // indicates that this symbol is used by both PASM and spin
|
|||
}; |
|||
|
|||
struct SymbolTableEntryData |
|||
{ |
|||
symbol_Type type; // what type of symbol is it?
|
|||
int value; // value is type dependant
|
|||
int value_2; // value 2 is type dependant
|
|||
char* name; // the string of the symbol
|
|||
unsigned char operator_type_or_asm; // operator type for op symbols, or asm value for dual symbols
|
|||
bool dual; // indicates that this symbol is used by both PASM and spin
|
|||
}; |
|||
|
|||
class SymbolTableEntry : public Hashable |
|||
{ |
|||
public: |
|||
SymbolTableEntry() |
|||
{ |
|||
m_data.name = 0; |
|||
} |
|||
SymbolTableEntry(const SymbolTableEntryDataTable& data); |
|||
~SymbolTableEntry() |
|||
{ |
|||
delete [] m_data.name; |
|||
} |
|||
SymbolTableEntryData m_data; |
|||
}; |
|||
|
|||
class SymbolEngine |
|||
{ |
|||
HashTable* m_pSymbols; // predefined symbols
|
|||
HashTable* m_pUserSymbols; // any symbols defined during compiling
|
|||
HashTable* m_pTempUserSymbols; // used for locals during CompileSubBlocks
|
|||
|
|||
public: |
|||
SymbolEngine(); |
|||
~SymbolEngine(); |
|||
|
|||
SymbolTableEntry* FindSymbol(const char* pSymbolName); |
|||
|
|||
void AddSymbol(const char* pSymbolName, symbol_Type type, int value, int value_2 = 0, bool bTemp = false); |
|||
void Reset(bool bTempsOnly = false); |
|||
}; |
|||
|
|||
#endif // _SYMBOL_ENGINE_H_
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,992 @@ |
|||
|
|||
///////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
|
|||
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|||
// See end of file for terms of use. //
|
|||
// //
|
|||
///////////////////////////////////////////////////////////////
|
|||
//
|
|||
// UnusedMethodUtils.cpp
|
|||
//
|
|||
|
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
#include "PropellerCompiler.h" |
|||
|
|||
//
|
|||
// track object names based on "indent" or which child/parent level
|
|||
// note: the same name can be in here multiple times at different indent levels
|
|||
//
|
|||
|
|||
struct ObjectNameEntry |
|||
{ |
|||
char filename[256]; |
|||
int nCompileIndex; |
|||
}; |
|||
|
|||
ObjectNameEntry s_objectNames[file_limit * file_limit]; |
|||
int s_nNumObjectNames = 0; |
|||
|
|||
void AddObjectName(char* pFilename, int nCompileIndex) |
|||
{ |
|||
strcpy(s_objectNames[s_nNumObjectNames].filename, pFilename); |
|||
|
|||
// chop off the .spin extension
|
|||
char* pExtension = strstr(s_objectNames[s_nNumObjectNames].filename, ".spin"); |
|||
if (pExtension != 0) |
|||
{ |
|||
*pExtension = 0; |
|||
} |
|||
|
|||
s_objectNames[s_nNumObjectNames].nCompileIndex = nCompileIndex; |
|||
s_nNumObjectNames++; |
|||
} |
|||
|
|||
int GetObjectName(int nCompileIndex) |
|||
{ |
|||
for (int i = 0; i < s_nNumObjectNames; i++) |
|||
{ |
|||
if (s_objectNames[i].nCompileIndex == nCompileIndex) |
|||
{ |
|||
return i; |
|||
} |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
//
|
|||
// track method usage by object
|
|||
//
|
|||
|
|||
struct IndexEntry |
|||
{ |
|||
short offset; // offset in longs to method (or sub object)
|
|||
short vars; // var offset for objs, locals size for methods
|
|||
}; |
|||
|
|||
struct CallEntry |
|||
{ |
|||
unsigned char* objaddress; |
|||
unsigned int callOffset; |
|||
unsigned short objoffset; |
|||
unsigned char opcode; |
|||
unsigned char pubnum; |
|||
unsigned char objnum; |
|||
}; |
|||
|
|||
struct MethodUsage |
|||
{ |
|||
int nLength; |
|||
int nCalled; |
|||
int nCalls; |
|||
CallEntry *pCalls; |
|||
int nCurrCall; |
|||
int nNewIndex; |
|||
}; |
|||
|
|||
struct ObjectEntry |
|||
{ |
|||
int nObjectNameIndex; |
|||
unsigned char* pObject; |
|||
int nObjectMethodCount; |
|||
int nObjectSubObjectCount; |
|||
int nObjectIndexCount; |
|||
int nMethodsCalled; |
|||
int nNewObjectIndex; |
|||
IndexEntry* pIndexTable; |
|||
MethodUsage* pMethods; |
|||
}; |
|||
|
|||
ObjectEntry s_objects[file_limit * file_limit]; |
|||
int s_nNumObjects; |
|||
|
|||
bool HaveObject(unsigned char* pObject) |
|||
{ |
|||
for (int i = 0; i < s_nNumObjects; i++) |
|||
{ |
|||
if (s_objects[i].pObject == pObject) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
ObjectEntry* GetObject(unsigned char* pObject) |
|||
{ |
|||
for (int i = 0; i < s_nNumObjects; i++) |
|||
{ |
|||
if (s_objects[i].pObject == pObject) |
|||
{ |
|||
return &s_objects[i]; |
|||
} |
|||
} |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
ObjectEntry* GetObjectByName(char* pFilename) |
|||
{ |
|||
for (int i = 0; i < s_nNumObjects; i++) |
|||
{ |
|||
if (strcmp(s_objectNames[s_objects[i].nObjectNameIndex].filename, pFilename) == 0) |
|||
{ |
|||
return &s_objects[i]; |
|||
} |
|||
} |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
int AddObject(unsigned char* pObject, int nObjectNameIndex) |
|||
{ |
|||
s_objects[s_nNumObjects].pObject = pObject; |
|||
s_objects[s_nNumObjects].nObjectNameIndex = nObjectNameIndex; |
|||
s_objects[s_nNumObjects].nObjectMethodCount = pObject[2]-1; |
|||
s_objects[s_nNumObjects].nObjectSubObjectCount = pObject[3]; |
|||
s_objects[s_nNumObjects].nObjectIndexCount = s_objects[s_nNumObjects].nObjectMethodCount + s_objects[s_nNumObjects].nObjectSubObjectCount; |
|||
s_objects[s_nNumObjects].pIndexTable = (IndexEntry *)&(pObject[4]); |
|||
s_objects[s_nNumObjects].pMethods = new MethodUsage[s_objects[s_nNumObjects].nObjectMethodCount]; |
|||
for (int i = 0; i < s_objects[s_nNumObjects].nObjectMethodCount; i++) |
|||
{ |
|||
s_objects[s_nNumObjects].pMethods[i].nCalled = 0; |
|||
s_objects[s_nNumObjects].pMethods[i].nCalls = 0; |
|||
s_objects[s_nNumObjects].pMethods[i].pCalls = 0; |
|||
s_objects[s_nNumObjects].pMethods[i].nCurrCall = 0; |
|||
s_objects[s_nNumObjects].pMethods[i].nNewIndex = 0; |
|||
s_objects[s_nNumObjects].pMethods[i].nLength = 0; |
|||
} |
|||
return s_nNumObjects++; |
|||
} |
|||
|
|||
bool IsObjectUsed(char* pFilename) |
|||
{ |
|||
// chop off the .spin extension, saving the . char for restoring
|
|||
char* pExtension = strstr(pFilename, ".spin"); |
|||
char savedChar = 0; |
|||
if (pExtension != 0) |
|||
{ |
|||
savedChar = *pExtension; |
|||
*pExtension = 0; |
|||
} |
|||
|
|||
ObjectEntry* pObject = GetObjectByName(pFilename); |
|||
|
|||
// restore extention to passed in filename
|
|||
if (pExtension != 0) |
|||
{ |
|||
*pExtension = savedChar; |
|||
} |
|||
|
|||
if (pObject && pObject->nMethodsCalled > 0) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
bool IsMethodUsed(char* pFilename, int nMethod) |
|||
{ |
|||
ObjectEntry* pObject = GetObjectByName(pFilename); |
|||
if (pObject && pObject->nMethodsCalled > 0 && pObject->pMethods[nMethod].nCalled > 0) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
//
|
|||
// store pubcon list data so it can be used in the final compile
|
|||
// note: this is needed to allow removing a child object where the parent used only CONs from the child
|
|||
//
|
|||
|
|||
struct ObjectPubConListEntry |
|||
{ |
|||
char filename[256]; |
|||
unsigned char* pPubConList; |
|||
int nPubConListSize; |
|||
}; |
|||
|
|||
ObjectPubConListEntry s_objectPubConLists[file_limit * file_limit]; |
|||
int s_nNumObjectPubConLists; |
|||
|
|||
ObjectPubConListEntry* GetObjectPubConListEntryByName(char* pFilename) |
|||
{ |
|||
for (int i = 0; i < s_nNumObjectPubConLists; i++) |
|||
{ |
|||
if (strcmp(s_objectPubConLists[i].filename, pFilename) == 0) |
|||
{ |
|||
return &s_objectPubConLists[i]; |
|||
} |
|||
} |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
void AddObjectPubConList(char* pFilename, unsigned char* pPubConList, int nPubConListSize) |
|||
{ |
|||
strcpy(s_objectPubConLists[s_nNumObjectPubConLists].filename, pFilename); |
|||
s_objectPubConLists[s_nNumObjectPubConLists].pPubConList = new unsigned char[nPubConListSize]; |
|||
s_objectPubConLists[s_nNumObjectPubConLists].nPubConListSize = nPubConListSize; |
|||
memcpy(s_objectPubConLists[s_nNumObjectPubConLists].pPubConList, pPubConList, s_objectPubConLists[s_nNumObjectPubConLists].nPubConListSize); |
|||
s_nNumObjectPubConLists++; |
|||
} |
|||
|
|||
bool GetObjectPubConList(char* pFilename, unsigned char** ppPubConList, int* pnPubConListSize) |
|||
{ |
|||
ObjectPubConListEntry* pObject = GetObjectPubConListEntryByName(pFilename); |
|||
if (pObject && pObject->pPubConList != 0 && pObject->nPubConListSize > 0) |
|||
{ |
|||
*ppPubConList = pObject->pPubConList; |
|||
*pnPubConListSize = pObject->nPubConListSize; |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
struct ObjectCogInitEntry |
|||
{ |
|||
char filename[256]; |
|||
int nSubConstant; |
|||
}; |
|||
|
|||
ObjectCogInitEntry s_objectCogInits[file_limit * file_limit]; |
|||
int s_nNumObjectCogInits; |
|||
|
|||
void AddCogNewOrInit(char* pFilename, int nSubConstant) |
|||
{ |
|||
if (s_nNumObjectCogInits > 0) |
|||
{ |
|||
// see if this combo already is in the array
|
|||
for (int i = s_nNumObjectCogInits; i > 0; i--) |
|||
{ |
|||
if (s_objectCogInits[i-1].nSubConstant == nSubConstant && strcmp(s_objectCogInits[i-1].filename, pFilename) == 0) |
|||
{ |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
// wasn't already there, so add it
|
|||
strcpy(s_objectCogInits[s_nNumObjectCogInits].filename, pFilename); |
|||
s_objectCogInits[s_nNumObjectCogInits].nSubConstant = nSubConstant; |
|||
s_nNumObjectCogInits++; |
|||
} |
|||
|
|||
void MarkCalls(MethodUsage* pMethod, ObjectEntry* pObject); |
|||
|
|||
void CheckForCogNewOrInit(ObjectEntry* pObject) |
|||
{ |
|||
char* pObjectFilename = s_objectNames[pObject->nObjectNameIndex].filename; |
|||
for (int i = 0; i < s_nNumObjectCogInits; i++) |
|||
{ |
|||
if (strcmp(s_objectCogInits[i].filename, pObjectFilename) == 0) |
|||
{ |
|||
// don't do this if the object has no called methods already
|
|||
// in that case it means the cognew/coginit is never done, so it's safe to not mark the referred to method
|
|||
if (pObject->nMethodsCalled > 0) |
|||
{ |
|||
MarkCalls(&(pObject->pMethods[s_objectCogInits[i].nSubConstant - 1]), pObject); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
void CleanUpUnusedMethodData() |
|||
{ |
|||
for (int i = 0; i < s_nNumObjects; i++) |
|||
{ |
|||
s_objects[i].pObject = 0; |
|||
s_objects[i].pIndexTable = 0; |
|||
|
|||
for (int j = 0; j < s_objects[s_nNumObjects].nObjectMethodCount; j++) |
|||
{ |
|||
if (s_objects[i].pMethods[j].pCalls) |
|||
{ |
|||
delete [] s_objects[i].pMethods[j].pCalls; |
|||
s_objects[i].pMethods[j].pCalls = 0; |
|||
} |
|||
} |
|||
delete [] s_objects[i].pMethods; |
|||
s_objects[i].pMethods = 0; |
|||
} |
|||
s_nNumObjects = 0; |
|||
s_nNumObjectNames = 0; |
|||
|
|||
for (int i = 0; i < s_nNumObjectPubConLists; i++) |
|||
{ |
|||
delete [] s_objectPubConLists[i].pPubConList; |
|||
s_objectPubConLists[i].pPubConList = 0; |
|||
} |
|||
s_nNumObjectPubConLists = 0; |
|||
|
|||
s_nNumObjectCogInits = 0; |
|||
} |
|||
|
|||
void InitUnusedMethodData() |
|||
{ |
|||
for (int i = 0; i < (file_limit * file_limit); i++) |
|||
{ |
|||
s_objectPubConLists[i].filename[0] = 0; |
|||
s_objectPubConLists[i].pPubConList = 0; |
|||
s_objectPubConLists[i].nPubConListSize = 0; |
|||
} |
|||
s_nNumObjectPubConLists = 0; |
|||
s_nNumObjectCogInits = 0; |
|||
s_nNumObjectNames = 0; |
|||
} |
|||
|
|||
void AdvanceCompileIndex(unsigned char* pObject, int& nCompileIndex) |
|||
{ |
|||
nCompileIndex++; |
|||
|
|||
int nNextObjOffset = *((unsigned short *)pObject); |
|||
ObjectEntry* pObjectEntry = GetObject(pObject); |
|||
for (int i = 0; i < pObjectEntry->nObjectIndexCount; i++) |
|||
{ |
|||
if (pObjectEntry->pIndexTable[i].offset >= nNextObjOffset) |
|||
{ |
|||
AdvanceCompileIndex(&(pObject[pObjectEntry->pIndexTable[i].offset]), nCompileIndex); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void BuildTables(unsigned char* pObject, int indent, int& nCompileIndex) |
|||
{ |
|||
#ifdef RPE_DEBUG |
|||
#define MAX_INDENT 32 |
|||
char s_indent[MAX_INDENT+1] = " "; |
|||
#endif |
|||
|
|||
if (HaveObject(pObject)) |
|||
{ |
|||
#ifdef RPE_DEBUG |
|||
printf("%sObject Already Added\n", &s_indent[MAX_INDENT-indent]); |
|||
#endif |
|||
AdvanceCompileIndex(pObject, nCompileIndex); |
|||
return; |
|||
} |
|||
nCompileIndex++; |
|||
int nNextObjOffset = *((unsigned short *)pObject); |
|||
int nObjectName = GetObjectName(nCompileIndex); |
|||
int nObject = AddObject(pObject, nObjectName); |
|||
|
|||
#ifdef RPE_DEBUG |
|||
printf("%sObject Index Table: %s\n", &s_indent[MAX_INDENT-indent], s_objectNames[s_objects[nObject].nObjectNameIndex].filename); |
|||
#endif |
|||
for (int i = 0; i < s_objects[nObject].nObjectIndexCount; i++) |
|||
{ |
|||
if (s_objects[nObject].pIndexTable[i].offset >= nNextObjOffset) |
|||
{ |
|||
#ifdef RPE_DEBUG |
|||
printf("%s Object Offset: %04d Vars Offset: %d\n", &s_indent[MAX_INDENT-indent], s_objects[nObject].pIndexTable[i].offset, s_objects[nObject].pIndexTable[i].vars); |
|||
#endif |
|||
// this skip logic here is to handle the case where there are multiple instances of the same object source included
|
|||
// either as an array of objects or as separately named objects
|
|||
bool bSkip = false; |
|||
for (int j = 0; j < i; j++) |
|||
{ |
|||
if (s_objects[nObject].pIndexTable[i].offset == s_objects[nObject].pIndexTable[j].offset) |
|||
{ |
|||
bSkip = true; |
|||
} |
|||
} |
|||
if (!bSkip) |
|||
{ |
|||
BuildTables(&(pObject[s_objects[nObject].pIndexTable[i].offset]), indent + 1, nCompileIndex); |
|||
} |
|||
} |
|||
#ifdef RPE_DEBUG |
|||
else |
|||
{ |
|||
printf("%s Method Offset: %04d Locals size: %d\n", &s_indent[MAX_INDENT-indent], s_objects[nObject].pIndexTable[i].offset, s_objects[nObject].pIndexTable[i].vars); |
|||
} |
|||
#endif |
|||
} |
|||
} |
|||
|
|||
//
|
|||
// byte code scanning stuff
|
|||
// borrowed from Dave Hein's spinsim code and then modified for my needs (mostly stripped down to just skip intelligently over byte code)
|
|||
//
|
|||
|
|||
int SkipSignedOffset(unsigned char* pOpcode) |
|||
{ |
|||
return (*pOpcode < 0x80) ? 1 : 2; |
|||
} |
|||
|
|||
int SkipUnsignedOffset(unsigned char* pOpcode) |
|||
{ |
|||
return (*pOpcode & 0x80) ? 2 : 1; |
|||
} |
|||
|
|||
int ScanMathOpcode(unsigned char* pOpcode) |
|||
{ |
|||
bool execflag = false; |
|||
int opcode = *pOpcode; |
|||
|
|||
if (opcode < 0xe0) |
|||
{ |
|||
execflag = true; |
|||
opcode += 0xe0 - 0x40; |
|||
} |
|||
|
|||
// Execute the math op
|
|||
switch (opcode) |
|||
{ |
|||
case 0xe0: // ror
|
|||
case 0xe1: // rol
|
|||
case 0xe2: // shr
|
|||
case 0xe3: // shl
|
|||
case 0xe4: // min
|
|||
case 0xe5: // max
|
|||
case 0xe6: // neg
|
|||
case 0xe7: // com
|
|||
case 0xe8: // and
|
|||
case 0xe9: // abs
|
|||
case 0xea: // or
|
|||
case 0xeb: // xor
|
|||
case 0xec: // add
|
|||
case 0xed: // sub
|
|||
case 0xee: // sar
|
|||
case 0xef: // rev
|
|||
case 0xf0: // andl
|
|||
case 0xf1: // encode
|
|||
case 0xf4: // mul
|
|||
case 0xf5: // mulh
|
|||
case 0xf2: // orl
|
|||
case 0xf3: // decode
|
|||
case 0xf6: // div
|
|||
case 0xf7: // mod
|
|||
case 0xf8: // sqrt
|
|||
case 0xf9: // cmplt
|
|||
case 0xfa: // cmpgt
|
|||
case 0xfb: // cmpne
|
|||
case 0xfc: // cmpeq
|
|||
case 0xfd: // cmple
|
|||
case 0xfe: // cmpgr
|
|||
case 0xff: // notl
|
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
|
|||
return (execflag ? 0 : 1); |
|||
} |
|||
|
|||
int ScanExtraOpcode(unsigned char* pOpcode, int opcode) |
|||
{ |
|||
int nOpSize = 0; |
|||
|
|||
opcode &= 0x7f; |
|||
|
|||
if (opcode >= 0x40 && opcode < 0x60) // math op
|
|||
{ |
|||
nOpSize += ScanMathOpcode(pOpcode); |
|||
} |
|||
else if ((opcode & 0x7e) == 0x00) // store
|
|||
{ |
|||
} |
|||
else if ((opcode & 0x7a) == 0x02) // repeat, repeats
|
|||
{ |
|||
nOpSize += SkipSignedOffset(pOpcode); |
|||
} |
|||
else if ((opcode & 0x78) == 8) // randf, randr
|
|||
{ |
|||
} |
|||
else if ((opcode & 0x7c) == 0x10) // sexb
|
|||
{ |
|||
} |
|||
else if ((opcode & 0x7c) == 0x14) // sexw
|
|||
{ |
|||
} |
|||
else if ((opcode & 0x7c) == 0x18) // postclr
|
|||
{ |
|||
} |
|||
else if ((opcode & 0x7c) == 0x1c) // postset
|
|||
{ |
|||
} |
|||
else if ((opcode & 0x78) == 0x20) // preinc
|
|||
{ |
|||
} |
|||
else if ((opcode & 0x78) == 0x28) // postinc
|
|||
{ |
|||
} |
|||
else if ((opcode & 0x78) == 0x30) // predec
|
|||
{ |
|||
} |
|||
else if ((opcode & 0x78) == 0x38) // postdec
|
|||
{ |
|||
} |
|||
else |
|||
{ |
|||
#ifdef _DEBUG |
|||
printf("NOT IMPLEMENTED\n"); |
|||
#endif |
|||
} |
|||
|
|||
return nOpSize; |
|||
} |
|||
|
|||
|
|||
int ScanMemoryOpcode(unsigned char* pOpcode) |
|||
{ |
|||
int opcode = *pOpcode; |
|||
int memfunc = opcode & 3; |
|||
|
|||
int nOpSize = 1; |
|||
|
|||
if (opcode < 0x80) // Compact offset
|
|||
{ |
|||
} |
|||
else |
|||
{ |
|||
if ((opcode & 0x0c) >> 2) |
|||
{ |
|||
nOpSize += SkipUnsignedOffset(&pOpcode[nOpSize]); |
|||
} |
|||
} |
|||
|
|||
if (memfunc == 3) // la
|
|||
{ |
|||
} |
|||
else if (memfunc == 0) // ld
|
|||
{ |
|||
} |
|||
else if (memfunc == 1) // st
|
|||
{ |
|||
} |
|||
else // ex
|
|||
{ |
|||
opcode = pOpcode[nOpSize]; |
|||
nOpSize++; |
|||
|
|||
nOpSize += ScanExtraOpcode(&pOpcode[nOpSize], opcode); |
|||
} |
|||
|
|||
return nOpSize; |
|||
} |
|||
|
|||
int ScanRegisterOpcode(unsigned char* pOpcode, int operand) |
|||
{ |
|||
int opcode; |
|||
int nOpSize = 0; |
|||
int memfunc = (operand >> 5) & 3; |
|||
|
|||
if (memfunc == 1) // store
|
|||
{ |
|||
} |
|||
else if (memfunc == 0) // load
|
|||
{ |
|||
} |
|||
else if (memfunc == 2) // execute
|
|||
{ |
|||
opcode = *pOpcode; |
|||
nOpSize++; |
|||
|
|||
nOpSize += ScanExtraOpcode(&pOpcode[nOpSize], opcode); |
|||
} |
|||
else |
|||
{ |
|||
#ifdef _DEBUG |
|||
printf("Undefined register operation\n"); |
|||
#endif |
|||
} |
|||
|
|||
return nOpSize; |
|||
} |
|||
|
|||
int ScanLowerOpcode(unsigned char* pOpcode, MethodUsage* pUsage, ObjectEntry* pObject, unsigned char* pMethodStart) |
|||
{ |
|||
int opcode = *pOpcode; |
|||
int nOpSize = 1; |
|||
|
|||
if (opcode <= 3) // ldfrmr, ldfrm, ldfrmar, ldfrma
|
|||
{ |
|||
} |
|||
else if (opcode == 0x04) // jmp
|
|||
{ |
|||
nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); |
|||
} |
|||
else if (opcode >= 0x05 && opcode <= 0x07) // call, callobj, callobjx
|
|||
{ |
|||
int objnum = 0; |
|||
|
|||
if (opcode > 0x05) |
|||
{ |
|||
objnum = pOpcode[nOpSize]; |
|||
nOpSize++; |
|||
if (opcode == 0x07) |
|||
{ |
|||
// indexed
|
|||
} |
|||
|
|||
// skip over invalid calls (happens when we scan strings as opcodes, this can go away when we fix scanning strings properly)
|
|||
if (objnum < 0 || objnum > (pObject->nObjectMethodCount + pObject->nObjectSubObjectCount)) |
|||
{ |
|||
return nOpSize + 1; |
|||
} |
|||
} |
|||
|
|||
int pubnum = pOpcode[nOpSize]; |
|||
nOpSize++; |
|||
|
|||
// skip over invalid calls (happens when we scan strings as opcodes, this can go away when we fix scanning strings properly)
|
|||
if (objnum == 0 && (pubnum < 0 || pubnum > pObject->nObjectMethodCount)) |
|||
{ |
|||
return nOpSize; |
|||
} |
|||
|
|||
// need to update usage here
|
|||
if (pUsage->pCalls == 0) |
|||
{ |
|||
pUsage->nCalls++; |
|||
} |
|||
else |
|||
{ |
|||
pUsage->pCalls[pUsage->nCurrCall].opcode = (unsigned char)opcode; |
|||
pUsage->pCalls[pUsage->nCurrCall].pubnum = (unsigned char)pubnum; |
|||
pUsage->pCalls[pUsage->nCurrCall].callOffset = (unsigned int)((&pOpcode[1]) - pMethodStart); |
|||
|
|||
if (opcode > 0x05) |
|||
{ |
|||
pUsage->pCalls[pUsage->nCurrCall].objnum = (unsigned char)objnum; |
|||
pUsage->pCalls[pUsage->nCurrCall].objoffset = pObject->pIndexTable[objnum-1].offset; |
|||
pUsage->pCalls[pUsage->nCurrCall].objaddress = &pObject->pObject[pUsage->pCalls[pUsage->nCurrCall].objoffset]; |
|||
#ifdef RPE_DEBUG |
|||
printf(" callobj %02X:%02X (%p)\n", pUsage->pCalls[pUsage->nCurrCall].objnum, pUsage->pCalls[pUsage->nCurrCall].pubnum, pUsage->pCalls[pUsage->nCurrCall].objaddress); |
|||
#endif |
|||
} |
|||
else |
|||
{ |
|||
pUsage->pCalls[pUsage->nCurrCall].objnum = 0; |
|||
pUsage->pCalls[pUsage->nCurrCall].objoffset = 0; |
|||
pUsage->pCalls[pUsage->nCurrCall].objaddress = (pObject->pObject); |
|||
#ifdef RPE_DEBUG |
|||
printf(" call %02X (%p)\n", pUsage->pCalls[pUsage->nCurrCall].pubnum, pUsage->pCalls[pUsage->nCurrCall].objaddress); |
|||
#endif |
|||
} |
|||
pUsage->nCurrCall++; |
|||
} |
|||
} |
|||
else if (opcode == 0x08) // tjz
|
|||
{ |
|||
nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); |
|||
} |
|||
else if (opcode == 0x09) // djnz
|
|||
{ |
|||
nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); |
|||
} |
|||
else if (opcode == 0x0a) // jz
|
|||
{ |
|||
nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); |
|||
} |
|||
else if (opcode == 0x0b) // jnz
|
|||
{ |
|||
nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); |
|||
} |
|||
else if (opcode >= 0x0c && opcode <= 0x15) |
|||
{ |
|||
if (opcode == 0x0c) // casedone
|
|||
{ |
|||
} |
|||
else if (opcode == 0x0d) // casevalue
|
|||
{ |
|||
nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); |
|||
} |
|||
else if (opcode == 0x0e) // caserange
|
|||
{ |
|||
nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); |
|||
} |
|||
else if (opcode == 0x0f) // lookdone
|
|||
{ |
|||
} |
|||
else if (opcode == 0x10) // lookupval
|
|||
{ |
|||
} |
|||
else if (opcode == 0x11) // lookdnval
|
|||
{ |
|||
} |
|||
else if (opcode == 0x12) // lookuprng
|
|||
{ |
|||
} |
|||
else if (opcode == 0x13) // lookdnrng
|
|||
{ |
|||
} |
|||
else if (opcode == 0x14) // pop
|
|||
{ |
|||
} |
|||
else if (opcode == 0x15) // run
|
|||
{ |
|||
} |
|||
else |
|||
{ |
|||
#ifdef _DEBUG |
|||
printf("%2.2x - NOT IMPLEMENTED\n", opcode); |
|||
#endif |
|||
} |
|||
} |
|||
else if (opcode >= 0x16 && opcode <= 0x23) |
|||
{ |
|||
if (opcode == 0x16) // strsize
|
|||
{ |
|||
} |
|||
else if (opcode == 0x17) // strcomp
|
|||
{ |
|||
} |
|||
else if (opcode == 0x18) // bytefill
|
|||
{ |
|||
} |
|||
else if (opcode == 0x19) // wordfill
|
|||
{ |
|||
} |
|||
else if (opcode == 0x1a) // longfill
|
|||
{ |
|||
} |
|||
else if (opcode == 0x1b) // waitpeq
|
|||
{ |
|||
} |
|||
else if (opcode >= 0x1c && opcode <= 0x1e ) // bytemove, wordmove, longmove
|
|||
{ |
|||
} |
|||
else if (opcode == 0x1f) // waitpne
|
|||
{ |
|||
} |
|||
else if (opcode == 0x20) // clkset
|
|||
{ |
|||
} |
|||
else if (opcode == 0x21) // cogstop
|
|||
{ |
|||
} |
|||
else if (opcode == 0x22) // lockret
|
|||
{ |
|||
} |
|||
else if (opcode == 0x23) // waitcnt
|
|||
{ |
|||
} |
|||
} |
|||
else if (opcode >= 0x24 && opcode <= 0x2f) |
|||
{ |
|||
if (opcode >= 0x24 && opcode <= 0x26) // ldregx, stregx, exregx
|
|||
{ |
|||
int operand = ((opcode & 3) << 5); |
|||
nOpSize += ScanRegisterOpcode(&pOpcode[nOpSize], operand); |
|||
} |
|||
else if (opcode == 0x27) // waitvid
|
|||
{ |
|||
} |
|||
else if (opcode == 0x28 || opcode == 0x2c) // coginitret, coginit
|
|||
{ |
|||
} |
|||
else if (opcode == 0x29 || opcode == 0x2d) // locknewret, locknew
|
|||
{ |
|||
} |
|||
else if (opcode == 0x2a || opcode == 0x2b || opcode == 0x2e || opcode == 0x2f) // locksetret, lockclrret, lockset, lockclr
|
|||
{ |
|||
} |
|||
} |
|||
else if (opcode >= 0x30 && opcode <= 0x33) // abort, abortval, ret, retval
|
|||
{ |
|||
} |
|||
else if (opcode >= 0x34 && opcode < 0x3c) |
|||
{ |
|||
if (opcode == 0x35) // dli0
|
|||
{ |
|||
} |
|||
else if (opcode == 0x36) // dli1
|
|||
{ |
|||
} |
|||
else if (opcode == 0x34) // dlim1
|
|||
{ |
|||
} |
|||
else if (opcode == 0x37) // ldlip
|
|||
{ |
|||
nOpSize++; |
|||
} |
|||
else // ldbi, ldwi, ldmi, ldli
|
|||
{ |
|||
while (opcode-- >= 0x38) |
|||
{ |
|||
nOpSize++; |
|||
} |
|||
} |
|||
} |
|||
else if (opcode == 0x3d) // ldregbit, stregbit, exregbit
|
|||
{ |
|||
int operand = pOpcode[nOpSize]; |
|||
nOpSize++; |
|||
|
|||
nOpSize += ScanRegisterOpcode(&pOpcode[nOpSize], operand); |
|||
} |
|||
else if (opcode == 0x3e) // ldregbits, stregbits, exregbits
|
|||
{ |
|||
int operand = pOpcode[nOpSize]; |
|||
nOpSize++; |
|||
|
|||
nOpSize += ScanRegisterOpcode(&pOpcode[nOpSize], operand); |
|||
} |
|||
else if (opcode == 0x3f) // ldreg, streg, exreg
|
|||
{ |
|||
int operand = pOpcode[nOpSize]; |
|||
nOpSize++; |
|||
|
|||
nOpSize += ScanRegisterOpcode(&pOpcode[nOpSize], operand); |
|||
} |
|||
else |
|||
{ |
|||
#ifdef _DEBUG |
|||
printf("NOT PROCESSED\n"); |
|||
#endif |
|||
} |
|||
|
|||
return nOpSize; |
|||
} |
|||
|
|||
|
|||
int ScanOpcode(unsigned char* pOpcode, MethodUsage* pUsage, ObjectEntry* pObject, unsigned char* pMethodStart) |
|||
{ |
|||
if (*pOpcode < 0x40) |
|||
{ |
|||
return ScanLowerOpcode(pOpcode, pUsage, pObject, pMethodStart); |
|||
} |
|||
else if (*pOpcode < 0xe0) |
|||
{ |
|||
return ScanMemoryOpcode(pOpcode); |
|||
} |
|||
else |
|||
{ |
|||
return ScanMathOpcode(pOpcode); |
|||
} |
|||
} |
|||
|
|||
|
|||
void ScanMethod(unsigned char* pMethod, MethodUsage* pUsage, ObjectEntry* pObject) |
|||
{ |
|||
#ifdef RPE_DEBUG |
|||
for (int i = 0; i < pUsage->nLength; i++) |
|||
{ |
|||
printf("%02x ", pMethod[i]); |
|||
} |
|||
printf("\n"); |
|||
#endif |
|||
|
|||
// scan once to count calls
|
|||
int nOffset = 0; |
|||
while (nOffset < pUsage->nLength) |
|||
{ |
|||
nOffset += ScanOpcode(&pMethod[nOffset], pUsage, pObject, pMethod); |
|||
} |
|||
if (pUsage->nCalls > 0) |
|||
{ |
|||
// if there were calls then allocate space and scan again to fill in call info
|
|||
pUsage->pCalls = new CallEntry[pUsage->nCalls]; |
|||
nOffset = 0; |
|||
while (nOffset < pUsage->nLength) |
|||
{ |
|||
nOffset += ScanOpcode(&pMethod[nOffset], pUsage, pObject, pMethod); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void ScanObjectMethods(ObjectEntry* pObjectEntry) |
|||
{ |
|||
for (int i = 0; i < pObjectEntry->nObjectMethodCount; i++) |
|||
{ |
|||
unsigned char* pMethod = pObjectEntry->pObject + pObjectEntry->pIndexTable[i].offset; |
|||
int nLength = 0; |
|||
if (i < pObjectEntry->nObjectMethodCount-1) |
|||
{ |
|||
nLength = pObjectEntry->pIndexTable[i+1].offset - pObjectEntry->pIndexTable[i].offset; |
|||
} |
|||
else |
|||
{ |
|||
int nNextObjectOffset = *((unsigned short *)(pObjectEntry->pObject)); |
|||
nLength = nNextObjectOffset - pObjectEntry->pIndexTable[i].offset; |
|||
} |
|||
pObjectEntry->pMethods[i].nLength = nLength; |
|||
ScanMethod(pMethod, &(pObjectEntry->pMethods[i]), pObjectEntry); |
|||
} |
|||
} |
|||
|
|||
void MarkCalls(MethodUsage* pMethod, ObjectEntry* pObject) |
|||
{ |
|||
if (pMethod->nCalled == 0) |
|||
{ |
|||
pMethod->nCalled = 1; |
|||
pObject->nMethodsCalled++; |
|||
|
|||
for (int nCall = 0; nCall < pMethod->nCalls; nCall++) |
|||
{ |
|||
CallEntry* pCall = &(pMethod->pCalls[nCall]); |
|||
if ( pCall->opcode == 5 ) // normal call
|
|||
{ |
|||
MarkCalls(&(pObject->pMethods[pCall->pubnum-1]), pObject); |
|||
} |
|||
else // obj call
|
|||
{ |
|||
ObjectEntry* pSubObject = GetObject(pCall->objaddress); |
|||
MarkCalls(&(pSubObject->pMethods[pCall->pubnum-1]), pSubObject); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
void FindUnusedMethods(CompilerData* pCompilerData) |
|||
{ |
|||
for (int i = 0; i < (file_limit * file_limit); i++) |
|||
{ |
|||
s_objects[i].pObject = 0; |
|||
s_objects[i].nObjectMethodCount = 0; |
|||
s_objects[i].nObjectSubObjectCount = 0; |
|||
s_objects[i].nObjectIndexCount = 0; |
|||
s_objects[i].nMethodsCalled = 0; |
|||
s_objects[i].nNewObjectIndex = 0; |
|||
s_objects[i].pIndexTable = 0; |
|||
s_objects[i].pMethods = 0; |
|||
} |
|||
s_nNumObjects = 0; |
|||
|
|||
int nCompileIndex = 0; |
|||
BuildTables(&(pCompilerData->obj[4]), 0, nCompileIndex); |
|||
|
|||
for (int i = 0; i < s_nNumObjects; i++) |
|||
{ |
|||
ScanObjectMethods(&s_objects[i]); |
|||
} |
|||
|
|||
ObjectEntry* pObject = &(s_objects[0]); |
|||
MethodUsage* pMethod = &(pObject->pMethods[0]); |
|||
MarkCalls(pMethod, pObject); |
|||
|
|||
for (int i = 0; i < s_nNumObjects; i++) |
|||
{ |
|||
CheckForCogNewOrInit(&s_objects[i]); |
|||
} |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,50 @@ |
|||
///////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
|
|||
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|||
// See end of file for terms of use. //
|
|||
// //
|
|||
///////////////////////////////////////////////////////////////
|
|||
//
|
|||
// UnusedMethodUtils.h
|
|||
//
|
|||
|
|||
#ifndef _UNUSEDMETHODUTILS_H_ |
|||
#define _UNUSEDMETHODUTILS_H_ |
|||
|
|||
struct CompilerData; |
|||
|
|||
void AddObjectName(char* pFilename, int nCompileIndex); |
|||
void FindUnusedMethods(CompilerData* pCompilerData); |
|||
void CleanUpUnusedMethodData(); |
|||
void InitUnusedMethodData(); |
|||
|
|||
bool IsObjectUsed(char* pFilename); |
|||
bool IsMethodUsed(char* pFilename, int nMethod); |
|||
void AddObjectPubConList(char* pFilename, unsigned char* pPubConList, int nPubConListSize); |
|||
bool GetObjectPubConList(char* pFilename, unsigned char** ppPubConList, int* pnPubConListSize); |
|||
|
|||
void AddCogNewOrInit(char* pFilename, int nSubConstant); |
|||
|
|||
#endif // _UNUSEDMETHODUTILS_H_
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,851 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// Utilities.cpp
|
|||
//
|
|||
|
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
#include <errno.h> |
|||
#include "PropellerCompilerInternal.h" |
|||
#include "SymbolEngine.h" |
|||
#include "Elementizer.h" |
|||
#include "ErrorStrings.h" |
|||
|
|||
char* pPrintDestination = 0; |
|||
int printLimit = 0; |
|||
|
|||
void SetPrint(char* pDestination, int limit) |
|||
{ |
|||
pPrintDestination = pDestination; |
|||
printLimit = limit; |
|||
g_pCompilerData->print_length = 0; |
|||
} |
|||
|
|||
bool PrintChr(char theChar) |
|||
{ |
|||
if (g_pCompilerData->print_length >= printLimit) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_litl]; |
|||
return false; |
|||
} |
|||
pPrintDestination[g_pCompilerData->print_length++] = theChar; |
|||
return true; |
|||
} |
|||
|
|||
bool PrintString(const char* theString) |
|||
{ |
|||
int stringOffset = 0; |
|||
bool result = true; |
|||
char theChar = theString[stringOffset++]; |
|||
while(theChar != 0 && result) |
|||
{ |
|||
result = PrintChr(theChar); |
|||
theChar = theString[stringOffset++]; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
bool PrintSymbol(const char* pSymbolName, unsigned char type, int value, int value_2) |
|||
{ |
|||
char tempStr[symbol_limit + 64]; |
|||
sprintf(tempStr, "TYPE: %02X", type); |
|||
if (!PrintString(tempStr)) |
|||
{ |
|||
return false; |
|||
} |
|||
sprintf(tempStr, " VALUE: %08X (%08x)", value, value_2); |
|||
if (!PrintString(tempStr)) |
|||
{ |
|||
return false; |
|||
} |
|||
sprintf(tempStr, " NAME: %s\r", pSymbolName); |
|||
return PrintString(tempStr); |
|||
} |
|||
|
|||
bool ListLine(int offset, int count) |
|||
{ |
|||
char tempStr[8]; |
|||
sprintf(tempStr, "%04X-", offset); |
|||
if (!PrintString(tempStr)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
for (int i = 0; i < 17; i++) |
|||
{ |
|||
if (i < count) |
|||
{ |
|||
sprintf(tempStr, " %02X", g_pCompilerData->obj[offset+i]); |
|||
if (!PrintString(tempStr)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (!PrintChr(32)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!PrintChr(32)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!PrintChr(32)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
unsigned char theChar = g_pCompilerData->obj[offset+i]; |
|||
if (theChar < ' ' || theChar >= 0x7F) |
|||
{ |
|||
theChar = '.'; |
|||
} |
|||
if (!PrintChr(theChar)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
return PrintChr(13); |
|||
} |
|||
|
|||
bool PrintObj() |
|||
{ |
|||
char tempStr[256]; |
|||
sprintf(tempStr, "\rOBJ bytes: %d", g_pCompilerData->obj_ptr); |
|||
if (!PrintString(tempStr)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
sprintf(tempStr, "\r\r_CLKMODE: %02X", g_pCompilerData->clkmode); |
|||
if (!PrintString(tempStr)) |
|||
{ |
|||
return false; |
|||
} |
|||
sprintf(tempStr, "\r_CLKFREQ: %08X\r\r", g_pCompilerData->clkfreq); |
|||
if (!PrintString(tempStr)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
for (int i = 0; i < g_pCompilerData->obj_ptr; i+=16) |
|||
{ |
|||
if (!ListLine(i, ((i + 16) < g_pCompilerData->obj_ptr) ? 16 : (g_pCompilerData->obj_ptr - i))) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool DocPrint(char theChar) |
|||
{ |
|||
if (g_pCompilerData->doc_mode) |
|||
{ |
|||
return PrintChr(theChar); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
// assumes theChar has been uppercased.
|
|||
bool CheckWordChar(char theChar) |
|||
{ |
|||
if ((theChar >= '0' && theChar <= '9') || (theChar == '_') || (theChar >= 'A' && theChar <= 'Z')) |
|||
{ |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
char Uppercase(char theChar) |
|||
{ |
|||
if (theChar >= 'a' && theChar <= 'z') |
|||
{ |
|||
return theChar - ('a' - 'A'); |
|||
} |
|||
return theChar; |
|||
} |
|||
|
|||
// if theChar is a hex digit this returns true and digitValue is 0 to 15 depending on the digit
|
|||
bool CheckHex(char theChar, char& digitValue) |
|||
{ |
|||
theChar = Uppercase(theChar); |
|||
digitValue = theChar - '0'; |
|||
if (digitValue >= 0 && digitValue <= 9) |
|||
{ |
|||
return true; |
|||
} |
|||
digitValue -= ('A' - '9' - 1); |
|||
if (digitValue >= 10 && digitValue <= 15) |
|||
{ |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
// if theChar is a valid digit in numberBase this returns true and digitValue is 0 to numberBase-1 depending on the digit
|
|||
bool CheckDigit(char theChar, char& digitValue, char numberBase) |
|||
{ |
|||
if (CheckHex(theChar, digitValue)) |
|||
{ |
|||
if (digitValue < numberBase) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
bool CheckPlus(char theChar) |
|||
{ |
|||
if (theChar == '+') |
|||
{ |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
bool CheckLocal(bool& bLocal) |
|||
{ |
|||
if (g_pElementizer->GetType() != type_colon) |
|||
{ |
|||
bLocal = false; |
|||
return true; |
|||
} |
|||
else |
|||
{ |
|||
int save_start = g_pCompilerData->source_start; |
|||
int length = 0; |
|||
if (!GetSymbol(&length)) |
|||
{ |
|||
return false; |
|||
} |
|||
g_pCompilerData->source_start = save_start; |
|||
if (length == 0) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eals]; |
|||
return false; |
|||
} |
|||
if (length > symbol_limit) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_sexc]; |
|||
return false; |
|||
} |
|||
|
|||
int temp = g_pCompilerData->asm_local; |
|||
temp += 0x01010101; //(last four characters range from 01h-20h)
|
|||
|
|||
//append above four bytes to the symbol name
|
|||
char* pSymbol = g_pElementizer->GetCurrentSymbol(); |
|||
pSymbol += strlen(pSymbol); |
|||
//*((int*)pSymbol) = temp;
|
|||
pSymbol[0] = (char)(temp & 0xFF); |
|||
pSymbol[1] = (char)((temp >> 8) & 0xFF); |
|||
pSymbol[2] = (char)((temp >> 16) & 0xFF); |
|||
pSymbol[3] = (char)((temp >> 24) & 0xFF); |
|||
pSymbol += 4; |
|||
*pSymbol = 0; |
|||
|
|||
// re-get the symbol (point to the beginning of it)
|
|||
pSymbol = g_pElementizer->GetCurrentSymbol(); |
|||
|
|||
// try to find the symbol
|
|||
g_pElementizer->FindSymbol(pSymbol); |
|||
bLocal = true; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
// returns true if it's able to get a valid float from pSource
|
|||
// on success, value will be the float value
|
|||
bool GetFloat(char* pSource, int& sourceOffset, int& value) |
|||
{ |
|||
// copy stuff to a temp buffer, stripping _'s and going until an invalid float char
|
|||
// this also stops if we hit a second ., a second E, or get a sign without and E before it
|
|||
//
|
|||
char temp[128]; |
|||
int tempOffset = 0; |
|||
bool bGotDot = false; |
|||
bool bGotE = false; |
|||
bool bGotSign = false; |
|||
while(tempOffset < 127) |
|||
{ |
|||
char currentChar = pSource[sourceOffset++]; |
|||
if (currentChar == '_') |
|||
{ |
|||
continue; |
|||
} |
|||
if (currentChar >= '0' && currentChar <= '9') |
|||
{ |
|||
temp[tempOffset++] = currentChar; |
|||
} |
|||
else if (bGotDot == false && currentChar == '.') |
|||
{ |
|||
temp[tempOffset++] = currentChar; |
|||
bGotDot = true; |
|||
} |
|||
else if (bGotE == false && (currentChar == 'e' || currentChar == 'E')) |
|||
{ |
|||
temp[tempOffset++] = currentChar; |
|||
bGotE = true; |
|||
} |
|||
else if (bGotE == true && bGotSign == false && (currentChar == '+' || currentChar == '-')) |
|||
{ |
|||
temp[tempOffset++] = currentChar; |
|||
bGotSign = true; |
|||
} |
|||
else |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
// terminate temp buffer
|
|||
temp[tempOffset] = 0; |
|||
|
|||
// if temp is full bail (it's not possible for this to be a valid float)
|
|||
if (tempOffset == 127) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// use strtod to convert temp to a float
|
|||
char* endPtr; |
|||
float floatValue = (float)strtod(temp, &endPtr); |
|||
|
|||
// if strtod failed then bail
|
|||
if (endPtr == temp || errno == ERANGE) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// then use pointer assignment trick to assign float into int without casting
|
|||
value = *((int*)&floatValue); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool GetSymbol(int* pLength) |
|||
{ |
|||
bool bEof = false; |
|||
|
|||
if (!g_pElementizer->GetNext(bEof)) |
|||
{ |
|||
return false; |
|||
} |
|||
char* pSymbol = g_pElementizer->GetCurrentSymbol(); |
|||
if (!CheckWordChar(pSymbol[0])) // g_pCompilerData->source[g_pCompilerData->source_start]
|
|||
{ |
|||
*pLength = 0; |
|||
} |
|||
else |
|||
{ |
|||
*pLength = (int)strlen(pSymbol); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool GetObjSymbol(int type, char id) |
|||
{ |
|||
int length = 0; |
|||
if (!GetSymbol(&length)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (length > 0) |
|||
{ |
|||
// append id to symbol
|
|||
char* pSymbol = g_pElementizer->GetCurrentSymbol(); |
|||
pSymbol[length] = id + 1; |
|||
pSymbol[length+1] = 0; |
|||
|
|||
g_pElementizer->FindSymbol(pSymbol); |
|||
|
|||
if (type == type_objpub) |
|||
{ |
|||
if (g_pElementizer->GetType() == type_objpub) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (g_pElementizer->GetType() == type_objcon || g_pElementizer->GetType() == type_objcon_float) |
|||
{ |
|||
// convert type_objcon_xx to type_con_xx
|
|||
g_pElementizer->ObjConToCon(); |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
g_pCompilerData->error = true; |
|||
if (type == type_objpub) |
|||
{ |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_easn]; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eacn]; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
bool GetCommaOrEnd(bool& bComma) |
|||
{ |
|||
bool bEof = false; |
|||
g_pElementizer->GetNext(bEof); |
|||
if (g_pElementizer->GetType() == type_comma) |
|||
{ |
|||
bComma = true; |
|||
return true; |
|||
} |
|||
if (g_pElementizer->GetType() == type_end) |
|||
{ |
|||
bComma = false; |
|||
return true; |
|||
} |
|||
|
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_ecoeol]; |
|||
return false; |
|||
} |
|||
|
|||
bool GetCommaOrRight(bool& bComma) |
|||
{ |
|||
bool bEof = false; |
|||
g_pElementizer->GetNext(bEof); |
|||
if (g_pElementizer->GetType() == type_comma) |
|||
{ |
|||
bComma = true; |
|||
return true; |
|||
} |
|||
if (g_pElementizer->GetType() == type_right) |
|||
{ |
|||
bComma = false; |
|||
return true; |
|||
} |
|||
|
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_ecor]; |
|||
return false; |
|||
} |
|||
|
|||
bool GetPipeOrEnd(bool& bPipe) |
|||
{ |
|||
bool bEof = false; |
|||
g_pElementizer->GetNext(bEof); |
|||
if (g_pElementizer->GetType() == type_binary && g_pElementizer->GetOpType() == op_or) |
|||
{ |
|||
bPipe = true; |
|||
return true; |
|||
} |
|||
if (g_pElementizer->GetType() == type_end) |
|||
{ |
|||
bPipe = false; |
|||
return true; |
|||
} |
|||
|
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_epoeol]; |
|||
return false; |
|||
} |
|||
|
|||
// this puts the filename into g_pCompilerData->filename
|
|||
bool GetFilename(int& filenameStart, int& filenameFinish) |
|||
{ |
|||
bool bEof = false; |
|||
int filenameOffset = 0; |
|||
|
|||
g_pElementizer->GetNext(bEof); |
|||
filenameStart = g_pCompilerData->source_start; |
|||
g_pElementizer->Backup(); |
|||
|
|||
for (;;) |
|||
{ |
|||
g_pElementizer->GetNext(bEof); |
|||
if (g_pElementizer->GetType() != type_con) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_ifufiq]; |
|||
return false; |
|||
} |
|||
char theChar = (char)(g_pElementizer->GetValue()); |
|||
|
|||
// check for illegal characters in filename
|
|||
if (theChar > 127 || theChar < 32 || theChar == '\\' || theChar == '/' || |
|||
theChar == ':' || theChar == '*' || theChar == '?' || theChar == '\"' || |
|||
theChar == '<' || theChar == '>' || theChar == '|') |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_ifc]; |
|||
break; |
|||
} |
|||
|
|||
// add character
|
|||
g_pCompilerData->filename[filenameOffset++] = theChar; |
|||
filenameFinish = g_pCompilerData->source_finish; |
|||
|
|||
// see if the filename is too long
|
|||
if (filenameOffset > 253) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_ftl]; |
|||
break; |
|||
} |
|||
|
|||
if (!g_pElementizer->CheckElement(type_comma)) |
|||
{ |
|||
g_pCompilerData->filename[filenameOffset] = 0; // terminate filename
|
|||
g_pCompilerData->source_start = filenameStart; |
|||
g_pCompilerData->source_finish = filenameFinish; |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
void EnterInfo() |
|||
{ |
|||
int index = g_pCompilerData->info_count; |
|||
if (index >= info_limit) |
|||
{ |
|||
index--; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->info_count++; |
|||
} |
|||
|
|||
g_pCompilerData->info_start[index] = g_pCompilerData->inf_start; |
|||
g_pCompilerData->info_finish[index] = g_pCompilerData->inf_finish; |
|||
g_pCompilerData->info_type[index] = g_pCompilerData->inf_type; |
|||
g_pCompilerData->info_data0[index] = g_pCompilerData->inf_data0; |
|||
g_pCompilerData->info_data1[index] = g_pCompilerData->inf_data1; |
|||
g_pCompilerData->info_data2[index] = g_pCompilerData->inf_data2; |
|||
g_pCompilerData->info_data3[index] = g_pCompilerData->inf_data3; |
|||
g_pCompilerData->info_data4[index] = g_pCompilerData->inf_data4; |
|||
} |
|||
|
|||
bool EnterObj(unsigned char value) |
|||
{ |
|||
if (g_pCompilerData->obj_ptr < g_pCompilerData->obj_limit) |
|||
{ |
|||
g_pCompilerData->obj[g_pCompilerData->obj_ptr++] = value; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_oex]; |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool EnterObjLong(int value) |
|||
{ |
|||
if (g_pCompilerData->obj_ptr+4 < g_pCompilerData->obj_limit) |
|||
{ |
|||
g_pCompilerData->obj[g_pCompilerData->obj_ptr++] = (unsigned char)value; |
|||
value >>= 8; |
|||
g_pCompilerData->obj[g_pCompilerData->obj_ptr++] = (unsigned char)value; |
|||
value >>= 8; |
|||
g_pCompilerData->obj[g_pCompilerData->obj_ptr++] = (unsigned char)value; |
|||
value >>= 8; |
|||
g_pCompilerData->obj[g_pCompilerData->obj_ptr++] = (unsigned char)value; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_oex]; |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool IncrementAsmLocal() |
|||
{ |
|||
unsigned char* pAsmLocal = (unsigned char*)&(g_pCompilerData->asm_local); |
|||
(*pAsmLocal)++; |
|||
(*pAsmLocal)&=0x1F; |
|||
if (*pAsmLocal == 0) |
|||
{ |
|||
(*(pAsmLocal+1))++; |
|||
(*(pAsmLocal+1))&=0x1F; |
|||
if ((*(pAsmLocal+1)) == 0) |
|||
{ |
|||
(*(pAsmLocal+2))++; |
|||
(*(pAsmLocal+2))&=0x1F; |
|||
if ((*(pAsmLocal+2)) == 0) |
|||
{ |
|||
(*(pAsmLocal+3))++; |
|||
(*(pAsmLocal+3))&=0x1F; |
|||
if ((*(pAsmLocal+3)) == 0) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_loxdse]; |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool AddFileName(int& fileCount, int& fileIndex, char* pFilenames, int* pNameStart, int* pNameFinish, int error) |
|||
{ |
|||
int filenameStart = 0; |
|||
int filenameFinish = 0; |
|||
if (GetFilename(filenameStart, filenameFinish)) |
|||
{ |
|||
for (int i = 0; i < fileCount; i++) |
|||
{ |
|||
if (strcmp(&pFilenames[i*256], g_pCompilerData->filename) == 0) |
|||
{ |
|||
// filename already in list
|
|||
fileIndex = i; |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
// not in list, so add it if there is room
|
|||
if (fileCount < file_limit) |
|||
{ |
|||
pNameStart[fileCount] = filenameStart; |
|||
pNameFinish[fileCount] = filenameFinish; |
|||
strcpy(&pFilenames[fileCount*256], g_pCompilerData->filename); |
|||
fileIndex = fileCount; |
|||
fileCount++; |
|||
return true; |
|||
} |
|||
|
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error]; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
bool AddPubConListByte(char value) |
|||
{ |
|||
if (g_pCompilerData->pubcon_list_size < pubcon_list_limit) |
|||
{ |
|||
g_pCompilerData->pubcon_list[g_pCompilerData->pubcon_list_size] = value; |
|||
g_pCompilerData->pubcon_list_size++; |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_pclo]; |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool AddSymbolToPubConList() |
|||
{ |
|||
for (unsigned int i = 0; i < strlen(g_pCompilerData->symbolBackup); i++) |
|||
{ |
|||
if (!AddPubConListByte(g_pCompilerData->symbolBackup[i])) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool ConAssign(bool bFloat, int value) |
|||
{ |
|||
if (g_pCompilerData->assign_flag == 0) |
|||
{ |
|||
// verify
|
|||
g_pCompilerData->source_start = g_pCompilerData->inf_start; |
|||
g_pCompilerData->source_finish = g_pCompilerData->inf_finish; |
|||
|
|||
int type = bFloat ? type_con_float : type_con; |
|||
if (g_pCompilerData->assign_type != type || g_pCompilerData->assign_value != value) |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_siad]; |
|||
return false; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->inf_type = bFloat ? info_con_float : info_con; |
|||
g_pCompilerData->inf_data0 = value; |
|||
g_pCompilerData->inf_data1 = 0; |
|||
g_pCompilerData->inf_data2 = 0; |
|||
g_pCompilerData->inf_data3 = 0; |
|||
g_pCompilerData->inf_data4 = 0; |
|||
EnterInfo(); |
|||
|
|||
if (!AddSymbolToPubConList()) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!AddPubConListByte(bFloat ? 17 : 16)) |
|||
{ |
|||
return false; |
|||
} |
|||
int temp = value; |
|||
for (int i = 0; i < 4; i++) |
|||
{ |
|||
if (!AddPubConListByte(temp & 0xFF)) |
|||
{ |
|||
return false; |
|||
} |
|||
temp >>= 8; |
|||
} |
|||
|
|||
g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, bFloat ? type_con_float : type_con, value); |
|||
#ifdef RPE_DEBUG |
|||
float fValue = *((float*)(&value)); |
|||
printf("%s %d %f \n", g_pCompilerData->symbolBackup, value, fValue); |
|||
#endif |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool HandleConSymbol(int pass) |
|||
{ |
|||
// symbol
|
|||
g_pCompilerData->inf_start = g_pCompilerData->source_start; |
|||
g_pCompilerData->inf_finish = g_pCompilerData->source_finish; |
|||
|
|||
// save a copy of the symbol
|
|||
g_pElementizer->BackupSymbol(); |
|||
|
|||
bool bFloat = false; |
|||
|
|||
bool bEof = false; |
|||
g_pElementizer->GetNext(bEof); |
|||
if (g_pElementizer->GetType() == type_equal) |
|||
{ |
|||
// equal
|
|||
if (!GetTryValue(pass == 1 ? true : false, false)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pCompilerData->intMode == 2) |
|||
{ |
|||
bFloat = true; |
|||
} |
|||
if (g_pCompilerData->bUndefined == false) |
|||
{ |
|||
if (!ConAssign(bFloat, GetResult())) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
else if (g_pElementizer->GetType() == type_leftb) |
|||
{ |
|||
// enumx
|
|||
if (!GetTryValue(pass == 1 ? true : false, true)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (!g_pElementizer->GetElement(type_rightb)) |
|||
{ |
|||
return false; |
|||
} |
|||
if (g_pCompilerData->bUndefined == false) |
|||
{ |
|||
if (g_pCompilerData->enum_valid == 1) |
|||
{ |
|||
int temp = g_pCompilerData->enum_value; |
|||
g_pCompilerData->enum_value = GetResult() + temp; |
|||
|
|||
if (!ConAssign(bFloat, temp)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->enum_valid = 0; |
|||
} |
|||
} |
|||
else if ((g_pElementizer->GetType() == type_comma) || |
|||
(g_pElementizer->GetType() == type_end)) |
|||
{ |
|||
// enuma
|
|||
g_pElementizer->Backup(); |
|||
if (g_pCompilerData->enum_valid == 1) |
|||
{ |
|||
int temp = g_pCompilerData->enum_value; |
|||
g_pCompilerData->enum_value = 1 + temp; |
|||
|
|||
if (!ConAssign(bFloat, temp)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
g_pCompilerData->error = true; |
|||
g_pCompilerData->error_msg = g_pErrorStrings[error_eelcoeol]; |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
#define WORD_LENGTH (8 * sizeof(value)) |
|||
int rol(unsigned int value, int places) |
|||
{ |
|||
return (value << places) | (value >> (WORD_LENGTH - places)); |
|||
} |
|||
|
|||
int ror(unsigned int value, int places) |
|||
{ |
|||
return (value >> places) | (value << (WORD_LENGTH - places)); |
|||
} |
|||
#undef WORD_LENGTH |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,319 @@ |
|||
//////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// 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. //
|
|||
// //
|
|||
//////////////////////////////////////////////////////////////
|
|||
//
|
|||
// Utilities.h
|
|||
//
|
|||
|
|||
#ifndef _UTILITIES_H_ |
|||
#define _UTILITIES_H_ |
|||
|
|||
extern void SetPrint(char* pDestination, int limit); |
|||
extern bool PrintChr(char theChar); |
|||
extern bool PrintString(const char* theString); |
|||
extern bool PrintLong(int value); |
|||
extern bool PrintWord(short value); |
|||
extern bool PrintByte(char value); |
|||
extern bool PrintHex(char value); |
|||
extern bool PrintDecimal(int value); |
|||
extern bool PrintSymbol(const char* pSymbolName, unsigned char type, int value, int value_2); |
|||
extern bool PrintObj(); |
|||
extern bool DocPrint(char theChar); |
|||
|
|||
extern char Uppercase(char theChar); |
|||
|
|||
extern bool CheckWordChar(char theChar); |
|||
extern bool CheckHex(char theChar, char& digitValue); |
|||
extern bool CheckDigit(char theChar, char& digitValue, char numberBase); |
|||
extern bool CheckPlus(char theChar); |
|||
extern bool CheckLocal(bool& bLocal); |
|||
|
|||
extern bool GetFloat(char* pSource, int& sourceOffset, int& value); |
|||
extern bool GetSymbol(int* length); |
|||
extern bool GetObjSymbol(int type, char id); |
|||
|
|||
extern bool GetCommaOrEnd(bool& bComma); |
|||
extern bool GetCommaOrRight(bool& bComma); |
|||
extern bool GetPipeOrEnd(bool& bPipe); |
|||
|
|||
extern bool GetFilename(int& filenameStart, int& filenameFinish); |
|||
|
|||
extern void EnterInfo(); |
|||
extern bool EnterObj(unsigned char value); |
|||
extern bool EnterObjLong(int value); |
|||
|
|||
extern bool IncrementAsmLocal(); |
|||
|
|||
extern bool AddFileName(int& fileCount, int& fileIndex, char* pFilenames, int* pNameStart, int* pNameFinish, int error); |
|||
extern bool AddPubConListByte(char value); |
|||
extern bool AddSymbolToPubConList(); |
|||
extern bool ConAssign(bool bFloat, int value); |
|||
extern bool HandleConSymbol(int pass); |
|||
|
|||
extern int rol(unsigned int value, int places); |
|||
extern int ror(unsigned int value, int places); |
|||
|
|||
// these is in ExpressionResolver.cpp
|
|||
extern bool GetTryValue(bool bMustResolve, bool bInteger, bool bOperandMode = false); |
|||
extern int GetResult(); |
|||
|
|||
//
|
|||
// Simple Hash Table (used by the Symbol Engine)
|
|||
//
|
|||
|
|||
class Hashable |
|||
{ |
|||
public: |
|||
virtual ~Hashable() |
|||
{ |
|||
} |
|||
}; |
|||
|
|||
struct HashNode |
|||
{ |
|||
int key; |
|||
Hashable* pValue; |
|||
HashNode* pNext; |
|||
HashNode* pNextList; |
|||
|
|||
~HashNode() |
|||
{ |
|||
if (pNext) |
|||
{ |
|||
delete pNext; |
|||
} |
|||
delete pValue; |
|||
} |
|||
}; |
|||
|
|||
class HashTable |
|||
{ |
|||
private: |
|||
HashNode** m_pTable; |
|||
int m_tableSize; |
|||
HashNode* m_pListHead; |
|||
HashNode* m_pListTail; |
|||
|
|||
public: |
|||
HashTable(int tableSize) |
|||
: m_tableSize(tableSize) |
|||
, m_pListHead(0) |
|||
, m_pListTail(0) |
|||
{ |
|||
m_pTable = new HashNode*[tableSize]; |
|||
for(int i = 0; i < m_tableSize; i++) |
|||
{ |
|||
m_pTable[i] = 0; |
|||
} |
|||
} |
|||
~HashTable() |
|||
{ |
|||
for(int i = 0; i < m_tableSize; i++) |
|||
{ |
|||
if (m_pTable[i] != 0) |
|||
{ |
|||
delete m_pTable[i]; |
|||
m_pTable[i] = 0; |
|||
} |
|||
} |
|||
delete [] m_pTable; |
|||
m_pTable = 0; |
|||
m_pListHead = m_pListTail = 0; |
|||
} |
|||
|
|||
// insert a new node in the table with the given key and value
|
|||
void Insert(int key, Hashable* pValue) |
|||
{ |
|||
unsigned int bucket = (unsigned int)key % m_tableSize; |
|||
|
|||
HashNode* pNode = new HashNode; |
|||
pNode->key = key; |
|||
pNode->pValue = pValue; |
|||
pNode->pNext = m_pTable[bucket]; |
|||
pNode->pNextList = 0; |
|||
|
|||
m_pTable[bucket] = pNode; |
|||
|
|||
if ( m_pListTail ) |
|||
{ |
|||
m_pListTail->pNextList = pNode; |
|||
m_pListTail = pNode; |
|||
} |
|||
else |
|||
{ |
|||
m_pListHead = m_pListTail = pNode; |
|||
} |
|||
} |
|||
|
|||
HashNode* First() |
|||
{ |
|||
return m_pListHead; |
|||
} |
|||
|
|||
HashNode* Last() |
|||
{ |
|||
return m_pListTail; |
|||
} |
|||
|
|||
HashNode* Next(HashNode* pCurrent) |
|||
{ |
|||
return (pCurrent != 0) ? pCurrent->pNextList : 0; |
|||
} |
|||
|
|||
// find the first node with a matching key
|
|||
// returns 0 if not found
|
|||
HashNode* FindFirst(int key) |
|||
{ |
|||
unsigned int bucket = (unsigned int)key % m_tableSize; |
|||
if (m_pTable[bucket] != 0) |
|||
{ |
|||
HashNode* pNode = m_pTable[bucket]; |
|||
while (pNode != 0) |
|||
{ |
|||
if (pNode->key == key) |
|||
{ |
|||
return pNode; |
|||
} |
|||
pNode = pNode->pNext; |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// find the next node with a matching key
|
|||
// returns 0 if not found
|
|||
HashNode* FindNext(HashNode* pCurrent) |
|||
{ |
|||
if (pCurrent->pNext != 0 && pCurrent->pNext->key == pCurrent->key) |
|||
{ |
|||
return pCurrent->pNext; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// calculate a hash value of a zero terminated string (uppercased)
|
|||
// uses Jenkins One-at-a-time hash function
|
|||
int GetStringHashUppercase(const char* s) |
|||
{ |
|||
int hash = 0; |
|||
while (*s != 0) |
|||
{ |
|||
int c = *s; |
|||
c = c - (32 * (c >= 'a' && c <= 'z')); |
|||
hash += c; |
|||
hash += (hash << 10); |
|||
hash ^= (hash >> 6); |
|||
s++; |
|||
} |
|||
hash += (hash << 3); |
|||
hash ^= (hash >> 11); |
|||
hash += (hash << 15); |
|||
return hash; |
|||
} |
|||
|
|||
// calculate a hash value of a zero terminated string
|
|||
// uses Jenkins One-at-a-time hash function
|
|||
int GetStringHash(const char* s) |
|||
{ |
|||
int hash = 0; |
|||
while (*s != 0) |
|||
{ |
|||
hash += *s; |
|||
hash += (hash << 10); |
|||
hash ^= (hash >> 6); |
|||
s++; |
|||
} |
|||
hash += (hash << 3); |
|||
hash ^= (hash >> 11); |
|||
hash += (hash << 15); |
|||
return hash; |
|||
} |
|||
}; |
|||
|
|||
|
|||
class HeirarchyNode |
|||
{ |
|||
public: |
|||
HeirarchyNode* m_pNextSibling; |
|||
HeirarchyNode* m_pParent; |
|||
|
|||
HeirarchyNode() |
|||
: m_pNextSibling(0) |
|||
, m_pParent(0) |
|||
{ |
|||
} |
|||
|
|||
~HeirarchyNode() |
|||
{ |
|||
if (m_pNextSibling) |
|||
{ |
|||
delete m_pNextSibling; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
class Heirarchy |
|||
{ |
|||
public: |
|||
HeirarchyNode* m_pRoot; |
|||
|
|||
Heirarchy() |
|||
: m_pRoot(0) |
|||
{ |
|||
} |
|||
~Heirarchy() |
|||
{ |
|||
delete m_pRoot; |
|||
} |
|||
|
|||
void AddNode(HeirarchyNode* pValue, HeirarchyNode* pParent) |
|||
{ |
|||
if (m_pRoot == 0) |
|||
{ |
|||
m_pRoot = pValue; |
|||
} |
|||
else |
|||
{ |
|||
if (pParent) |
|||
{ |
|||
pValue->m_pNextSibling = pParent->m_pNextSibling; |
|||
pParent->m_pNextSibling = pValue; |
|||
} |
|||
else |
|||
{ |
|||
pValue->m_pNextSibling = m_pRoot->m_pNextSibling; |
|||
m_pRoot->m_pNextSibling = pValue; |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
#endif // _UTILITIES_H_
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,128 @@ |
|||
/*
|
|||
* Functions for manipulating variable sized memory buffers. |
|||
* These buffers can grow and shrink as the program progresses. |
|||
* |
|||
* Written by Eric R. Smith |
|||
* Copyright (c) 2012 Total Spectrum Software Inc. |
|||
* MIT Licensed; see terms at the end of this file. |
|||
*/ |
|||
|
|||
#include "flexbuf.h" |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
|
|||
#define DEFAULT_GROWSIZE BUFSIZ |
|||
|
|||
void flexbuf_init(struct flexbuf *fb, size_t growsize) |
|||
{ |
|||
fb->data = NULL; |
|||
fb->len = 0; |
|||
fb->space = 0; |
|||
fb->growsize = growsize ? growsize : DEFAULT_GROWSIZE; |
|||
} |
|||
|
|||
size_t flexbuf_curlen(struct flexbuf *fb) |
|||
{ |
|||
return fb->len; |
|||
} |
|||
|
|||
/* add a single character to a buffer */ |
|||
char *flexbuf_addchar(struct flexbuf *fb, int c) |
|||
{ |
|||
size_t newlen = fb->len + 1; |
|||
|
|||
if (newlen > fb->space) { |
|||
char *newdata; |
|||
newdata = (char *)realloc(fb->data, fb->space + fb->growsize); |
|||
if (!newdata) return newdata; |
|||
fb->space += fb->growsize; |
|||
fb->data = newdata; |
|||
} |
|||
fb->data[fb->len] = (char)c; |
|||
fb->len = newlen; |
|||
return fb->data; |
|||
} |
|||
|
|||
/* add N characters to a buffer */ |
|||
char *flexbuf_addmem(struct flexbuf *fb, const char *buf, size_t N) |
|||
{ |
|||
size_t newlen = fb->len + N; |
|||
|
|||
if (newlen > fb->space) { |
|||
char *newdata; |
|||
size_t newspace; |
|||
newspace = fb->space + fb->growsize; |
|||
if (newspace < newlen) { |
|||
newspace = newlen + fb->growsize; |
|||
} |
|||
newdata = (char *)realloc(fb->data, newspace); |
|||
if (!newdata) return newdata; |
|||
fb->space = newspace; |
|||
fb->data = newdata; |
|||
} |
|||
memcpy(fb->data + fb->len, buf, N); |
|||
fb->len = newlen; |
|||
return fb->data; |
|||
} |
|||
|
|||
/* add a string to a buffer */ |
|||
char *flexbuf_addstr(struct flexbuf *fb, const char *str) |
|||
{ |
|||
return flexbuf_addmem(fb, str, strlen(str)); |
|||
} |
|||
|
|||
/* retrieve the pointer for a flexbuf */ |
|||
/* "peek" gets it but keeps it reserved;
|
|||
* "get" gets it and releases it from the flexbuf |
|||
*/ |
|||
char *flexbuf_peek(struct flexbuf *fb) |
|||
{ |
|||
char *r = fb->data; |
|||
return r; |
|||
} |
|||
|
|||
char *flexbuf_get(struct flexbuf *fb) |
|||
{ |
|||
char *r = fb->data; |
|||
flexbuf_init(fb, fb->growsize); |
|||
return r; |
|||
} |
|||
|
|||
/* reset the buffer to empty (but do not free space) */ |
|||
void flexbuf_clear(struct flexbuf *fb) |
|||
{ |
|||
fb->len = 0; |
|||
} |
|||
|
|||
/* free the memory associated with a buffer */ |
|||
void flexbuf_delete(struct flexbuf *fb) |
|||
{ |
|||
if (fb->data) |
|||
free(fb->data); |
|||
flexbuf_init(fb, 1); |
|||
} |
|||
|
|||
/*
|
|||
* +-------------------------------------------------------------------- |
|||
* ¦ 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. |
|||
* +-------------------------------------------------------------------- |
|||
*/ |
|||
@ -0,0 +1,49 @@ |
|||
/*
|
|||
* Functions for manipulating variable sized memory buffers. |
|||
* These buffers can grow and shrink as the program progresses. |
|||
* |
|||
* Written by Eric R. Smith |
|||
* Copyright (c) 2012 Total Spectrum Software Inc. |
|||
* See terms of use in flexbuf.c |
|||
*/ |
|||
|
|||
#ifndef FLEXBUF_H_ |
|||
#define FLEXBUF_H_ |
|||
#include <string.h> |
|||
|
|||
struct flexbuf { |
|||
char * data; /* current data */ |
|||
size_t len; /* current length of valid data */ |
|||
size_t space; /* total space available (must be >= len) */ |
|||
size_t growsize; /* how much we should grow */ |
|||
}; |
|||
|
|||
/* initialize a buffer */ |
|||
void flexbuf_init(struct flexbuf *fb, size_t growsize); |
|||
|
|||
/* add a single character to a buffer */ |
|||
/* returns a pointer to the start of the buffer, or NULL on failure */ |
|||
char *flexbuf_addchar(struct flexbuf *fb, int c); |
|||
|
|||
/* add N characters to a buffer */ |
|||
char *flexbuf_addmem(struct flexbuf *fb, const char *buf, size_t N); |
|||
|
|||
/* add a string to a buffer */ |
|||
char *flexbuf_addstr(struct flexbuf *fb, const char *str); |
|||
|
|||
/* reset the buffer to empty */ |
|||
void flexbuf_clear(struct flexbuf *fb); |
|||
|
|||
/* harvest the flexible buffer pointer for use elsewhere */ |
|||
char *flexbuf_get(struct flexbuf *fb); |
|||
|
|||
/* like get, but does not release the buffer */ |
|||
char *flexbuf_peek(struct flexbuf *fb); |
|||
|
|||
/* free the space associated with a buffer */ |
|||
void flexbuf_delete(struct flexbuf *fb); |
|||
|
|||
/* find current length of a buffer */ |
|||
size_t flexbuf_curlen(struct flexbuf *fb); |
|||
|
|||
#endif |
|||
@ -0,0 +1,118 @@ |
|||
///////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
|
|||
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|||
// Adapted from Jeff Martin's Delphi code by Roy Eltham //
|
|||
// See end of file for terms of use. //
|
|||
// //
|
|||
///////////////////////////////////////////////////////////////
|
|||
//
|
|||
// objectheap.cpp
|
|||
//
|
|||
#include <string.h> |
|||
|
|||
#include "PropellerCompiler.h" |
|||
#include "objectheap.h" |
|||
|
|||
// Object heap (compile-time objects)
|
|||
struct ObjHeap |
|||
{ |
|||
char* ObjFilename; // Full filename of object
|
|||
char* Obj; // Object binary
|
|||
int ObjSize; // Size of object
|
|||
}; |
|||
|
|||
ObjHeap s_ObjHeap[MaxObjInHeap]; |
|||
int s_nObjHeapIndex = 0; |
|||
|
|||
bool AddObjectToHeap(char* name, CompilerData* pCompilerData) |
|||
{ |
|||
// see if it already exists in the heap
|
|||
if (IndexOfObjectInHeap(name) != -1) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
// add the object to the heap
|
|||
if (s_nObjHeapIndex < MaxObjInHeap) |
|||
{ |
|||
int nNameBufferLength = (int)strlen(name)+1; |
|||
s_ObjHeap[s_nObjHeapIndex].ObjFilename = new char[nNameBufferLength]; |
|||
strcpy(s_ObjHeap[s_nObjHeapIndex].ObjFilename, name); |
|||
s_ObjHeap[s_nObjHeapIndex].ObjSize = pCompilerData->obj_ptr; |
|||
s_ObjHeap[s_nObjHeapIndex].Obj = new char[pCompilerData->obj_ptr]; |
|||
memcpy(s_ObjHeap[s_nObjHeapIndex].Obj, &(pCompilerData->obj[0]), pCompilerData->obj_ptr); |
|||
s_nObjHeapIndex++; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
// Returns index of object of Name in Object Heap. Returns -1 if not found.
|
|||
int IndexOfObjectInHeap(char* name) |
|||
{ |
|||
for (int i = s_nObjHeapIndex-1; i >= 0; i--) |
|||
{ |
|||
if (_stricmp(s_ObjHeap[i].ObjFilename, name) == 0) |
|||
{ |
|||
return i; |
|||
} |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
void CleanObjectHeap() |
|||
{ |
|||
for (int i = 0; i < s_nObjHeapIndex; i++) |
|||
{ |
|||
delete [] s_ObjHeap[i].ObjFilename; |
|||
s_ObjHeap[i].ObjFilename = NULL; |
|||
delete [] s_ObjHeap[i].Obj; |
|||
s_ObjHeap[i].Obj = NULL; |
|||
s_ObjHeap[i].ObjSize = 0; |
|||
} |
|||
s_nObjHeapIndex = 0; |
|||
} |
|||
|
|||
bool CopyObjectsFromHeap(CompilerData* pCompilerData, char* filenames) |
|||
{ |
|||
// load sub-objects from heap into obj_data for Compile2()
|
|||
int p = 0; |
|||
for (int i = 0; i < pCompilerData->obj_files; i++) |
|||
{ |
|||
int nObjIdx = IndexOfObjectInHeap(&filenames[i<<8]); |
|||
if (p + s_ObjHeap[nObjIdx].ObjSize > data_limit) |
|||
{ |
|||
return false; |
|||
} |
|||
memcpy(&pCompilerData->obj_data[p], s_ObjHeap[nObjIdx].Obj, s_ObjHeap[nObjIdx].ObjSize); |
|||
pCompilerData->obj_offsets[i] = p; |
|||
pCompilerData->obj_lengths[i] = s_ObjHeap[nObjIdx].ObjSize; |
|||
p += s_ObjHeap[nObjIdx].ObjSize; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,44 @@ |
|||
///////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
|
|||
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|||
// Adapted from Jeff Martin's Delphi code by Roy Eltham //
|
|||
// See end of file for terms of use. //
|
|||
// //
|
|||
///////////////////////////////////////////////////////////////
|
|||
//
|
|||
// objectheap.h
|
|||
//
|
|||
|
|||
#ifndef _OBJECTHEAP_H_ |
|||
#define _OBJECTHEAP_H_ |
|||
|
|||
#define MaxObjInHeap 256 |
|||
|
|||
bool AddObjectToHeap(char* name, CompilerData* pCompilerData); |
|||
int IndexOfObjectInHeap(char* name); |
|||
void CleanObjectHeap(); |
|||
bool CopyObjectsFromHeap(CompilerData* pCompilerData, char* filenames); |
|||
|
|||
#endif // _OBJECTHEAP_H_
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
File diff suppressed because it is too large
@ -0,0 +1,115 @@ |
|||
#ifndef PREPROCESS_H_ |
|||
#define PREPROCESS_H_ |
|||
|
|||
#include <string.h> |
|||
#include "flexbuf.h" |
|||
|
|||
struct predef |
|||
{ |
|||
struct predef *next; |
|||
const char *name; |
|||
const char *def; |
|||
int flags; |
|||
}; |
|||
#define PREDEF_FLAG_FREEDEFS 0x01 /* if "name" and "def" should be freed */ |
|||
|
|||
|
|||
#define MODE_UNKNOWN 0 |
|||
#define MODE_UTF8 1 |
|||
#define MODE_UTF16 2 |
|||
|
|||
typedef char* (*PreprocessLoadFileFunc)(const char* pFilename, int* pnLength, char** ppFilePath); |
|||
typedef void (*PreprocessFreeFileBufferFunc)(char* buffer); |
|||
|
|||
struct memoryfile |
|||
{ |
|||
char* buffer; |
|||
int length; |
|||
int readoffset; |
|||
char* filepath; |
|||
}; |
|||
|
|||
struct filestate |
|||
{ |
|||
struct filestate *next; |
|||
memoryfile *f; |
|||
const char *name; |
|||
int lineno; |
|||
int (*readfunc)(memoryfile *f, char *buf); |
|||
int flags; |
|||
}; |
|||
#define FILE_FLAGS_CLOSEFILE 0x01 |
|||
|
|||
struct ifstate |
|||
{ |
|||
struct ifstate *next; |
|||
int skip; /* if we are currently skipping code */ |
|||
const char *name; /* the name of the file it started in */ |
|||
int linenum; /* the line number it started on */ |
|||
int skiprest; /* if we have already processed some branch */ |
|||
int sawelse; /* if we have already processed a #else */ |
|||
}; |
|||
|
|||
struct preprocess |
|||
{ |
|||
struct filestate *fil; |
|||
struct flexbuf line; |
|||
struct flexbuf whole; |
|||
struct predef *defs; |
|||
|
|||
struct ifstate *ifs; |
|||
|
|||
/* comment handling code */ |
|||
const char *linecomment; |
|||
const char *startcomment; |
|||
const char *endcomment; |
|||
|
|||
int incomment; |
|||
|
|||
/* error handling code */ |
|||
void (*messagefunc)(const char *level, const char *filename, int linenum, const char *msg); |
|||
|
|||
bool alternate; /* flag to enable alternate preprocessor rules - */ |
|||
/* affects #error handling, macro substitution of */ |
|||
/* symbols that are "defined" but have no value. */ |
|||
}; |
|||
|
|||
#define pp_active(pp) (!((pp)->ifs && (pp)->ifs->skip)) |
|||
|
|||
void pp_setFileFunctions(PreprocessLoadFileFunc pLoadFileFunc, PreprocessFreeFileBufferFunc pFreeFileBufferFunc); |
|||
|
|||
/* initialize for reading */ |
|||
void pp_init(struct preprocess *pp, bool alternate); |
|||
|
|||
/* push an opened FILE struct */ |
|||
void pp_push_file_struct(struct preprocess *pp, memoryfile *f, const char *name); |
|||
|
|||
/* push a file by name */ |
|||
void pp_push_file(struct preprocess *pp, const char *filename); |
|||
|
|||
/* pop a file (finish processing it) */ |
|||
void pp_pop_file(struct preprocess *pp); |
|||
|
|||
/* set the strings that will be recognized to start line comments and start and end
|
|||
multi-line comments; these nest */ |
|||
void pp_setcomments(struct preprocess *pp, const char *line, const char *s, const char *e); |
|||
|
|||
/* define symbol "name" to have "val", or undefine it if val is NULL */ |
|||
void pp_define(struct preprocess *pp, const char *name, const char *val); |
|||
|
|||
/* get the current state of the define stack */ |
|||
void *pp_get_define_state(struct preprocess *pp); |
|||
|
|||
/* restore the define state to the state given by a previous call to get_define_state */ |
|||
void pp_restore_define_state(struct preprocess *pp, void *ptr); |
|||
|
|||
/* clear all the define state */ |
|||
void pp_clear_define_state(struct preprocess *pp); |
|||
|
|||
/* actually perform the preprocessing on all files that have been pushed so far */ |
|||
void pp_run(struct preprocess *pp); |
|||
|
|||
/* finish preprocessing and retrieve the result string */ |
|||
char *pp_finish(struct preprocess *pp); |
|||
|
|||
#endif |
|||
@ -0,0 +1,284 @@ |
|||
///////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
|
|||
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|||
// See end of file for terms of use. //
|
|||
// //
|
|||
///////////////////////////////////////////////////////////////
|
|||
//
|
|||
// textconvert.h
|
|||
//
|
|||
|
|||
unsigned int DecodeUtf8(const char* pBuffer, int& nCharSize) |
|||
{ |
|||
unsigned int nChar = (unsigned int)((unsigned char)(*pBuffer)); |
|||
if (nChar < 128) |
|||
{ |
|||
nCharSize = 1; |
|||
} |
|||
else if (nChar >= 192 && nChar <= 223) |
|||
{ |
|||
// character is two bytes
|
|||
nCharSize = 2; |
|||
nChar = ((nChar & 31) << 6) | ((unsigned int)pBuffer[1] & 63); |
|||
} |
|||
else if (nChar >= 224 && nChar <= 239) |
|||
{ |
|||
// character is three bytes
|
|||
nCharSize = 3; |
|||
nChar = ((nChar & 15) << 12) | (((unsigned int)pBuffer[1] & 63) << 6) | ((unsigned int)pBuffer[2] & 63); |
|||
} |
|||
else if (nChar >= 240 && nChar <= 247) |
|||
{ |
|||
// character is four bytes
|
|||
nCharSize = 4; |
|||
nChar = ((nChar & 7) << 18) | (((unsigned int)pBuffer[1] & 63) << 12) | (((unsigned int)pBuffer[2] & 63) << 6) | ((unsigned int)pBuffer[3] & 63); |
|||
} |
|||
else if (nChar >= 248 && nChar <= 251) |
|||
{ |
|||
// character is five bytes
|
|||
nCharSize = 5; |
|||
nChar = ((nChar & 3) << 24) | (((unsigned int)pBuffer[1] & 63) << 18) | (((unsigned int)pBuffer[2] & 63) << 12) | (((unsigned int)pBuffer[3] & 63) << 6) | ((unsigned int)pBuffer[4] & 63); |
|||
} |
|||
else if (nChar >= 252 && nChar <= 253) |
|||
{ |
|||
// character is six bytes
|
|||
nCharSize = 6; |
|||
nChar = ((nChar & 1) << 30) | (((unsigned int)pBuffer[1] & 63) << 24) | (((unsigned int)pBuffer[2] & 63) << 18) | (((unsigned int)pBuffer[3] & 63) << 12) | (((unsigned int)pBuffer[4] & 63) << 6) | ((unsigned int)pBuffer[5] & 63); |
|||
} |
|||
|
|||
return nChar; |
|||
} |
|||
|
|||
|
|||
static unsigned short s_aConvertTable[] = { |
|||
0x0000, 0x0000, 0x2190, 0x2192, 0x2191, 0x2193,0x25C0, 0x25B6, 0x0000, 0x0009, 0x000A, 0x0000, 0x0000, 0x000D, 0x2023, 0x2022, |
|||
0x0394, 0x03C0, 0x03A3, 0x03A9, 0x2248, 0x221A,0xF016, 0xF017, 0xF018, 0xF019, 0xF01A, 0xF01B, 0xF01C, 0xF01D, 0xF01E, 0xF01F, |
|||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025,0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, |
|||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, |
|||
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045,0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, |
|||
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055,0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, |
|||
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065,0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, |
|||
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075,0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0xF07F, |
|||
0xF080, 0xF081, 0xF082, 0xF083, 0xF084, 0xF085,0xF086, 0xF087, 0xF088, 0xF089, 0xF08A, 0xF08B, 0xF08C, 0xF08D, 0xF08E, 0xF08F, |
|||
0x2500, 0x2502, 0x253C, 0x254B, 0x2524, 0x251C,0x2534, 0x252C, 0x252B, 0x2523, 0x253B, 0x2533, 0x2518, 0x2514, 0x2510, 0x250C, |
|||
0xF0A0, 0x00A1, 0xF0A2, 0x00A3, 0x20AC, 0x00A5,0xF0A6, 0xF0A7, 0xF0A8, 0xF0A9, 0xF0AA, 0xF0AB, 0xF0AC, 0xF0AD, 0xF0AE, 0xF0AF, |
|||
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0xF0B4, 0x00B5,0xF0B6, 0xF0B7, 0xF0B8, 0x00B9, 0xF0BA, 0xF0BB, 0xF0BC, 0xF0BD, 0xF0BE, 0x00BF, |
|||
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5,0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, |
|||
0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5,0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, |
|||
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5,0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, |
|||
0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5,0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x221E |
|||
}; |
|||
|
|||
|
|||
void PASCIIToUnicode16(char* pPASCIIBuffer, int nPASCIIBufferLength, unsigned short* pUnicode16Buffer) |
|||
{ |
|||
for (int i = 0; i < nPASCIIBufferLength; i++) |
|||
{ |
|||
pUnicode16Buffer[i] = s_aConvertTable[(int)pPASCIIBuffer[i]]; |
|||
} |
|||
} |
|||
|
|||
|
|||
/*
|
|||
The Parallax font v1.0 utilizes the following Unicode addresses (grouped here into similar ranges): |
|||
$0020- $007E, $00A1, $00A3, $00A5, $00B0- $00B3, $00B5, $00B9, $00BF- $00FE, |
|||
$0394, $03A3, $03A9, $03C0, |
|||
$2022, $2023, $20AC, |
|||
$2190- $2193, |
|||
$221A, $221E, $2248, |
|||
$25B6, $2500, $2502, $250C, $2510, $2514, $2518, $251C, $2523, $2524, $252B, $252C, $2533, $2534, $253B, $253C, $254B, $25C0, |
|||
$F000, $F001, $F008- $F00D, $F016- $F01F, $F07F- $F08F, $F0A0, $F0A2, $F0A6- $F0AF, $F0B4, $F0B6- $F0B8, $F0BA- $F0BE |
|||
Propeller source files are sometimes Unicode-encoded (UTF-16) and can contain only the supported Parallax font characters with the following |
|||
exceptions: 1) Run-time only characters ($F000, $F001, $F008-$F00D) are not valid |
|||
2) Some control code characters ($0009, $0010, $000D) are allowed. |
|||
Any invalid characters will be translated to the PASCII infinity character ($00FF). |
|||
All others will be mapped to their corresponding PASCII character. |
|||
NOTE: The speediest translation would be a simple lookup table, but the natural size would be impractical. |
|||
A little math solves this problem: |
|||
ANDing the unicode character value with $07FF yields a range of $0000 to $07FF but causes the 20xx characters to inappropriately |
|||
collide with other valid values. ANDing with $07FF then ORing with ((CharVal >> 5) AND NOT(CharVal >> 4) AND $0100) corrects |
|||
this by mapping 20xx into 21xx space and 22xx characters into 23xx space. This allows for a practical translation table |
|||
(of 2K bytes) to be used. |
|||
*/ |
|||
static unsigned char s_aCharTxMap[0x800] = { |
|||
// 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F
|
|||
/*000*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x09, 0x0A, 0xff, 0xff, 0x0D, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, |
|||
/*020*/ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, |
|||
/*040*/ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, |
|||
/*060*/ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, |
|||
/*080*/ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*0A0*/ 0xA0, 0xA1, 0xA2, 0xA3, 0xff, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, |
|||
/*0C0*/ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, |
|||
/*0E0*/ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xff, |
|||
/*100*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*120*/ 0xff, 0xff, 0x0F, 0x0E, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*140*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*160*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*180*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x04, 0x03, 0x05, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*1A0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xA4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*1C0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*1E0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*200*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*220*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*240*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*260*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*280*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*2A0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*2C0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*2E0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*300*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0xff, 0xff, 0xff, 0xFF, 0xff, |
|||
/*320*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*340*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*360*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*380*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*3A0*/ 0xff, 0xff, 0xff, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*3C0*/ 0x11, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*3E0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*400*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*420*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*440*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*460*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*480*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*4A0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*4C0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*4E0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*500*/ 0x90, 0xff, 0x91, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9F, 0xff, 0xff, 0xff, 0x9E, 0xff, 0xff, 0xff, 0x9D, 0xff, 0xff, 0xff, 0x9C, 0xff, 0xff, 0xff, 0x95, 0xff, 0xff, 0xff, |
|||
/*520*/ 0xff, 0xff, 0xff, 0x99, 0x94, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x98, 0x97, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9B, 0x96, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9A, 0x92, 0xff, 0xff, 0xff, |
|||
/*540*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x93, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*560*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*580*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*5A0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*5C0*/ 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*5E0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*600*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*620*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*640*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*660*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*680*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*6A0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*6C0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*6E0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*700*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*720*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*740*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*760*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*780*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*7A0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*7C0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
/*7E0*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff |
|||
}; |
|||
|
|||
bool UnicodeToPASCII(char* pBuffer, int nBufferLength, char* pPASCIIBuffer, bool bForceUTF8) |
|||
{ |
|||
// Translate Unicode source to PASCII (Parallax ASCII) source
|
|||
|
|||
// detect Unicode or ASCII form
|
|||
bool bUnicode = false; |
|||
bool bUtf8 = false; |
|||
if (bForceUTF8) |
|||
{ |
|||
// preprocessor outputs utf8 encoded data, so just force it
|
|||
bUnicode = true; |
|||
bUtf8 = true; |
|||
} |
|||
else if (*((short*)(&pBuffer[0])) == -257) // -257 == 0xFEFF which is the UTF-16 BOM character for Little Endian
|
|||
{ |
|||
bUnicode = true; |
|||
} |
|||
else if (*((short*)(&pBuffer[0])) == -2) // -2 == 0xFFFE which is the UTF-16 BOM character for Big Endian
|
|||
{ |
|||
// we don't handle this encoding format
|
|||
return false; |
|||
} |
|||
else if (nBufferLength > 2 && pBuffer[1] == 0) // this attempts to handle the case of a UTF-16 encoded file without a BOM character. It assumes the first character is < 255, thus the second byte is 0
|
|||
{ |
|||
bUnicode = true; |
|||
} |
|||
else if (nBufferLength > 2 && (unsigned char)pBuffer[0] == 239 && (unsigned char)pBuffer[1] == 187 && (unsigned char)pBuffer[2] == 191) // handle the UTF-8 BOM sequence case
|
|||
{ |
|||
bUnicode = true; |
|||
bUtf8 = true; |
|||
} |
|||
|
|||
// probably need to add a way to detect utf-8 without a BOM character (need to scan file and see if it's all valid utf-8 form
|
|||
|
|||
// the compiler code expects 0x0D line endings, this code will strip out 0x0A from the line endings and put in 0x0D if they are not there.
|
|||
if (bUnicode) |
|||
{ |
|||
// unicode, copy over translating line endings
|
|||
int nSourceOffset = 0; |
|||
int nDestOffset = 0; |
|||
unsigned short nPrevChar = 0; |
|||
while (nSourceOffset < nBufferLength) |
|||
{ |
|||
int nCharSize = 2; |
|||
unsigned short nChar = (bUtf8 == true) ? (unsigned short)DecodeUtf8(&pBuffer[nSourceOffset], nCharSize) : *((unsigned short*)(&pBuffer[nSourceOffset])); |
|||
if (nChar != 0x000A && nChar != 0xFEFF) // -257 == 0xFEFF
|
|||
{ |
|||
pPASCIIBuffer[nDestOffset] = s_aCharTxMap[(nChar | ((nChar >> 5) & ~(nChar >> 4) & 0x0100)) & 0x07FF]; |
|||
nDestOffset++; |
|||
} |
|||
else if (nChar == 0x000A) |
|||
{ |
|||
if (nSourceOffset == 0 || nPrevChar != 0x000D) |
|||
{ |
|||
pPASCIIBuffer[nDestOffset] = 0x0D; |
|||
nDestOffset++; |
|||
} |
|||
} |
|||
nSourceOffset += nCharSize; |
|||
nPrevChar = nChar; |
|||
} |
|||
pPASCIIBuffer[nDestOffset] = 0; |
|||
} |
|||
else |
|||
{ |
|||
// ascii, copy over translating line endings
|
|||
int nSourceOffset = 0; |
|||
int nDestOffset = 0; |
|||
while (nSourceOffset < nBufferLength) |
|||
{ |
|||
char nChar = pBuffer[nSourceOffset]; |
|||
if (nChar != 0x0A) |
|||
{ |
|||
pPASCIIBuffer[nDestOffset] = nChar; |
|||
nDestOffset++; |
|||
} |
|||
else |
|||
{ |
|||
if (nSourceOffset == 0 || pBuffer[nSourceOffset-1] != 0x0D) |
|||
{ |
|||
pPASCIIBuffer[nDestOffset] = 0x0D; |
|||
nDestOffset++; |
|||
} |
|||
} |
|||
nSourceOffset++; |
|||
} |
|||
pPASCIIBuffer[nDestOffset] = 0; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,40 @@ |
|||
///////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
|
|||
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|||
// See end of file for terms of use. //
|
|||
// //
|
|||
///////////////////////////////////////////////////////////////
|
|||
//
|
|||
// textconvert.h
|
|||
//
|
|||
|
|||
#ifndef _TEXTCONVERT_H_ |
|||
#define _TEXTCONVERT_H_ |
|||
|
|||
unsigned int DecodeUtf8(const char* pBuffer, int& nCharSize); |
|||
void PASCIIToUnicode16(char* pPASCIIBuffer, int nPASCIIBufferLength, unsigned short* pUnicode16Buffer); |
|||
bool UnicodeToPASCII(char* pBuffer, int nBufferLength, char* pPASCIIBuffer, bool bForceUTF8); |
|||
|
|||
#endif // _TEXTCONVERT_H_
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,37 @@ |
|||
Introduction |
|||
============ |
|||
|
|||
OpenSpin is an open source compiler for the Spin/PASM language of the Parallax Propeller. It was ported from Chip Gracey's original x86 assembler code. The only binary differences in the output are from the corrected handling of floating point numbers (which is now IEEE compliant). |
|||
|
|||
There are solution/project files for VS 2015 & VS 2017, and there are make files for use with GCC/clang/etc. Tested on MinGW, linux, and Mac OSX. They build the PropellerCompiler library and openspin.exe. |
|||
|
|||
The code successfully compiles all of the Library files shipped with PropTool as well as all of the files available in the OBEX as of August 2012. That's approximately 1450 spin files. |
|||
|
|||
OpenSpin allows symbols to be 254 characters long (instead of 31), has unused method elimination, and supports a basic [preprocessor](https://github.com/reltham/OpenSpin/wiki/Preprocessor). |
|||
|
|||
PropellerCompiler library |
|||
------------------------- |
|||
|
|||
PropellerCompiler.cpp/h contain the interface to the compiler. Look at openspin.cpp for an example of how to work with the interface. |
|||
|
|||
openspin.exe |
|||
------------ |
|||
|
|||
openspin.exe is a command line wrapper for the compiler library. You give it a spin file and it passes it through the compiler and produces a .binary (or optional .eeprom) file with the same base name as the passed in spin file. There are several [command line options](https://github.com/reltham/OpenSpin/wiki/CommandLine) available. Run openspin.exe with no arguments to get a usage description. |
|||
|
|||
Downloads |
|||
--------- |
|||
|
|||
### Builds provided by David Zemon's TeamCity service: |
|||
Note: These are updated automatically whenever changes are submitted here, so they include changes between releases. |
|||
* [Linux x86_64](http://david.zemon.name:8111/repository/download/OpenSpin_LinuxX8664/lastSuccessful/openspin.tar.gz?guest=1) |
|||
* [Windows x86](http://david.zemon.name:8111/repository/download/OpenSpin_WindowsX86/lastSuccessful/openspin.zip?guest=1) |
|||
* [Mac OS X](http://david.zemon.name:8111/repository/download/OpenSpin_MacOsX/2548:id/openspin.tar.gz?guest-1) |
|||
* [Raspberry Pi](http://david.zemon.name:8111/repository/download/OpenSpin_RaspberryPi/lastSuccessful/openspin.tar.gz?guest=1) |
|||
|
|||
Thanks |
|||
------ |
|||
|
|||
* Thanks to Steve Denson, for the Makefile and testing on linux! |
|||
* Thanks to David Betz for testing on Mac OSX. |
|||
* Thanks to Eric Smith for providing the code and helping with integrating the preprocessor. |
|||
@ -0,0 +1,494 @@ |
|||
///////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
|
|||
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|||
// Adapted from Jeff Martin's Delphi code by Roy Eltham //
|
|||
// See end of file for terms of use. //
|
|||
// //
|
|||
///////////////////////////////////////////////////////////////
|
|||
//
|
|||
// openspin.cpp
|
|||
//
|
|||
|
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
#include "../PropellerCompiler/CompileSpin.h" |
|||
#include "pathentry.h" |
|||
|
|||
#define MAX_FILES 2048 |
|||
|
|||
static int s_nFilesAccessed = 0; |
|||
static char s_filesAccessed[MAX_FILES][PATH_MAX]; |
|||
|
|||
|
|||
static void Banner(void) |
|||
{ |
|||
fprintf(stdout, "Propeller Spin/PASM Compiler \'OpenSpin\' (c)2012-2018 Parallax Inc. DBA Parallax Semiconductor.\n"); |
|||
fprintf(stdout, "Version 1.00.81 Compiled on %s %s\n",__DATE__, __TIME__); |
|||
} |
|||
|
|||
/* Usage - display a usage message and exit */ |
|||
static void Usage(void) |
|||
{ |
|||
Banner(); |
|||
fprintf(stderr, "\
|
|||
usage: openspin\n\ |
|||
[ -h ] display this help\n\ |
|||
[ -L or -I <path> ] add a directory to the include path\n\ |
|||
[ -o <path> ] output filename\n\ |
|||
[ -b ] output binary file format\n\ |
|||
[ -e ] output eeprom file format\n\ |
|||
[ -c ] output only DAT sections\n\ |
|||
[ -d ] dump out doc mode\n\ |
|||
[ -t ] output just the object file tree\n\ |
|||
[ -f ] output a list of filenames for use in archiving\n\ |
|||
[ -q ] quiet mode (suppress banner and non-error text)\n\ |
|||
[ -v ] verbose output\n\ |
|||
[ -p ] disable the preprocessor\n\ |
|||
[ -a ] use alternative preprocessor rules\n\ |
|||
[ -D <define> ] add a define\n\ |
|||
[ -M <size> ] size of eeprom (up to 16777216 bytes)\n\ |
|||
[ -s ] dump PUB & CON symbol information for top object\n\ |
|||
[ -u ] enable unused method elimination\n\ |
|||
<name.spin> spin file to compile\n\ |
|||
\n"); |
|||
} |
|||
|
|||
FILE* OpenFileInPath(const char *name, const char *mode) |
|||
{ |
|||
const char* pTryPath = NULL; |
|||
|
|||
FILE* file = fopen(name, mode); |
|||
if (!file) |
|||
{ |
|||
PathEntry* entry = NULL; |
|||
while(!file) |
|||
{ |
|||
pTryPath = MakeNextPath(&entry, name); |
|||
if (pTryPath) |
|||
{ |
|||
file = fopen(pTryPath, mode); |
|||
if (file != NULL) |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (s_nFilesAccessed < MAX_FILES) |
|||
{ |
|||
if (!pTryPath) |
|||
{ |
|||
#ifdef WIN32 |
|||
if (_fullpath(s_filesAccessed[s_nFilesAccessed], name, PATH_MAX) == NULL) |
|||
#else |
|||
if (realpath(name, s_filesAccessed[s_nFilesAccessed]) == NULL) |
|||
#endif |
|||
{ |
|||
strcpy(s_filesAccessed[s_nFilesAccessed], name); |
|||
} |
|||
s_nFilesAccessed++; |
|||
} |
|||
else |
|||
{ |
|||
strcpy(s_filesAccessed[s_nFilesAccessed++], pTryPath); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// should never hit this, but just in case
|
|||
printf("Too many files!\n"); |
|||
exit(-2); |
|||
} |
|||
|
|||
return file; |
|||
} |
|||
|
|||
// returns NULL if the file failed to open or is 0 length
|
|||
char* LoadFile(const char* pFilename, int* pnLength, char** ppFilePath) |
|||
{ |
|||
char* pBuffer = 0; |
|||
FILE* pFile = OpenFileInPath(pFilename, "rb"); |
|||
if (pFile != NULL) |
|||
{ |
|||
// get the length of the file by seeking to the end and using ftell
|
|||
fseek(pFile, 0, SEEK_END); |
|||
*pnLength = ftell(pFile); |
|||
|
|||
if (*pnLength > 0) |
|||
{ |
|||
pBuffer = (char*)malloc(*pnLength+1); // allocate a buffer that is the size of the file plus one char
|
|||
pBuffer[*pnLength] = 0; // set the end of the buffer to 0 (null)
|
|||
|
|||
// seek back to the beginning of the file and read it in
|
|||
fseek(pFile, 0, SEEK_SET); |
|||
fread(pBuffer, 1, *pnLength, pFile); |
|||
} |
|||
|
|||
fclose(pFile); |
|||
|
|||
*ppFilePath = &(s_filesAccessed[s_nFilesAccessed-1][0]); |
|||
} |
|||
else |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
return pBuffer; |
|||
} |
|||
|
|||
void FreeFileBuffer(char* pBuffer) |
|||
{ |
|||
if (pBuffer != 0) |
|||
{ |
|||
free(pBuffer); |
|||
} |
|||
} |
|||
|
|||
int main(int argc, char* argv[]) |
|||
{ |
|||
CompilerConfig compilerConfig; |
|||
|
|||
char* infile = NULL; |
|||
char* outfile = NULL; |
|||
char* p = NULL; |
|||
s_nFilesAccessed = 0; |
|||
|
|||
// go through the command line arguments, skipping over any -D
|
|||
for(int i = 1; i < argc; i++) |
|||
{ |
|||
// handle switches
|
|||
if(argv[i][0] == '-') |
|||
{ |
|||
switch(argv[i][1]) |
|||
{ |
|||
case 'I': |
|||
case 'L': |
|||
if(argv[i][2]) |
|||
{ |
|||
p = &argv[i][2]; |
|||
} |
|||
else if(++i < argc) |
|||
{ |
|||
p = argv[i]; |
|||
} |
|||
else |
|||
{ |
|||
Usage(); |
|||
CleanupPathEntries(); |
|||
return 1; |
|||
} |
|||
AddPath(p); |
|||
break; |
|||
|
|||
case 'M': |
|||
if (argv[i][2]) |
|||
{ |
|||
p = &argv[i][2]; |
|||
} |
|||
else if(++i < argc) |
|||
{ |
|||
p = argv[i]; |
|||
} |
|||
else |
|||
{ |
|||
Usage(); |
|||
CleanupPathEntries(); |
|||
return 1; |
|||
} |
|||
sscanf(p, "%d", &(compilerConfig.eeprom_size)); |
|||
if (compilerConfig.eeprom_size > 16777216) |
|||
{ |
|||
Usage(); |
|||
CleanupPathEntries(); |
|||
return 1; |
|||
} |
|||
break; |
|||
|
|||
case 'o': |
|||
if(argv[i][2]) |
|||
{ |
|||
outfile = &argv[i][2]; |
|||
} |
|||
else if(++i < argc) |
|||
{ |
|||
outfile = argv[i]; |
|||
} |
|||
else |
|||
{ |
|||
Usage(); |
|||
CleanupPathEntries(); |
|||
return 1; |
|||
} |
|||
break; |
|||
|
|||
case 'p': |
|||
compilerConfig.bUsePreprocessor = false; |
|||
break; |
|||
|
|||
case 'a': |
|||
compilerConfig.bAlternatePreprocessorMode = true; |
|||
break; |
|||
|
|||
case 'D': |
|||
if (compilerConfig.bUsePreprocessor) |
|||
{ |
|||
if (argv[i][2]) |
|||
{ |
|||
p = &argv[i][2]; |
|||
} |
|||
else if(++i < argc) |
|||
{ |
|||
p = argv[i]; |
|||
} |
|||
else |
|||
{ |
|||
Usage(); |
|||
CleanupPathEntries(); |
|||
return 1; |
|||
} |
|||
// just skipping these for now
|
|||
} |
|||
else |
|||
{ |
|||
Usage(); |
|||
CleanupPathEntries(); |
|||
return 1; |
|||
} |
|||
break; |
|||
|
|||
case 't': |
|||
compilerConfig.bFileTreeOutputOnly = true; |
|||
break; |
|||
|
|||
case 'f': |
|||
compilerConfig.bFileListOutputOnly = true; |
|||
break; |
|||
|
|||
case 'b': |
|||
compilerConfig.bBinary = true; |
|||
break; |
|||
|
|||
case 'c': |
|||
compilerConfig.bDATonly = true; |
|||
break; |
|||
|
|||
case 'd': |
|||
compilerConfig.bDocMode = true; |
|||
break; |
|||
|
|||
case 'e': |
|||
compilerConfig.bBinary = false; |
|||
break; |
|||
|
|||
case 'q': |
|||
compilerConfig.bQuiet = true; |
|||
break; |
|||
|
|||
case 'v': |
|||
compilerConfig.bVerbose = true; |
|||
break; |
|||
|
|||
case 's': |
|||
compilerConfig.bDumpSymbols = true; |
|||
break; |
|||
|
|||
case 'u': |
|||
compilerConfig.bUnusedMethodElimination = true; |
|||
break; |
|||
|
|||
case 'h': |
|||
default: |
|||
Usage(); |
|||
CleanupPathEntries(); |
|||
return 1; |
|||
break; |
|||
} |
|||
} |
|||
else // handle the input filename
|
|||
{ |
|||
if (infile) |
|||
{ |
|||
Usage(); |
|||
CleanupPathEntries(); |
|||
return 1; |
|||
} |
|||
infile = argv[i]; |
|||
} |
|||
} |
|||
|
|||
// must have input file
|
|||
if (!infile) |
|||
{ |
|||
Usage(); |
|||
CleanupPathEntries(); |
|||
return 1; |
|||
} |
|||
|
|||
if (compilerConfig.bFileTreeOutputOnly || compilerConfig.bFileListOutputOnly || compilerConfig.bDumpSymbols) |
|||
{ |
|||
compilerConfig.bQuiet = true; |
|||
} |
|||
|
|||
// finish the include path
|
|||
AddFilePath(infile); |
|||
|
|||
char outputFilename[256]; |
|||
if (!outfile) |
|||
{ |
|||
// create *.binary filename from user passed in spin filename
|
|||
strcpy(&outputFilename[0], infile); |
|||
const char* pTemp = strstr(&outputFilename[0], ".spin"); |
|||
if (pTemp == 0) |
|||
{ |
|||
printf("ERROR: spinfile must have .spin extension. You passed in: %s\n", infile); |
|||
Usage(); |
|||
CleanupPathEntries(); |
|||
return 1; |
|||
} |
|||
else |
|||
{ |
|||
int offset = (int)(pTemp - &outputFilename[0]); |
|||
outputFilename[offset+1] = 0; |
|||
if (compilerConfig.bDATonly) |
|||
{ |
|||
strcat(&outputFilename[0], "dat"); |
|||
} |
|||
else if (compilerConfig.bBinary) |
|||
{ |
|||
strcat(&outputFilename[0], "binary"); |
|||
} |
|||
else |
|||
{ |
|||
strcat(&outputFilename[0], "eeprom"); |
|||
} |
|||
} |
|||
} |
|||
else // use filename specified with -o
|
|||
{ |
|||
strcpy(outputFilename, outfile); |
|||
} |
|||
|
|||
if (!compilerConfig.bQuiet) |
|||
{ |
|||
Banner(); |
|||
printf("Compiling...\n%s\n", infile); |
|||
} |
|||
|
|||
InitCompiler(&compilerConfig, LoadFile, FreeFileBuffer); |
|||
|
|||
if (compilerConfig.bUsePreprocessor) |
|||
{ |
|||
// go through the command line arguments again, this time only processing -D
|
|||
for(int i = 1; i < argc; i++) |
|||
{ |
|||
// handle switches
|
|||
if(argv[i][0] == '-') |
|||
{ |
|||
if (argv[i][1] == 'D') |
|||
{ |
|||
if (argv[i][2]) |
|||
{ |
|||
p = &argv[i][2]; |
|||
} |
|||
else if(++i < argc) |
|||
{ |
|||
p = argv[i]; |
|||
} |
|||
else |
|||
{ |
|||
Usage(); |
|||
ShutdownCompiler(); |
|||
CleanupPathEntries(); |
|||
return 1; |
|||
} |
|||
|
|||
// add any predefined symbols here - note that when using the
|
|||
// "alternate" rules, these symbols have a null value - i.e.
|
|||
// they are just "defined", but are not used in macro substitution
|
|||
SetDefine(p, (compilerConfig.bAlternatePreprocessorMode ? "" : "1")); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// add symbols with predefined values here
|
|||
SetDefine("__SPIN__", "1"); |
|||
SetDefine("__TARGET__", "P1"); |
|||
} |
|||
|
|||
int nLength = 0; |
|||
unsigned char* pBuffer = CompileSpin(infile, &nLength); |
|||
|
|||
if (pBuffer) |
|||
{ |
|||
FILE* pFile = fopen(outputFilename, "wb"); |
|||
if (pFile) |
|||
{ |
|||
fwrite(pBuffer, nLength, 1, pFile); |
|||
fclose(pFile); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// compiler put out an error
|
|||
ShutdownCompiler(); |
|||
CleanupPathEntries(); |
|||
return 1; |
|||
} |
|||
|
|||
if (compilerConfig.bFileListOutputOnly) |
|||
{ |
|||
for (int i = 0; i < s_nFilesAccessed; i++) |
|||
{ |
|||
for (int j = i+1; j < s_nFilesAccessed; j++) |
|||
{ |
|||
if (strcmp(s_filesAccessed[i], s_filesAccessed[j]) == 0) |
|||
{ |
|||
s_filesAccessed[j][0] = 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
for (int i = 0; i < s_nFilesAccessed; i++) |
|||
{ |
|||
if (s_filesAccessed[i][0] != 0) |
|||
{ |
|||
printf("%s\n", s_filesAccessed[i]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
ShutdownCompiler(); |
|||
CleanupPathEntries(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,110 @@ |
|||
///////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
|
|||
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|||
// See end of file for terms of use. //
|
|||
// //
|
|||
///////////////////////////////////////////////////////////////
|
|||
//
|
|||
// pathentry.cpp
|
|||
//
|
|||
|
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
|
|||
#include "pathentry.h" |
|||
|
|||
PathEntry *path = NULL; |
|||
static PathEntry **pNextPathEntry = &path; |
|||
|
|||
static char lastfullpath[PATH_MAX]; |
|||
|
|||
const char *MakeNextPath(PathEntry **entry, const char *name) |
|||
{ |
|||
if (!*entry) |
|||
{ |
|||
*entry = path; |
|||
} |
|||
else |
|||
{ |
|||
*entry = (*entry)->next; |
|||
} |
|||
if (*entry) |
|||
{ |
|||
sprintf(lastfullpath, "%s%c%s", (*entry)->path, DIR_SEP, name); |
|||
return lastfullpath; |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
bool AddPath(const char *newPath) |
|||
{ |
|||
PathEntry* entry = (PathEntry*)new char[(sizeof(PathEntry) + strlen(newPath))]; |
|||
if (!(entry)) |
|||
{ |
|||
return false; |
|||
} |
|||
strcpy(entry->path, newPath); |
|||
*pNextPathEntry = entry; |
|||
pNextPathEntry = &entry->next; |
|||
entry->next = NULL; |
|||
return true; |
|||
} |
|||
|
|||
bool AddFilePath(const char *name) |
|||
{ |
|||
const char* end = strrchr(name, DIR_SEP); |
|||
if (!end) |
|||
{ |
|||
return false; |
|||
} |
|||
int len = (int)(end - name); |
|||
PathEntry *entry = (PathEntry*)new char[(sizeof(PathEntry) + len)]; |
|||
if (!entry) |
|||
{ |
|||
return false; |
|||
} |
|||
strncpy(entry->path, name, len); |
|||
entry->path[len] = '\0'; |
|||
*pNextPathEntry = entry; |
|||
pNextPathEntry = &entry->next; |
|||
entry->next = NULL; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
void CleanupPathEntries() |
|||
{ |
|||
PathEntry *entry = path; |
|||
while (entry != NULL) |
|||
{ |
|||
PathEntry *nextEntry = entry->next; |
|||
delete [] entry; |
|||
entry = nextEntry; |
|||
} |
|||
path = NULL; |
|||
lastfullpath[0] = 0; |
|||
} |
|||
|
|||
|
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -0,0 +1,58 @@ |
|||
///////////////////////////////////////////////////////////////
|
|||
// //
|
|||
// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
|
|||
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|||
// See end of file for terms of use. //
|
|||
// //
|
|||
///////////////////////////////////////////////////////////////
|
|||
//
|
|||
// pathentry.h
|
|||
//
|
|||
|
|||
//
|
|||
// code for handling directory paths (used with -I option)
|
|||
//
|
|||
|
|||
#ifndef PATH_MAX |
|||
#define PATH_MAX 1024 |
|||
#endif |
|||
|
|||
#if defined(WIN32) |
|||
#define DIR_SEP '\\' |
|||
#define DIR_SEP_STR "\\" |
|||
#else |
|||
#define DIR_SEP '/' |
|||
#define DIR_SEP_STR "/" |
|||
#endif |
|||
|
|||
struct PathEntry |
|||
{ |
|||
PathEntry *next; |
|||
char path[1]; |
|||
}; |
|||
|
|||
const char *MakeNextPath(PathEntry **entry, const char *name); // pass the address of an entry that is NULL to get first path, keep calling with same entry to walk list
|
|||
bool AddPath(const char *path); |
|||
bool AddFilePath(const char *name); |
|||
void CleanupPathEntries(); |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
// 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. //
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
|||
@ -1,23 +0,0 @@ |
|||
#
|
|||
# build the propeller tools for linux and Darwin
|
|||
#
|
|||
UNAME := $(shell uname) |
|||
ifeq ($(UNAME), Linux) |
|||
SUFFIX=linux |
|||
endif |
|||
ifeq ($(UNAME), Darwin) |
|||
SUFFIX=osx |
|||
endif |
|||
|
|||
DEST = ../../$(UNAME) |
|||
|
|||
all: $(DEST) |
|||
-for i in *.$(SUFFIX) ; do \
|
|||
chmod +x $$i ; \
|
|||
cp -p $$i $(DEST)/$$(basename $$i .$(SUFFIX)) ; \
|
|||
done |
|||
|
|||
$(DEST): |
|||
mkdir $(DEST) |
|||
|
|||
clean: |
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue