mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
876 lines
22 KiB
876 lines
22 KiB
//////////////////////////////////////////////////////////////
|
|
// //
|
|
// Propeller Spin/PASM Compiler //
|
|
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
|
|
// Adapted from Chip Gracey's x86 asm code by Roy Eltham //
|
|
// See end of file for terms of use. //
|
|
// //
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// 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. //
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|