Add templates
This commit is contained in:
parent
07969d1fa6
commit
fef6bc29bc
|
@ -3,6 +3,15 @@ rem @echo off
|
|||
@call :test opp_string.cpp
|
||||
@if %errorlevel% neq 0 goto :error
|
||||
|
||||
@call :test opp_array.cpp
|
||||
@if %errorlevel% neq 0 goto :error
|
||||
|
||||
@call :test opp_vector.cpp
|
||||
@if %errorlevel% neq 0 goto :error
|
||||
|
||||
@call :test opp_vector_string.cpp
|
||||
@if %errorlevel% neq 0 goto :error
|
||||
|
||||
@call :test opp_streamtest.cpp
|
||||
@if %errorlevel% neq 0 goto :error
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#include <opp/array.h>
|
||||
#include <assert.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
array<int, 10> a10;
|
||||
array<int, 20> a20;
|
||||
|
||||
for(int i=0; i<10; i++)
|
||||
a10[i] = i;
|
||||
for(int i=0; i<20; i++)
|
||||
a20[i] = i;
|
||||
|
||||
int s = 0;
|
||||
for(int i=0; i<10; i++)
|
||||
s += a10[i];
|
||||
for(int i=10; i<20; i++)
|
||||
s -= a20[i];
|
||||
|
||||
assert(s == -100);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#include <opp/vector.h>
|
||||
#include <assert.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
vector<int> a;
|
||||
|
||||
for(int i=0; i<10; i++)
|
||||
a.push_back(i);
|
||||
|
||||
int s = 0;
|
||||
for(int i=0; i<a.size(); i++)
|
||||
s += a[i];
|
||||
|
||||
assert(s == 45);
|
||||
|
||||
for(int i=0; i<5; i++)
|
||||
a.erase(i);
|
||||
|
||||
s = 0;
|
||||
for(int i=0; i<a.size(); i++)
|
||||
s += a[i];
|
||||
|
||||
assert(s == 1 + 3 + 5 + 7 + 9);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#include <opp/vector.h>
|
||||
#include <opp/string.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <opp/iostream.h>
|
||||
|
||||
string join(const vector<string> & vs)
|
||||
{
|
||||
string sj;
|
||||
for(int i=0; i<vs.size(); i++)
|
||||
sj += vs[i];
|
||||
return sj;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
vector<string> vs;
|
||||
string a;
|
||||
|
||||
for(int i=0; i<10; i++)
|
||||
{
|
||||
vs.push_back(a);
|
||||
a += "x";
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i=0; i<10; i++)
|
||||
s += vs[i].size();
|
||||
|
||||
assert(s == 45);
|
||||
|
||||
assert(join(vs).size() == 45);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
#ifndef OPP_ARRAY_H
|
||||
#define OPP_ARRAY_H
|
||||
|
||||
|
||||
template <class T, int n>
|
||||
class array
|
||||
{
|
||||
protected:
|
||||
T _data[n];
|
||||
public:
|
||||
int size(void) const
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
int max_size(void) const
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
bool empty(void) const
|
||||
{
|
||||
return n == 0;
|
||||
}
|
||||
|
||||
const T & at(int at) const
|
||||
{
|
||||
return _data[at];
|
||||
}
|
||||
|
||||
T & at(int at)
|
||||
{
|
||||
return _data[at];
|
||||
}
|
||||
|
||||
T & operator[] (int at)
|
||||
{
|
||||
return _data[at];
|
||||
}
|
||||
|
||||
const T & operator[] (int at) const
|
||||
{
|
||||
return _data[at];
|
||||
}
|
||||
|
||||
T * begin(void)
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
const T * begin(void) const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
const T * cbegin(void) const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
T * end(void)
|
||||
{
|
||||
return _data + n;
|
||||
}
|
||||
|
||||
const T * end(void) const
|
||||
{
|
||||
return _data + n;
|
||||
}
|
||||
|
||||
const T * cend(void) const
|
||||
{
|
||||
return _data + n;
|
||||
}
|
||||
|
||||
T & back(void)
|
||||
{
|
||||
return _data[n - 1];
|
||||
}
|
||||
|
||||
const T & back(void) const
|
||||
{
|
||||
return _data[n - 1];
|
||||
}
|
||||
|
||||
T & front(void)
|
||||
{
|
||||
return _data[0];
|
||||
}
|
||||
|
||||
const T & front(void) const
|
||||
{
|
||||
return _data[0];
|
||||
}
|
||||
|
||||
T * data(void)
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
const T * data(void) const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
void fill(const T & t)
|
||||
{
|
||||
for(int i=0; i<n; i++)
|
||||
_data[i] = t;
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
void swap(array<T, n> & a)
|
||||
{
|
||||
for(int i=0; i<n; i++)
|
||||
{
|
||||
T t(_data[i]);
|
||||
_data[i] = a._data[i];
|
||||
a._data[i] = t;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -129,23 +129,20 @@ string & string::operator+=(const string & s)
|
|||
{
|
||||
if (s.cstr)
|
||||
{
|
||||
char d = 0;
|
||||
if (cstr)
|
||||
{
|
||||
char l = cstr[0] + s.cstr[0];
|
||||
d = cstr[0];
|
||||
|
||||
char l = s.cstr[0] + d;
|
||||
char * c = malloc(char(l + 2));
|
||||
c[0] = l;
|
||||
smemcpy(c + 1, cstr + 1, cstr[0]);
|
||||
smemcpy(c + 1 + cstr[0], s.cstr + 1, s.cstr[0] + 1);
|
||||
|
||||
if (d)
|
||||
smemcpy(c + 1, cstr + 1, d);
|
||||
smemcpy(c + 1 + d, s.cstr + 1, s.cstr[0] + 1);
|
||||
free(cstr);
|
||||
cstr = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
char l = s.cstr[0];
|
||||
cstr = malloc(char(l + 2));
|
||||
smemcpy(cstr, s.cstr, l + 2);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
#ifndef OPP_VECTOR_H
|
||||
#define OPP_VECTOR_H
|
||||
|
||||
template <class T>
|
||||
class vector
|
||||
{
|
||||
protected:
|
||||
T * _data;
|
||||
int _size, _capacity;
|
||||
public:
|
||||
vector(void) : _data(nullptr), _size(0), _capacity(0) {}
|
||||
vector(int n) : _data(new T[n]), _size(n), _capacity(n) {}
|
||||
~vector(void)
|
||||
{
|
||||
delete[] _data;
|
||||
}
|
||||
|
||||
int size(void) const
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
int max_size(void) const
|
||||
{
|
||||
return 32767;
|
||||
}
|
||||
|
||||
bool empty(void) const
|
||||
{
|
||||
return _size == 0;
|
||||
}
|
||||
|
||||
int capacity(void) const
|
||||
{
|
||||
return _capacity;
|
||||
}
|
||||
|
||||
void resize(int n);
|
||||
|
||||
void reserve(int n);
|
||||
|
||||
void shrink_to_fit(void);
|
||||
|
||||
T & at(int at)
|
||||
{
|
||||
return _data[at];
|
||||
}
|
||||
|
||||
const T & at(int at) const
|
||||
{
|
||||
return _data[at];
|
||||
}
|
||||
|
||||
T & operator[](int at)
|
||||
{
|
||||
return _data[at];
|
||||
}
|
||||
|
||||
const T & operator[](int at) const
|
||||
{
|
||||
return _data[at];
|
||||
}
|
||||
|
||||
T & front(void)
|
||||
{
|
||||
return _data[0];
|
||||
}
|
||||
|
||||
const T & front(void) const
|
||||
{
|
||||
return _data[0];
|
||||
}
|
||||
|
||||
T & back(void)
|
||||
{
|
||||
return _data[_size - 1];
|
||||
}
|
||||
|
||||
const T & back(void) const
|
||||
{
|
||||
return _data[_size - 1];
|
||||
}
|
||||
|
||||
T * data(void)
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
const T * at(void) const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
void push_back(const T & t);
|
||||
|
||||
void pop_back(void)
|
||||
{
|
||||
_size--;
|
||||
}
|
||||
|
||||
void insert(int at, const T & t);
|
||||
|
||||
void erase(int at, int n = 1);
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
void vector<T>::reserve(int n)
|
||||
{
|
||||
if (n > _capacity)
|
||||
{
|
||||
_capacity = n;
|
||||
T * d = new T[_capacity];
|
||||
for(int i=0; i<_size; i++)
|
||||
d[i] = _data[i];
|
||||
delete[] _data;
|
||||
_data = d;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void vector<T>::resize(int n)
|
||||
{
|
||||
if (n < _size)
|
||||
_size = n;
|
||||
else if (n < _capacity)
|
||||
_size = n;
|
||||
else
|
||||
{
|
||||
reserve(n);
|
||||
_size = n;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void vector<T>::shrink_to_fit(void)
|
||||
{
|
||||
if (_size < _capacity)
|
||||
{
|
||||
_capacity = _size;
|
||||
T * d = new T[_capacity];
|
||||
for(int i=0; i<_size; i++)
|
||||
d[i] = _data[i];
|
||||
delete[] _data;
|
||||
_data = d;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void vector<T>::push_back(const T & t)
|
||||
{
|
||||
if (_size == _capacity)
|
||||
reserve(_size + 1 + (_size >> 1));
|
||||
_data[_size++] = t;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void vector<T>::insert(int at, const T & t)
|
||||
{
|
||||
if (_size == _capacity)
|
||||
reserve(_size + 1 + (_size >> 1));
|
||||
for(int i=_size; i>at; i--)
|
||||
_data[i] = _data[i - 1];
|
||||
_data[at] = t;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void vector<T>::erase(int at, int n)
|
||||
{
|
||||
_size -= n;
|
||||
for(int i=at; i<_size; i++)
|
||||
_data[i] = _data[i + n];
|
||||
}
|
||||
|
||||
#endif
|
|
@ -15,6 +15,7 @@ CompilationUnits::CompilationUnits(Errors * errors)
|
|||
mScope = new DeclarationScope(nullptr, SLEVEL_GLOBAL);
|
||||
mRuntimeScope = new DeclarationScope(nullptr, SLEVEL_GLOBAL);
|
||||
mVTableScope = new DeclarationScope(nullptr, SLEVEL_GLOBAL);
|
||||
mTemplateScope = new DeclarationScope(nullptr, SLEVEL_GLOBAL);
|
||||
mStartup = nullptr;
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
|
|
|
@ -19,7 +19,7 @@ public:
|
|||
CompilationUnits(Errors * errors);
|
||||
~CompilationUnits(void);
|
||||
|
||||
DeclarationScope* mScope, * mVTableScope;
|
||||
DeclarationScope* mScope, * mVTableScope, * mTemplateScope;
|
||||
CompilationUnit* mCompilationUnits, * mPendingUnits;
|
||||
|
||||
Declaration* mStartup;
|
||||
|
|
|
@ -240,6 +240,10 @@ static void FillVTableTree(Declaration* vdec)
|
|||
cvdec = cvdec->mNext;
|
||||
}
|
||||
}
|
||||
void Compiler::CompleteTemplateExpansion(void)
|
||||
{
|
||||
}
|
||||
|
||||
void Compiler::BuildVTables(void)
|
||||
{
|
||||
// Connect vdecs with parents
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
|
||||
void CompileProcedure(InterCodeProcedure* proc);
|
||||
void BuildVTables(void);
|
||||
void CompleteTemplateExpansion(void);
|
||||
|
||||
bool WriteDbjFile(const char* filename);
|
||||
};
|
||||
|
|
|
@ -800,7 +800,7 @@ Declaration::Declaration(const Location& loc, DecType type)
|
|||
mVTable(nullptr),
|
||||
mVarIndex(-1), mLinkerObject(nullptr), mCallers(nullptr), mCalled(nullptr), mAlignment(1),
|
||||
mInteger(0), mNumber(0), mMinValue(-0x80000000LL), mMaxValue(0x7fffffffLL), mFastCallBase(0), mFastCallSize(0), mStride(0), mStripe(1),
|
||||
mCompilerOptions(0), mUseCount(0)
|
||||
mCompilerOptions(0), mUseCount(0), mTokens(nullptr), mParser(nullptr)
|
||||
{}
|
||||
|
||||
Declaration::~Declaration(void)
|
||||
|
@ -811,7 +811,12 @@ Declaration::~Declaration(void)
|
|||
|
||||
int Declaration::Stride(void) const
|
||||
{
|
||||
return mStride > 0 ? mStride : mBase->mSize;
|
||||
if (mStride > 0)
|
||||
return mStride;
|
||||
else if (mBase)
|
||||
return mBase->mSize;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
Declaration* Declaration::BuildConstPointer(const Location& loc)
|
||||
|
@ -862,6 +867,104 @@ Declaration* Declaration::Last(void)
|
|||
return p;
|
||||
}
|
||||
|
||||
const Ident* Declaration::MangleIdent(void)
|
||||
{
|
||||
if (!mMangleIdent)
|
||||
{
|
||||
if (mType == DT_CONST_INTEGER)
|
||||
{
|
||||
char buffer[20];
|
||||
sprintf_s(buffer, "%d", (int)mInteger);
|
||||
mMangleIdent = Ident::Unique(buffer);
|
||||
}
|
||||
else if (mType == DT_TYPE_INTEGER)
|
||||
{
|
||||
char buffer[20];
|
||||
sprintf_s(buffer, "%c%d", (mFlags & DTF_SIGNED) ? 'i' : 'u', mSize * 8);
|
||||
mMangleIdent = Ident::Unique(buffer);
|
||||
}
|
||||
else if (mType == DT_TYPE_FLOAT)
|
||||
{
|
||||
mMangleIdent = Ident::Unique("float");
|
||||
}
|
||||
else if (mType == DT_TYPE_REFERENCE)
|
||||
{
|
||||
mMangleIdent = mBase->MangleIdent()->PreMangle("&");
|
||||
}
|
||||
else if (mType == DT_TYPE_POINTER)
|
||||
{
|
||||
mMangleIdent = mBase->MangleIdent()->PreMangle("*");
|
||||
}
|
||||
else if (mType == DT_TYPE_STRUCT)
|
||||
{
|
||||
mMangleIdent = mQualIdent->PreMangle("struct ");
|
||||
}
|
||||
else if (mType == DT_TYPE_ENUM)
|
||||
{
|
||||
mMangleIdent = mQualIdent->PreMangle("enum ");
|
||||
}
|
||||
else if (mType == DT_TEMPLATE)
|
||||
{
|
||||
mMangleIdent = Ident::Unique("<");
|
||||
|
||||
Declaration* dec = mParams;
|
||||
while (dec)
|
||||
{
|
||||
mMangleIdent = mMangleIdent->Mangle(dec->mBase->MangleIdent()->mString);
|
||||
dec = dec->mNext;
|
||||
if (dec)
|
||||
mMangleIdent = mMangleIdent->Mangle(",");
|
||||
}
|
||||
mMangleIdent = mMangleIdent->Mangle(">");
|
||||
}
|
||||
else
|
||||
mMangleIdent = mQualIdent;
|
||||
|
||||
if (mFlags & DTF_CONST)
|
||||
mMangleIdent = mMangleIdent->PreMangle("const ");
|
||||
}
|
||||
|
||||
return mMangleIdent;
|
||||
}
|
||||
|
||||
Declaration* Declaration::TemplateExpand(Declaration* tdec)
|
||||
{
|
||||
if (mType == DT_ARGUMENT)
|
||||
{
|
||||
Declaration* edec = this->Clone();
|
||||
edec->mBase = mBase->TemplateExpand(tdec);
|
||||
if (mNext)
|
||||
edec->mNext = mNext->TemplateExpand(tdec);
|
||||
return edec;
|
||||
}
|
||||
else if (mType == DT_CONST_FUNCTION)
|
||||
{
|
||||
Declaration* edec = this->Clone();
|
||||
edec->mBase = mBase->TemplateExpand(tdec);
|
||||
return edec;
|
||||
}
|
||||
else if (mType == DT_TYPE_FUNCTION)
|
||||
{
|
||||
Declaration* edec = this->Clone();
|
||||
edec->mBase = mBase->TemplateExpand(tdec);
|
||||
if (edec->mParams)
|
||||
edec->mParams = mParams->TemplateExpand(tdec);
|
||||
return edec;
|
||||
}
|
||||
else if (mType == DT_TYPE_TEMPLATE || mType == DT_CONST_TEMPLATE)
|
||||
{
|
||||
return tdec->mScope->Lookup(mIdent);
|
||||
}
|
||||
else if (mType == DT_TYPE_POINTER || mType == DT_TYPE_ARRAY || mType == DT_TYPE_REFERENCE)
|
||||
{
|
||||
Declaration* edec = this->Clone();
|
||||
edec->mBase = mBase->TemplateExpand(tdec);
|
||||
return edec;
|
||||
}
|
||||
else
|
||||
return this;
|
||||
}
|
||||
|
||||
Declaration* Declaration::Clone(void)
|
||||
{
|
||||
Declaration* ndec = new Declaration(mLocation, mType);
|
||||
|
@ -1221,7 +1324,7 @@ bool Declaration::IsConstSame(const Declaration* dec) const
|
|||
|
||||
bool Declaration::IsSameParams(const Declaration* dec) const
|
||||
{
|
||||
if (mType == DT_TYPE_FUNCTION && dec->mType == DT_TYPE_FUNCTION)
|
||||
if (mType == DT_TYPE_FUNCTION && dec->mType == DT_TYPE_FUNCTION || mType == DT_TEMPLATE && dec->mType == DT_TEMPLATE)
|
||||
{
|
||||
Declaration* ld = mParams, * rd = dec->mParams;
|
||||
while (ld && rd)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
class LinkerObject;
|
||||
class LinkerSection;
|
||||
class Parser;
|
||||
|
||||
enum DecType
|
||||
{
|
||||
|
@ -25,6 +26,7 @@ enum DecType
|
|||
DT_TYPE_FUNCTION,
|
||||
DT_TYPE_ASSEMBLER,
|
||||
DT_TYPE_AUTO,
|
||||
DT_TYPE_TEMPLATE,
|
||||
|
||||
DT_TYPE_CONST,
|
||||
DT_TYPE_VOLATILE,
|
||||
|
@ -39,6 +41,7 @@ enum DecType
|
|||
DT_CONST_REFERENCE,
|
||||
DT_CONST_ASSEMBLER,
|
||||
DT_CONST_CONSTRUCTOR,
|
||||
DT_CONST_TEMPLATE,
|
||||
|
||||
DT_VARIABLE,
|
||||
DT_ARGUMENT,
|
||||
|
@ -115,6 +118,7 @@ enum ScopeLevel
|
|||
SLEVEL_GLOBAL,
|
||||
SLEVEL_STATIC,
|
||||
SLEVEL_NAMESPACE,
|
||||
SLEVEL_TEMPLATE,
|
||||
SLEVEL_CLASS,
|
||||
SLEVEL_FUNCTION,
|
||||
SLEVEL_LOCAL,
|
||||
|
@ -254,11 +258,13 @@ public:
|
|||
int64 mInteger, mMinValue, mMaxValue;
|
||||
double mNumber;
|
||||
uint64 mFlags, mCompilerOptions;
|
||||
const Ident * mIdent, * mQualIdent;
|
||||
const Ident * mIdent, * mQualIdent, * mMangleIdent;
|
||||
LinkerSection * mSection;
|
||||
const uint8 * mData;
|
||||
LinkerObject * mLinkerObject;
|
||||
int mUseCount;
|
||||
TokenSequence * mTokens;
|
||||
Parser * mParser;
|
||||
|
||||
GrowingArray<Declaration*> mCallers, mCalled;
|
||||
|
||||
|
@ -290,6 +296,10 @@ public:
|
|||
Declaration* BuildConstPointer(const Location& loc);
|
||||
Declaration* BuildConstReference(const Location& loc);
|
||||
|
||||
Declaration* TemplateExpand(Declaration* tdec);
|
||||
|
||||
const Ident* MangleIdent(void);
|
||||
|
||||
int Stride(void) const;
|
||||
};
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ enum ErrorID
|
|||
EERR_MISSING_TEMP,
|
||||
EERR_NON_STATIC_MEMBER,
|
||||
EERR_TEMPLATE_PARAMS,
|
||||
EERR_FUNCTION_TEMPLATE,
|
||||
|
||||
ERRR_STACK_OVERFLOW,
|
||||
ERRR_INVALID_NUMBER,
|
||||
|
|
|
@ -14812,6 +14812,18 @@ bool InterCodeBasicBlock::PeepholeReplaceOptimization(const GrowingVariableArray
|
|||
mInstructions[i + 0]->mSrc[1].mFinal = false;
|
||||
changed = true;
|
||||
}
|
||||
else if (
|
||||
mInstructions[i + 0]->mCode == IC_LEA &&
|
||||
mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR &&
|
||||
mInstructions[i + 2]->mCode == IC_LOAD &&
|
||||
mInstructions[i + 2]->mSrc[0].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 2]->mSrc[0].mFinal &&
|
||||
CanSwapInstructions(mInstructions[i + 1], mInstructions[i + 2]))
|
||||
{
|
||||
InterInstruction* ins = mInstructions[i + 2];
|
||||
mInstructions[i + 2] = mInstructions[i + 1];
|
||||
mInstructions[i + 1] = ins;
|
||||
changed = true;
|
||||
}
|
||||
else if (
|
||||
mInstructions[i + 0]->mCode == IC_STORE && mInstructions[i + 1]->mCode == IC_STORE &&
|
||||
SameMemSegment(mInstructions[i + 1]->mSrc[1], mInstructions[i + 0]->mSrc[1]) &&
|
||||
|
@ -16736,7 +16748,7 @@ void InterCodeProcedure::Close(void)
|
|||
{
|
||||
GrowingTypeArray tstack(IT_NONE);
|
||||
|
||||
CheckFunc = !strcmp(mIdent->mString, "main");
|
||||
CheckFunc = !strcmp(mIdent->mString, "join");
|
||||
|
||||
mEntryBlock = mBlocks[0];
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ static inline InterType InterTypeOf(const Declaration* dec)
|
|||
|
||||
InterCodeGenerator::ExValue InterCodeGenerator::ToValue(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, ExValue v)
|
||||
{
|
||||
if (v.mType->mType == DT_TYPE_REFERENCE)
|
||||
if (v.mType && v.mType->mType == DT_TYPE_REFERENCE)
|
||||
{
|
||||
v.mType = v.mType->mBase;
|
||||
v.mReference++;
|
||||
|
@ -1020,7 +1020,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateInline(Declaration* pro
|
|||
{
|
||||
if (vr.mType->mType == DT_TYPE_ARRAY || vr.mType->mType == DT_TYPE_FUNCTION)
|
||||
vr = Dereference(proc, texp, block, vr, 1);
|
||||
else if (pdec && pdec->mBase->mType == DT_TYPE_REFERENCE)
|
||||
else if (pdec && (pdec->mBase->mType == DT_TYPE_REFERENCE && vr.mType->mType != DT_TYPE_REFERENCE))
|
||||
vr = Dereference(proc, texp, block, vr, 1);
|
||||
else
|
||||
vr = Dereference(proc, texp, block, vr);
|
||||
|
@ -2029,7 +2029,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
|
|||
vr = Dereference(proc, exp, block, vr);
|
||||
|
||||
if (vl.mType->mType != DT_TYPE_ARRAY && vl.mType->mType != DT_TYPE_POINTER)
|
||||
{
|
||||
mErrors->Error(exp->mLocation, EERR_INVALID_INDEX, "Invalid type for indexing");
|
||||
return ExValue(TheConstVoidTypeDeclaration, -1);
|
||||
}
|
||||
|
||||
if (!vr.mType->IsIntegerType())
|
||||
mErrors->Error(exp->mLocation, EERR_INVALID_INDEX, "Index operand is not integral number");
|
||||
|
@ -3235,7 +3238,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
|
|||
mErrors->Error(texp->mLocation, EWARN_NUMERIC_0_USED_AS_NULLPTR, "Numeric 0 used for nullptr");
|
||||
vr = CoerceType(proc, texp, block, vr, pdec->mBase);
|
||||
}
|
||||
else if (pdec && pdec->mBase->mType == DT_TYPE_REFERENCE)
|
||||
else if (pdec && (pdec->mBase->mType == DT_TYPE_REFERENCE && vr.mType->mType != DT_TYPE_REFERENCE))
|
||||
vr = Dereference(proc, texp, block, vr, 1);
|
||||
else
|
||||
vr = Dereference(proc, texp, block, vr);
|
||||
|
@ -4659,7 +4662,7 @@ InterCodeProcedure* InterCodeGenerator::TranslateProcedure(InterCodeModule * mod
|
|||
InterCodeProcedure* proc = new InterCodeProcedure(mod, dec->mLocation, dec->mQualIdent, mLinker->AddObject(dec->mLocation, dec->mQualIdent, dec->mSection, LOT_BYTE_CODE, dec->mAlignment));
|
||||
|
||||
#if 0
|
||||
if (proc->mIdent && !strcmp(proc->mIdent->mString, "main"))
|
||||
if (proc->mIdent && !strcmp(proc->mIdent->mString, "join"))
|
||||
exp->Dump(0);
|
||||
#endif
|
||||
#if 0
|
||||
|
|
|
@ -16298,7 +16298,7 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc)
|
|||
fblock->mFalseJump = mFalseJump;
|
||||
fblock->mBranch = mBranch;
|
||||
|
||||
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
|
||||
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
|
||||
mIns[i + 1].mType = ASMIT_NOP;
|
||||
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
|
||||
mIns[i + 3].mType = ASMIT_INC; mIns[i + 3].mLive |= LIVE_CPU_REG_Z;
|
||||
|
@ -25274,6 +25274,8 @@ bool NativeCodeBasicBlock::MoveZeroPageCrossBlockUp(int at, const NativeCodeInst
|
|||
return false;
|
||||
if (mIns[i].ReferencesZeroPage(sins.mAddress))
|
||||
return false;
|
||||
if (mIns[i].mMode == ASMIM_INDIRECT_Y && (mIns[i].mAddress + 1 == lins.mAddress || mIns[i].mAddress == lins.mAddress))
|
||||
return false;
|
||||
}
|
||||
|
||||
at = mIns.Size();
|
||||
|
@ -27108,6 +27110,58 @@ bool NativeCodeBasicBlock::ReverseLoadCommutativeOpUp(int aload, int aop)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::MoveTYADCStoreDown(int at)
|
||||
{
|
||||
// [at + 0] TYA
|
||||
// [at + 1] CLC
|
||||
// [at + 2] ADC #
|
||||
// [at + 3] STA
|
||||
|
||||
int offset = mIns[at + 2].mAddress;
|
||||
int addr = mIns[at + 3].mAddress;
|
||||
|
||||
for (int i = at + 4; i < mIns.Size(); i++)
|
||||
{
|
||||
NativeCodeInstruction& ins(mIns[i]);
|
||||
|
||||
if (mIns[i].mType == ASMIT_INY)
|
||||
offset--;
|
||||
else if (mIns[i].mType == ASMIT_DEY)
|
||||
offset++;
|
||||
else if (mIns[i].ChangesYReg())
|
||||
return false;
|
||||
else if (mIns[i].ReferencesZeroPage(addr))
|
||||
return false;
|
||||
else if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z)))
|
||||
{
|
||||
if (offset < -2 || offset > 2)
|
||||
return false;
|
||||
while (offset < 0)
|
||||
{
|
||||
mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_DEY));
|
||||
offset++;
|
||||
i++;
|
||||
}
|
||||
while (offset > 0)
|
||||
{
|
||||
mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_INY));
|
||||
offset--;
|
||||
i++;
|
||||
}
|
||||
mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, addr));
|
||||
while (i > at)
|
||||
{
|
||||
mIns[i].mLive |= LIVE_CPU_REG_Y;
|
||||
i--;
|
||||
}
|
||||
mIns.Remove(at, 4);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NativeCodeBasicBlock::MoveLDSTXOutOfRange(int at)
|
||||
{
|
||||
int j = at + 2;
|
||||
|
@ -28678,15 +28732,19 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc)
|
|||
i++;
|
||||
}
|
||||
|
||||
int aimm = -1;
|
||||
bool aimm = false;
|
||||
NativeCodeInstruction ains;
|
||||
|
||||
if (!pblock->mExitRequiredRegs[CPU_REG_A] || !pblock->mExitRequiredRegs[CPU_REG_X])
|
||||
{
|
||||
for (int i = 0; i < mIns.Size(); i++)
|
||||
{
|
||||
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_IMMEDIATE)
|
||||
aimm = mIns[i].mAddress;
|
||||
else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && aimm >= 0)
|
||||
if (mIns[i].mType == ASMIT_LDA && (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS))
|
||||
{
|
||||
aimm = true;
|
||||
ains = mIns[i];
|
||||
}
|
||||
else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && aimm)
|
||||
{
|
||||
int reg = mIns[i].mAddress;
|
||||
if (!ReferencedOnPath(this, 0, i, reg) && !ChangedOnPath(this, i + 1, mIns.Size(), reg))
|
||||
|
@ -28698,12 +28756,12 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc)
|
|||
{
|
||||
if (!pblock->mExitRequiredRegs[CPU_REG_A])
|
||||
{
|
||||
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, aimm));
|
||||
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ains));
|
||||
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
|
||||
}
|
||||
else if (!pblock->mExitRequiredRegs[CPU_REG_X])
|
||||
{
|
||||
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, aimm));
|
||||
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ains));
|
||||
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, reg));
|
||||
}
|
||||
|
||||
|
@ -28724,7 +28782,7 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc)
|
|||
}
|
||||
}
|
||||
else if (mIns[i].ChangesAccu())
|
||||
aimm = -1;
|
||||
aimm = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33760,6 +33818,20 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
|
|||
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
for (int i = 0; i + 4 < mIns.Size(); i++)
|
||||
{
|
||||
if (mIns[i + 0].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_CLC &&
|
||||
mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE &&
|
||||
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)))
|
||||
{
|
||||
if (MoveTYADCStoreDown(i))
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
CheckLive();
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// move load - store abs up to initial store
|
||||
//
|
||||
|
@ -38380,6 +38452,26 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
|
|||
progress = true;
|
||||
}
|
||||
#endif
|
||||
#if 1
|
||||
else if (
|
||||
mIns[i + 0].mType == ASMIT_TYA &&
|
||||
mIns[i + 1].mType == ASMIT_TAX &&
|
||||
mIns[i + 2].mType == ASMIT_CLC &&
|
||||
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress <= 2 &&
|
||||
mIns[i + 4].mType == ASMIT_TAY && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)))
|
||||
{
|
||||
mIns[i + 0].mLive |= LIVE_CPU_REG_Y;
|
||||
mIns[i + 1].mLive |= LIVE_CPU_REG_Y;
|
||||
mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
|
||||
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
|
||||
if (mIns[i + 3].mAddress > 1)
|
||||
mIns[i + 4].mType = ASMIT_INY;
|
||||
else
|
||||
mIns[i + 4].mType = ASMIT_NOP;
|
||||
|
||||
progress = true;
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
else if (
|
||||
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
|
||||
|
@ -40692,7 +40784,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
|
|||
{
|
||||
mInterProc = proc;
|
||||
|
||||
CheckFunc = !strcmp(mInterProc->mIdent->mString, "time_draw");
|
||||
CheckFunc = !strcmp(mInterProc->mIdent->mString, "main");
|
||||
|
||||
int nblocks = proc->mBlocks.Size();
|
||||
tblocks = new NativeCodeBasicBlock * [nblocks];
|
||||
|
|
|
@ -410,6 +410,7 @@ public:
|
|||
bool MoveLoadAddZPStoreUp(int at);
|
||||
bool MoveLoadShiftRotateUp(int at);
|
||||
bool MoveLoadShiftStoreUp(int at);
|
||||
bool MoveTYADCStoreDown(int at);
|
||||
|
||||
bool MoveLDSTXOutOfRange(int at);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ Parser::Parser(Errors* errors, Scanner* scanner, CompilationUnits* compilationUn
|
|||
{
|
||||
mGlobals = new DeclarationScope(compilationUnits->mScope, SLEVEL_STATIC);
|
||||
mScope = mGlobals;
|
||||
mTemplateScope = nullptr;
|
||||
|
||||
mCodeSection = compilationUnits->mSectionCode;
|
||||
mDataSection = compilationUnits->mSectionData;
|
||||
|
@ -28,6 +29,20 @@ Parser::~Parser(void)
|
|||
|
||||
}
|
||||
|
||||
Parser* Parser::Clone(void)
|
||||
{
|
||||
Parser* p = new Parser(mErrors, new Scanner(mErrors, mScanner->mPreprocessor), mCompilationUnits);
|
||||
|
||||
p->mGlobals = mGlobals;
|
||||
p->mScope = mScope;
|
||||
p->mCompilerOptions = mCompilerOptions;
|
||||
p->mCodeSection = mCodeSection;
|
||||
p->mDataSection = mDataSection;
|
||||
p->mBSSection = mBSSection;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
Declaration* Parser::FindBaseMemberFunction(Declaration* dec, Declaration* mdec)
|
||||
{
|
||||
const Ident* ident = mdec->mIdent;
|
||||
|
@ -117,7 +132,15 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt)
|
|||
structName = mScanner->mTokenIdent;
|
||||
mScanner->NextToken();
|
||||
Declaration* edec = mScope->Lookup(structName);
|
||||
if (edec && mScanner->mToken != TK_OPEN_BRACE && mScanner->mToken != TK_COLON)
|
||||
if (edec && edec->mType == DT_TEMPLATE)
|
||||
{
|
||||
mTemplateScope->Insert(structName, dec);
|
||||
|
||||
dec->mIdent = structName;
|
||||
dec->mQualIdent = mScope->Mangle(structName->Mangle(mTemplateScope->mName->mString));
|
||||
dec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS, dec->mQualIdent);
|
||||
}
|
||||
else if (edec && mScanner->mToken != TK_OPEN_BRACE && mScanner->mToken != TK_COLON)
|
||||
{
|
||||
dec = edec;
|
||||
}
|
||||
|
@ -562,11 +585,20 @@ Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags, bool qualified)
|
|||
|
||||
case TK_IDENT:
|
||||
pident = mScanner->mTokenIdent;
|
||||
if (mTemplateScope)
|
||||
dec = mTemplateScope->Lookup(mScanner->mTokenIdent);
|
||||
|
||||
if (!dec)
|
||||
{
|
||||
dec = mScope->Lookup(mScanner->mTokenIdent);
|
||||
if (dec && dec->mType == DT_CONST_FUNCTION && mScope->mLevel == SLEVEL_CLASS)
|
||||
dec = mScope->mParent->Lookup(mScanner->mTokenIdent);
|
||||
|
||||
mScanner->NextToken();
|
||||
|
||||
if (dec && dec->mType == DT_TEMPLATE)
|
||||
dec = ParseTemplateExpansion(dec, nullptr);
|
||||
|
||||
while (qualified && dec && dec->mType == DT_TYPE_STRUCT && ConsumeTokenIf(TK_COLCOLON))
|
||||
{
|
||||
if (ExpectToken(TK_IDENT))
|
||||
|
@ -609,6 +641,9 @@ Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags, bool qualified)
|
|||
mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Identifier not defined", pident);
|
||||
else
|
||||
mErrors->Error(mScanner->mLocation, EERR_NOT_A_TYPE, "Identifier is no type", dec->mQualIdent);
|
||||
}
|
||||
else
|
||||
mScanner->NextToken();
|
||||
break;
|
||||
|
||||
case TK_ENUM:
|
||||
|
@ -804,10 +839,26 @@ Declaration* Parser::ParsePostfixDeclaration(void)
|
|||
{
|
||||
dec = new Declaration(mScanner->mLocation, DT_VARIABLE);
|
||||
dec->mIdent = mScanner->mTokenIdent;
|
||||
dec->mQualIdent = mScope->Mangle(dec->mIdent);
|
||||
dec->mSection = mBSSection;
|
||||
dec->mBase = nullptr;
|
||||
mScanner->NextToken();
|
||||
|
||||
if (mScanner->mToken == TK_LESS_THAN && mTemplateScope)
|
||||
{
|
||||
Declaration* tdec = mScope->Lookup(dec->mIdent);
|
||||
if (tdec && tdec->mType == DT_TEMPLATE)
|
||||
{
|
||||
// for now just skip over template stuff
|
||||
while (!ConsumeTokenIf(TK_GREATER_THAN))
|
||||
mScanner->NextToken();
|
||||
|
||||
if (mTemplateScope->mName)
|
||||
dec->mIdent = dec->mIdent->Mangle(mTemplateScope->mName->mString);
|
||||
}
|
||||
}
|
||||
|
||||
dec->mQualIdent = mScope->Mangle(dec->mIdent);
|
||||
|
||||
if (mScanner->mToken == TK_OPEN_PARENTHESIS && mScope->mLevel >= SLEVEL_FUNCTION)
|
||||
{
|
||||
// Can't be a function declaration in local context, so it must be an object
|
||||
|
@ -2964,6 +3015,7 @@ Expression* Parser::AddFunctionCallRefReturned(Expression* exp)
|
|||
cexp->mToken = pex->mToken;
|
||||
|
||||
pex->mType = EX_INITIALIZATION;
|
||||
pex->mToken = TK_ASSIGN;
|
||||
pex->mLeft = vexp;
|
||||
pex->mRight = cexp;
|
||||
pex->mDecValue = nullptr;
|
||||
|
@ -2990,6 +3042,38 @@ Expression* Parser::AddFunctionCallRefReturned(Expression* exp)
|
|||
rexp = ConcatExpression(rexp, dexp);
|
||||
}
|
||||
}
|
||||
else if (pdec->mBase->mType == DT_TYPE_REFERENCE && pex->mType == EX_CONSTANT)
|
||||
{
|
||||
// A simple constant is passed by const ref
|
||||
if (pex->mDecValue->mType == DT_CONST_INTEGER || pex->mDecValue->mType == DT_CONST_FLOAT || pex->mDecValue->mType == DT_CONST_POINTER)
|
||||
{
|
||||
int nindex = mLocalIndex++;
|
||||
|
||||
Declaration* vdec = new Declaration(exp->mLocation, DT_VARIABLE);
|
||||
|
||||
vdec->mVarIndex = nindex;
|
||||
vdec->mBase = pdec->mBase->mBase;
|
||||
vdec->mSize = pdec->mBase->mBase->mSize;
|
||||
|
||||
Expression* vexp = new Expression(pex->mLocation, EX_VARIABLE);
|
||||
vexp->mDecType = pdec->mBase->mBase;
|
||||
vexp->mDecValue = vdec;
|
||||
|
||||
Expression* cexp = new Expression(pex->mLocation, pex->mType);
|
||||
cexp->mDecType = pex->mDecType;
|
||||
cexp->mDecValue = pex->mDecValue;
|
||||
cexp->mLeft = pex->mLeft;
|
||||
cexp->mRight = pex->mRight;
|
||||
cexp->mToken = pex->mToken;
|
||||
|
||||
pex->mType = EX_INITIALIZATION;
|
||||
pex->mToken = TK_ASSIGN;
|
||||
pex->mLeft = vexp;
|
||||
pex->mRight = cexp;
|
||||
pex->mDecValue = nullptr;
|
||||
pex->mDecType = vdec->mBase;
|
||||
}
|
||||
}
|
||||
|
||||
pdec = pdec->mNext;
|
||||
}
|
||||
|
@ -4108,7 +4192,15 @@ Expression* Parser::ParseDeclarationExpression(Declaration * pdec)
|
|||
|
||||
Declaration* Parser::ParseQualIdent(void)
|
||||
{
|
||||
Declaration* dec = mScope->Lookup(mScanner->mTokenIdent);
|
||||
Declaration* dec = nullptr;
|
||||
if (mTemplateScope)
|
||||
{
|
||||
dec = mTemplateScope->Lookup(mScanner->mTokenIdent);
|
||||
}
|
||||
|
||||
if (!dec)
|
||||
dec = mScope->Lookup(mScanner->mTokenIdent);
|
||||
|
||||
if (dec)
|
||||
{
|
||||
mScanner->NextToken();
|
||||
|
@ -4371,6 +4463,9 @@ Expression* Parser::ParseSimpleExpression(bool lhs)
|
|||
dec = ParseQualIdent();
|
||||
if (dec)
|
||||
{
|
||||
if (dec->mType == DT_TEMPLATE)
|
||||
dec = ParseTemplateExpansion(dec, nullptr);
|
||||
|
||||
if (dec->mType == DT_CONST_INTEGER || dec->mType == DT_CONST_FLOAT || dec->mType == DT_CONST_FUNCTION || dec->mType == DT_CONST_ASSEMBLER || dec->mType == DT_LABEL || dec->mType == DT_LABEL_REF)
|
||||
{
|
||||
exp = new Expression(mScanner->mLocation, EX_CONSTANT);
|
||||
|
@ -6980,10 +7075,153 @@ Expression* Parser::ParseSwitchStatement(void)
|
|||
return sexp;
|
||||
}
|
||||
|
||||
void Parser::ParseTemplate(void)
|
||||
Declaration* Parser::ParseTemplateExpansion(Declaration* tmpld, Declaration* expd)
|
||||
{
|
||||
|
||||
Declaration * tdec = new Declaration(mScanner->mLocation, DT_TEMPLATE);
|
||||
tdec->mScope = new DeclarationScope(nullptr, SLEVEL_TEMPLATE);
|
||||
|
||||
if (expd)
|
||||
{
|
||||
tdec->mParams = expd->mParams;
|
||||
Declaration* dec = tdec->mParams;
|
||||
while (dec)
|
||||
{
|
||||
tdec->mScope->Insert(dec->mIdent, dec->mBase);
|
||||
dec = dec->mNext;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ConsumeToken(TK_LESS_THAN);
|
||||
|
||||
Declaration* ppdec = nullptr;
|
||||
Declaration* pdec = tmpld->mParams;
|
||||
while (pdec)
|
||||
{
|
||||
Declaration* epdec = pdec->Clone();
|
||||
Expression* exp = ParseShiftExpression(false);
|
||||
|
||||
if (epdec->mType == DT_TYPE_TEMPLATE)
|
||||
{
|
||||
if (exp->mType == EX_TYPE)
|
||||
epdec->mBase = exp->mDecType;
|
||||
else
|
||||
mErrors->Error(exp->mLocation, EERR_TEMPLATE_PARAMS, "Type parameter expected", pdec->mIdent);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
|
||||
epdec->mBase = exp->mDecValue;
|
||||
else
|
||||
mErrors->Error(exp->mLocation, EERR_TEMPLATE_PARAMS, "Const integer parameter expected", pdec->mIdent);
|
||||
}
|
||||
|
||||
tdec->mScope->Insert(epdec->mIdent, epdec->mBase);
|
||||
epdec->mFlags |= DTF_DEFINED;
|
||||
|
||||
if (ppdec)
|
||||
ppdec->mNext = epdec;
|
||||
else
|
||||
tdec->mParams = epdec;
|
||||
ppdec = epdec;
|
||||
|
||||
pdec = pdec->mNext;
|
||||
if (pdec)
|
||||
ConsumeToken(TK_COMMA);
|
||||
}
|
||||
|
||||
ConsumeToken(TK_GREATER_THAN);
|
||||
}
|
||||
|
||||
Declaration* etdec = tmpld->mNext;
|
||||
while (etdec && !etdec->IsSameParams(tdec))
|
||||
etdec = etdec->mNext;
|
||||
if (etdec)
|
||||
{
|
||||
return etdec->mBase;
|
||||
}
|
||||
else
|
||||
{
|
||||
Parser* p = tmpld->mParser;
|
||||
|
||||
p->mScanner->Replay(tmpld->mTokens);
|
||||
|
||||
tdec->mScope->mName = tdec->MangleIdent();
|
||||
|
||||
p->mTemplateScope = tdec->mScope;
|
||||
tdec->mBase = p->ParseDeclaration(nullptr, true, false);
|
||||
p->mTemplateScope = nullptr;
|
||||
|
||||
tdec->mNext = tmpld->mNext;
|
||||
tmpld->mNext = tdec;
|
||||
|
||||
if (tdec->mBase->mType == DT_ANON)
|
||||
{
|
||||
tdec->mBase = tdec->mBase->mBase;
|
||||
mCompilationUnits->mTemplateScope->Insert(tmpld->mQualIdent, tmpld);
|
||||
|
||||
tdec->mBase->mScope->Iterate([=](const Ident* ident, Declaration* mdec)
|
||||
{
|
||||
if (mdec->mType == DT_CONST_FUNCTION)
|
||||
{
|
||||
while (mdec)
|
||||
{
|
||||
if (!(mdec->mFlags & DTF_DEFINED))
|
||||
{
|
||||
Declaration* mpdec = mScope->Lookup(tmpld->mScope->Mangle(mdec->mIdent));
|
||||
if (mpdec && mpdec->mType == DT_TEMPLATE)
|
||||
{
|
||||
p->ParseTemplateExpansion(mpdec, tdec);
|
||||
}
|
||||
}
|
||||
|
||||
mdec = mdec->mNext;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return tdec->mBase;
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::CompleteTemplateExpansion(Declaration* tmpld)
|
||||
{
|
||||
tmpld = tmpld->mNext;
|
||||
while (tmpld)
|
||||
{
|
||||
if (tmpld->mBase->mType == DT_TYPE_STRUCT)
|
||||
{
|
||||
// now expand the templated members
|
||||
|
||||
tmpld->mBase->mScope->Iterate([=](const Ident* ident, Declaration* mdec)
|
||||
{
|
||||
if (mdec->mType == DT_CONST_FUNCTION)
|
||||
{
|
||||
while (mdec)
|
||||
{
|
||||
Declaration* mpdec = mScope->Lookup(mdec->mQualIdent);
|
||||
if (mpdec && mpdec->mType == DT_TEMPLATE)
|
||||
{
|
||||
ParseTemplateExpansion(mpdec, tmpld);
|
||||
}
|
||||
|
||||
mdec = mdec->mNext;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Parser::ParseTemplateDeclaration(void)
|
||||
{
|
||||
ConsumeToken(TK_LESS_THAN);
|
||||
Declaration* tdec = new Declaration(mScanner->mLocation, DT_TEMPLATE);
|
||||
tdec->mParser = this->Clone();
|
||||
tdec->mScope = new DeclarationScope(nullptr, SLEVEL_TEMPLATE);
|
||||
Declaration* ppdec = nullptr;
|
||||
|
||||
for (;;)
|
||||
|
@ -6994,9 +7232,8 @@ void Parser::ParseTemplate(void)
|
|||
{
|
||||
if (mScanner->mToken == TK_IDENT)
|
||||
{
|
||||
Declaration* pdec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
|
||||
pdec = new Declaration(mScanner->mLocation, DT_TYPE_TEMPLATE);
|
||||
pdec->mIdent = mScanner->mTokenIdent;
|
||||
pdec->mBase = TheVoidTypeDeclaration;
|
||||
mScanner->NextToken();
|
||||
}
|
||||
else
|
||||
|
@ -7006,9 +7243,8 @@ void Parser::ParseTemplate(void)
|
|||
{
|
||||
if (mScanner->mToken == TK_IDENT)
|
||||
{
|
||||
Declaration* pdec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
|
||||
pdec = new Declaration(mScanner->mLocation, DT_CONST_TEMPLATE);
|
||||
pdec->mIdent = mScanner->mTokenIdent;
|
||||
pdec->mBase = TheSignedIntTypeDeclaration;
|
||||
mScanner->NextToken();
|
||||
}
|
||||
else
|
||||
|
@ -7019,6 +7255,9 @@ void Parser::ParseTemplate(void)
|
|||
|
||||
if (pdec)
|
||||
{
|
||||
tdec->mScope->Insert(pdec->mIdent, pdec);
|
||||
pdec->mFlags |= DTF_DEFINED;
|
||||
|
||||
if (ppdec)
|
||||
ppdec->mNext = pdec;
|
||||
else
|
||||
|
@ -7032,17 +7271,87 @@ void Parser::ParseTemplate(void)
|
|||
|
||||
ConsumeToken(TK_GREATER_THAN);
|
||||
|
||||
mScanner->BeginRecord();
|
||||
if (mScanner->mToken == TK_CLASS)
|
||||
{
|
||||
// Class template
|
||||
Declaration* bdec = new Declaration(mScanner->mLocation, DT_TYPE_STRUCT);
|
||||
tdec->mBase = bdec;
|
||||
|
||||
mScanner->NextToken();
|
||||
if (mScanner->mToken == TK_IDENT)
|
||||
{
|
||||
bdec->mIdent = mScanner->mTokenIdent;
|
||||
bdec->mQualIdent = mScope->Mangle(bdec->mIdent);
|
||||
|
||||
while (mScanner->mToken != TK_SEMICOLON && mScanner->mToken != TK_OPEN_BRACE)
|
||||
mScanner->NextToken();
|
||||
|
||||
if (ConsumeTokenIf(TK_OPEN_BRACE))
|
||||
{
|
||||
int qdepth = 1;
|
||||
while (qdepth)
|
||||
{
|
||||
if (ConsumeTokenIf(TK_OPEN_BRACE))
|
||||
qdepth++;
|
||||
else if (ConsumeTokenIf(TK_CLOSE_BRACE))
|
||||
qdepth--;
|
||||
else
|
||||
mScanner->NextToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
mErrors->Error(bdec->mLocation, EERR_FUNCTION_TEMPLATE, "Class template expected");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Function template
|
||||
mTemplateScope = tdec->mScope;
|
||||
|
||||
Declaration* bdec = ParseBaseTypeDeclaration(0, false);
|
||||
Declaration* adec = ParsePostfixDeclaration();
|
||||
|
||||
adec = ReverseDeclaration(adec, bdec);
|
||||
|
||||
mTemplateScope = nullptr;
|
||||
|
||||
if (adec->mBase->mType == DT_TYPE_FUNCTION)
|
||||
{
|
||||
adec->mType = DT_CONST_FUNCTION;
|
||||
adec->mSection = mCodeSection;
|
||||
|
||||
if (mCompilerOptions & COPT_NATIVE)
|
||||
adec->mFlags |= DTF_NATIVE;
|
||||
|
||||
tdec->mBase = adec;
|
||||
|
||||
if (ConsumeTokenIf(TK_OPEN_BRACE))
|
||||
{
|
||||
int qdepth = 1;
|
||||
while (qdepth)
|
||||
{
|
||||
if (ConsumeTokenIf(TK_OPEN_BRACE))
|
||||
qdepth++;
|
||||
else if (ConsumeTokenIf(TK_CLOSE_BRACE))
|
||||
qdepth--;
|
||||
else
|
||||
mScanner->NextToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
mErrors->Error(bdec->mLocation, EERR_FUNCTION_TEMPLATE, "Function template expected");
|
||||
}
|
||||
|
||||
tdec->mTokens = mScanner->CompleteRecord();
|
||||
|
||||
tdec->mIdent = tdec->mBase->mIdent;
|
||||
tdec->mQualIdent = tdec->mBase->mQualIdent;
|
||||
tdec->mScope->mName = tdec->mQualIdent;
|
||||
|
||||
mScope->Insert(tdec->mQualIdent, tdec);
|
||||
}
|
||||
|
||||
|
||||
Expression* Parser::ParseAssemblerBaseOperand(Declaration* pcasm, int pcoffset)
|
||||
|
@ -8673,7 +8982,7 @@ void Parser::Parse(void)
|
|||
else if (mScanner->mToken == TK_TEMPLATE)
|
||||
{
|
||||
mScanner->NextToken();
|
||||
ParseTemplate();
|
||||
ParseTemplateDeclaration();
|
||||
}
|
||||
else if (mScanner->mToken == TK_NAMESPACE)
|
||||
{
|
||||
|
|
|
@ -10,7 +10,9 @@ public:
|
|||
Parser(Errors * errors, Scanner* scanner, CompilationUnits * compilationUnits);
|
||||
~Parser(void);
|
||||
|
||||
DeclarationScope * mGlobals, * mScope;
|
||||
Parser* Clone(void);
|
||||
|
||||
DeclarationScope * mGlobals, * mScope, * mTemplateScope;
|
||||
int mLocalIndex;
|
||||
CompilationUnits * mCompilationUnits;
|
||||
Declaration * mThisPointer, * mReturnType;
|
||||
|
@ -93,7 +95,9 @@ protected:
|
|||
bool CanCoerceExpression(Expression* exp, Declaration* type);
|
||||
void CompleteFunctionDefaultParams(Expression* exp);
|
||||
|
||||
void ParseTemplate(void);
|
||||
void ParseTemplateDeclaration(void);
|
||||
Declaration* ParseTemplateExpansion(Declaration* tmpld, Declaration* expd);
|
||||
void CompleteTemplateExpansion(Declaration* tmpld);
|
||||
|
||||
Expression* ParseSimpleExpression(bool lhs);
|
||||
Expression* ParsePrefixExpression(bool lhs);
|
||||
|
|
|
@ -309,7 +309,7 @@ Macro* MacroDict::Lookup(const Ident* ident)
|
|||
|
||||
TokenSequence::TokenSequence(Scanner* scanner)
|
||||
: mNext(nullptr), mLocation(scanner->mLocation), mToken(scanner->mToken),
|
||||
mTokenIdent(scanner->mTokenIdent), mTokenChar(scanner->mTokenChar),
|
||||
mTokenIdent(scanner->mTokenIdent),
|
||||
mTokenInteger(scanner->mTokenInteger), mTokenNumber(scanner->mTokenNumber),
|
||||
mTokenString(nullptr)
|
||||
{
|
||||
|
@ -345,6 +345,7 @@ Scanner::Scanner(Errors* errors, Preprocessor* preprocessor)
|
|||
mToken = TK_NONE;
|
||||
mUngetToken = TK_NONE;
|
||||
mReplay = nullptr;
|
||||
mRecord = mRecordLast = nullptr;
|
||||
|
||||
mOnceDict = new MacroDict();
|
||||
|
||||
|
@ -359,15 +360,23 @@ Scanner::~Scanner(void)
|
|||
}
|
||||
|
||||
|
||||
TokenSequence* Scanner::Record(void)
|
||||
void Scanner::BeginRecord(void)
|
||||
{
|
||||
return new TokenSequence(this);
|
||||
mRecord = mRecordLast = new TokenSequence(this);
|
||||
}
|
||||
|
||||
TokenSequence* Scanner::CompleteRecord(void)
|
||||
{
|
||||
TokenSequence* seq = mRecord;
|
||||
mRecord = mRecordLast = nullptr;
|
||||
return seq;
|
||||
}
|
||||
|
||||
const TokenSequence* Scanner::Replay(const TokenSequence* replay)
|
||||
{
|
||||
const TokenSequence* seq = mReplay;
|
||||
mReplay = replay;
|
||||
NextToken();
|
||||
return seq;
|
||||
}
|
||||
|
||||
|
@ -463,16 +472,27 @@ void Scanner::NextToken(void)
|
|||
mToken = mReplay->mToken;
|
||||
|
||||
mTokenIdent = mReplay->mTokenIdent;
|
||||
mTokenChar = mReplay->mTokenChar;
|
||||
mTokenNumber = mReplay->mTokenNumber;
|
||||
mTokenInteger = mReplay->mTokenInteger;
|
||||
if (mReplay->mTokenString)
|
||||
strcpy_s(mTokenString, mReplay->mTokenString);
|
||||
|
||||
mReplay = mReplay->mNext;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
NextPreToken();
|
||||
|
||||
if (mRecord)
|
||||
{
|
||||
mRecordLast->mNext = new TokenSequence(this);
|
||||
mRecordLast = mRecordLast->mNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Scanner::NextPreToken(void)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
NextRawToken();
|
||||
|
|
|
@ -214,7 +214,6 @@ struct TokenSequence
|
|||
Token mToken;
|
||||
|
||||
const Ident * mTokenIdent;
|
||||
char mTokenChar;
|
||||
const char * mTokenString;
|
||||
double mTokenNumber;
|
||||
int64 mTokenInteger;
|
||||
|
@ -233,7 +232,9 @@ public:
|
|||
|
||||
void NextToken(void);
|
||||
|
||||
TokenSequence* Record(void);
|
||||
void BeginRecord(void);
|
||||
TokenSequence* CompleteRecord(void);
|
||||
|
||||
const TokenSequence* Replay(const TokenSequence * sequence);
|
||||
|
||||
void Warning(const char * error);
|
||||
|
@ -272,6 +273,7 @@ public:
|
|||
void MarkSourceOnce(void);
|
||||
protected:
|
||||
void NextRawToken(void);
|
||||
void NextPreToken(void);
|
||||
|
||||
struct MacroExpansion
|
||||
{
|
||||
|
@ -289,6 +291,7 @@ protected:
|
|||
Token mUngetToken;
|
||||
|
||||
const TokenSequence* mReplay;
|
||||
TokenSequence* mRecord, * mRecordLast;
|
||||
|
||||
void StringToken(char terminator, char mode);
|
||||
void CharToken(char mode);
|
||||
|
|
Loading…
Reference in New Issue