mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 02:06:35 +01:00
Remerged dmd2 frontend using git subtree
This commit is contained in:
412
dmd2/access.c
Normal file
412
dmd2/access.c
Normal file
@@ -0,0 +1,412 @@
|
||||
|
||||
// Copyright (c) 1999-2012 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "root.h"
|
||||
#include "rmem.h"
|
||||
|
||||
#include "enum.h"
|
||||
#include "aggregate.h"
|
||||
#include "init.h"
|
||||
#include "attrib.h"
|
||||
#include "scope.h"
|
||||
#include "id.h"
|
||||
#include "mtype.h"
|
||||
#include "declaration.h"
|
||||
#include "aggregate.h"
|
||||
#include "expression.h"
|
||||
#include "module.h"
|
||||
|
||||
#define LOG 0
|
||||
|
||||
/* Code to do access checks
|
||||
*/
|
||||
|
||||
int hasPackageAccess(Scope *sc, Dsymbol *s);
|
||||
|
||||
/****************************************
|
||||
* Return PROT access for Dsymbol smember in this declaration.
|
||||
*/
|
||||
|
||||
enum PROT AggregateDeclaration::getAccess(Dsymbol *smember)
|
||||
{
|
||||
return PROTpublic;
|
||||
}
|
||||
|
||||
enum PROT StructDeclaration::getAccess(Dsymbol *smember)
|
||||
{
|
||||
enum PROT access_ret = PROTnone;
|
||||
|
||||
#if LOG
|
||||
printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n",
|
||||
toChars(), smember->toChars());
|
||||
#endif
|
||||
if (smember->toParent() == this)
|
||||
{
|
||||
access_ret = smember->prot();
|
||||
}
|
||||
else if (smember->isDeclaration()->isStatic())
|
||||
{
|
||||
access_ret = smember->prot();
|
||||
}
|
||||
return access_ret;
|
||||
}
|
||||
|
||||
enum PROT ClassDeclaration::getAccess(Dsymbol *smember)
|
||||
{
|
||||
enum PROT access_ret = PROTnone;
|
||||
|
||||
#if LOG
|
||||
printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
|
||||
toChars(), smember->toChars());
|
||||
#endif
|
||||
if (smember->toParent() == this)
|
||||
{
|
||||
access_ret = smember->prot();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (smember->isDeclaration()->isStatic())
|
||||
{
|
||||
access_ret = smember->prot();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < baseclasses->dim; i++)
|
||||
{ BaseClass *b = (*baseclasses)[i];
|
||||
|
||||
enum PROT access = b->base->getAccess(smember);
|
||||
switch (access)
|
||||
{
|
||||
case PROTnone:
|
||||
break;
|
||||
|
||||
case PROTprivate:
|
||||
access_ret = PROTnone; // private members of base class not accessible
|
||||
break;
|
||||
|
||||
case PROTpackage:
|
||||
case PROTprotected:
|
||||
case PROTpublic:
|
||||
case PROTexport:
|
||||
// If access is to be tightened
|
||||
if (b->protection < access)
|
||||
access = b->protection;
|
||||
|
||||
// Pick path with loosest access
|
||||
if (access > access_ret)
|
||||
access_ret = access;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if LOG
|
||||
printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
|
||||
toChars(), smember->toChars(), access_ret);
|
||||
#endif
|
||||
return access_ret;
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* Helper function for ClassDeclaration::accessCheck()
|
||||
* Returns:
|
||||
* 0 no access
|
||||
* 1 access
|
||||
*/
|
||||
|
||||
static int accessCheckX(
|
||||
Dsymbol *smember,
|
||||
Dsymbol *sfunc,
|
||||
AggregateDeclaration *dthis,
|
||||
AggregateDeclaration *cdscope)
|
||||
{
|
||||
assert(dthis);
|
||||
|
||||
#if 0
|
||||
printf("accessCheckX for %s.%s in function %s() in scope %s\n",
|
||||
dthis->toChars(), smember->toChars(),
|
||||
sfunc ? sfunc->toChars() : "NULL",
|
||||
cdscope ? cdscope->toChars() : "NULL");
|
||||
#endif
|
||||
if (dthis->hasPrivateAccess(sfunc) ||
|
||||
dthis->isFriendOf(cdscope))
|
||||
{
|
||||
if (smember->toParent() == dthis)
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
ClassDeclaration *cdthis = dthis->isClassDeclaration();
|
||||
if (cdthis)
|
||||
{
|
||||
for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
|
||||
{ BaseClass *b = (*cdthis->baseclasses)[i];
|
||||
enum PROT access = b->base->getAccess(smember);
|
||||
if (access >= PROTprotected ||
|
||||
accessCheckX(smember, sfunc, b->base, cdscope)
|
||||
)
|
||||
return 1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (smember->toParent() != dthis)
|
||||
{
|
||||
ClassDeclaration *cdthis = dthis->isClassDeclaration();
|
||||
if (cdthis)
|
||||
{
|
||||
for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
|
||||
{ BaseClass *b = (*cdthis->baseclasses)[i];
|
||||
|
||||
if (accessCheckX(smember, sfunc, b->base, cdscope))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
* Do access check for member of this class, this class being the
|
||||
* type of the 'this' pointer used to access smember.
|
||||
*/
|
||||
|
||||
void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
|
||||
{
|
||||
int result;
|
||||
|
||||
FuncDeclaration *f = sc->func;
|
||||
AggregateDeclaration *cdscope = sc->getStructClassScope();
|
||||
enum PROT access;
|
||||
|
||||
#if LOG
|
||||
printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
|
||||
toChars(), smember->toChars(),
|
||||
f ? f->toChars() : NULL,
|
||||
cdscope ? cdscope->toChars() : NULL);
|
||||
#endif
|
||||
|
||||
Dsymbol *smemberparent = smember->toParent();
|
||||
if (!smemberparent || !smemberparent->isAggregateDeclaration())
|
||||
{
|
||||
#if LOG
|
||||
printf("not an aggregate member\n");
|
||||
#endif
|
||||
return; // then it is accessible
|
||||
}
|
||||
|
||||
// BUG: should enable this check
|
||||
//assert(smember->parent->isBaseOf(this, NULL));
|
||||
|
||||
if (smemberparent == this)
|
||||
{ enum PROT access2 = smember->prot();
|
||||
|
||||
result = access2 >= PROTpublic ||
|
||||
hasPrivateAccess(f) ||
|
||||
isFriendOf(cdscope) ||
|
||||
(access2 == PROTpackage && hasPackageAccess(sc, this));
|
||||
#if LOG
|
||||
printf("result1 = %d\n", result);
|
||||
#endif
|
||||
}
|
||||
else if ((access = this->getAccess(smember)) >= PROTpublic)
|
||||
{
|
||||
result = 1;
|
||||
#if LOG
|
||||
printf("result2 = %d\n", result);
|
||||
#endif
|
||||
}
|
||||
else if (access == PROTpackage && hasPackageAccess(sc, this))
|
||||
{
|
||||
result = 1;
|
||||
#if LOG
|
||||
printf("result3 = %d\n", result);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
result = accessCheckX(smember, f, this, cdscope);
|
||||
#if LOG
|
||||
printf("result4 = %d\n", result);
|
||||
#endif
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
error(loc, "member %s is not accessible", smember->toChars());
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Determine if this is the same or friend of cd.
|
||||
*/
|
||||
|
||||
int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd)
|
||||
{
|
||||
#if LOG
|
||||
printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null");
|
||||
#endif
|
||||
if (this == cd)
|
||||
return 1;
|
||||
|
||||
// Friends if both are in the same module
|
||||
//if (toParent() == cd->toParent())
|
||||
if (cd && getAccessModule() == cd->getAccessModule())
|
||||
{
|
||||
#if LOG
|
||||
printf("\tin same module\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if LOG
|
||||
printf("\tnot friend\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Determine if scope sc has package level access to s.
|
||||
*/
|
||||
|
||||
int hasPackageAccess(Scope *sc, Dsymbol *s)
|
||||
{
|
||||
#if LOG
|
||||
printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc);
|
||||
#endif
|
||||
|
||||
for (; s; s = s->parent)
|
||||
{
|
||||
if (s->isPackage() && !s->isModule())
|
||||
break;
|
||||
}
|
||||
#if LOG
|
||||
if (s)
|
||||
printf("\tthis is in package '%s'\n", s->toChars());
|
||||
#endif
|
||||
|
||||
if (s && s == sc->module->parent)
|
||||
{
|
||||
#if LOG
|
||||
printf("\ts is in same package as sc\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#if LOG
|
||||
printf("\tno package access\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Determine if smember has access to private members of this declaration.
|
||||
*/
|
||||
|
||||
int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember)
|
||||
{
|
||||
if (smember)
|
||||
{ AggregateDeclaration *cd = NULL;
|
||||
Dsymbol *smemberparent = smember->toParent();
|
||||
if (smemberparent)
|
||||
cd = smemberparent->isAggregateDeclaration();
|
||||
|
||||
#if LOG
|
||||
printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n",
|
||||
toChars(), smember->toChars());
|
||||
#endif
|
||||
|
||||
if (this == cd) // smember is a member of this class
|
||||
{
|
||||
#if LOG
|
||||
printf("\tyes 1\n");
|
||||
#endif
|
||||
return 1; // so we get private access
|
||||
}
|
||||
|
||||
// If both are members of the same module, grant access
|
||||
while (1)
|
||||
{ Dsymbol *sp = smember->toParent();
|
||||
if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
|
||||
smember = sp;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (!cd && toParent() == smember->toParent())
|
||||
{
|
||||
#if LOG
|
||||
printf("\tyes 2\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
if (!cd && getAccessModule() == smember->getAccessModule())
|
||||
{
|
||||
#if LOG
|
||||
printf("\tyes 3\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#if LOG
|
||||
printf("\tno\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Check access to d for expression e.d
|
||||
*/
|
||||
|
||||
void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d)
|
||||
{
|
||||
#if LOG
|
||||
if (e)
|
||||
{ printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars());
|
||||
printf("\te->type = %s\n", e->type->toChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("accessCheck(%s)\n", d->toPrettyChars());
|
||||
}
|
||||
#endif
|
||||
if (!e)
|
||||
{
|
||||
if (d->prot() == PROTprivate && d->getAccessModule() != sc->module ||
|
||||
d->prot() == PROTpackage && !hasPackageAccess(sc, d))
|
||||
{
|
||||
error(loc, "%s %s is not accessible from module %s",
|
||||
d->kind(), d->toPrettyChars(), sc->module->toChars());
|
||||
}
|
||||
}
|
||||
else if (e->type->ty == Tclass)
|
||||
{ // Do access check
|
||||
ClassDeclaration *cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
|
||||
if (e->op == TOKsuper)
|
||||
{
|
||||
ClassDeclaration *cd2 = sc->func->toParent()->isClassDeclaration();
|
||||
if (cd2)
|
||||
cd = cd2;
|
||||
}
|
||||
cd->accessCheck(loc, sc, d);
|
||||
}
|
||||
else if (e->type->ty == Tstruct)
|
||||
{ // Do access check
|
||||
StructDeclaration *cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
|
||||
cd->accessCheck(loc, sc, d);
|
||||
}
|
||||
}
|
||||
363
dmd2/aggregate.h
Normal file
363
dmd2/aggregate.h
Normal file
@@ -0,0 +1,363 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_AGGREGATE_H
|
||||
#define DMD_AGGREGATE_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
#include "root.h"
|
||||
|
||||
#include "dsymbol.h"
|
||||
|
||||
#if IN_LLVM
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#endif
|
||||
|
||||
struct Identifier;
|
||||
struct Type;
|
||||
struct TypeFunction;
|
||||
struct Expression;
|
||||
struct FuncDeclaration;
|
||||
struct CtorDeclaration;
|
||||
struct DtorDeclaration;
|
||||
struct InvariantDeclaration;
|
||||
struct NewDeclaration;
|
||||
struct DeleteDeclaration;
|
||||
struct InterfaceDeclaration;
|
||||
struct TypeInfoClassDeclaration;
|
||||
struct VarDeclaration;
|
||||
struct dt_t;
|
||||
|
||||
#if IN_LLVM
|
||||
struct ClassInfoDeclaration;
|
||||
namespace llvm
|
||||
{
|
||||
class Type;
|
||||
class Value;
|
||||
class Constant;
|
||||
class ConstantStruct;
|
||||
class GlobalVariable;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct AggregateDeclaration : ScopeDsymbol
|
||||
{
|
||||
Type *type;
|
||||
StorageClass storage_class;
|
||||
enum PROT protection;
|
||||
Type *handle; // 'this' type
|
||||
unsigned structsize; // size of struct
|
||||
unsigned alignsize; // size of struct for alignment purposes
|
||||
unsigned structalign; // struct member alignment in effect
|
||||
int hasUnions; // set if aggregate has overlapping fields
|
||||
VarDeclarations fields; // VarDeclaration fields
|
||||
unsigned sizeok; // set when structsize contains valid data
|
||||
// 0: no size
|
||||
// 1: size is correct
|
||||
// 2: cannot determine size; fwd referenced
|
||||
Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol
|
||||
bool isdeprecated; // !=0 if deprecated
|
||||
|
||||
#if DMDV2
|
||||
int isnested; // !=0 if is nested
|
||||
VarDeclaration *vthis; // 'this' parameter if this aggregate is nested
|
||||
#endif
|
||||
// Special member functions
|
||||
InvariantDeclaration *inv; // invariant
|
||||
NewDeclaration *aggNew; // allocator
|
||||
DeleteDeclaration *aggDelete; // deallocator
|
||||
|
||||
#if DMDV2
|
||||
//CtorDeclaration *ctor;
|
||||
Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration
|
||||
CtorDeclaration *defaultCtor; // default constructor
|
||||
Dsymbol *aliasthis; // forward unresolved lookups to aliasthis
|
||||
bool noDefaultCtor; // no default construction
|
||||
#endif
|
||||
|
||||
FuncDeclarations dtors; // Array of destructors
|
||||
FuncDeclaration *dtor; // aggregate destructor
|
||||
|
||||
#ifdef IN_GCC
|
||||
Array methods; // flat list of all methods for debug information
|
||||
#endif
|
||||
|
||||
AggregateDeclaration(Loc loc, Identifier *id);
|
||||
void semantic2(Scope *sc);
|
||||
void semantic3(Scope *sc);
|
||||
void inlineScan();
|
||||
unsigned size(Loc loc);
|
||||
static void alignmember(unsigned salign, unsigned size, unsigned *poffset);
|
||||
Type *getType();
|
||||
void addField(Scope *sc, VarDeclaration *v);
|
||||
int firstFieldInUnion(int indx); // first field in union that includes indx
|
||||
int numFieldsInUnion(int firstIndex); // #fields in union starting at index
|
||||
int isDeprecated(); // is aggregate deprecated?
|
||||
FuncDeclaration *buildDtor(Scope *sc);
|
||||
int isNested();
|
||||
int isExport();
|
||||
|
||||
void emitComment(Scope *sc);
|
||||
void toJsonBuffer(OutBuffer *buf);
|
||||
void toDocBuffer(OutBuffer *buf);
|
||||
|
||||
// For access checking
|
||||
virtual PROT getAccess(Dsymbol *smember); // determine access to smember
|
||||
int isFriendOf(AggregateDeclaration *cd);
|
||||
int hasPrivateAccess(Dsymbol *smember); // does smember have private access to members of this class?
|
||||
void accessCheck(Loc loc, Scope *sc, Dsymbol *smember);
|
||||
|
||||
enum PROT prot();
|
||||
|
||||
#if IN_DMD
|
||||
// Back end
|
||||
Symbol *stag; // tag symbol for debug data
|
||||
Symbol *sinit;
|
||||
Symbol *toInitializer();
|
||||
#endif
|
||||
|
||||
AggregateDeclaration *isAggregateDeclaration() { return this; }
|
||||
|
||||
#if IN_LLVM
|
||||
// Aggregates that wouldn't have gotten semantic3'ed if we weren't inlining set this flag.
|
||||
bool availableExternally;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct AnonymousAggregateDeclaration : AggregateDeclaration
|
||||
{
|
||||
AnonymousAggregateDeclaration()
|
||||
: AggregateDeclaration(0, NULL)
|
||||
{
|
||||
}
|
||||
|
||||
AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; }
|
||||
};
|
||||
|
||||
struct StructDeclaration : AggregateDeclaration
|
||||
{
|
||||
int zeroInit; // !=0 if initialize with 0 fill
|
||||
#if DMDV2
|
||||
int hasIdentityAssign; // !=0 if has identity opAssign
|
||||
int hasIdentityEquals; // !=0 if has identity opEquals
|
||||
FuncDeclaration *cpctor; // generated copy-constructor, if any
|
||||
FuncDeclarations postblits; // Array of postblit functions
|
||||
FuncDeclaration *postblit; // aggregate postblit
|
||||
|
||||
FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals
|
||||
static FuncDeclaration *xerreq; // object.xopEquals
|
||||
#endif
|
||||
|
||||
StructDeclaration(Loc loc, Identifier *id);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void semantic(Scope *sc);
|
||||
Dsymbol *search(Loc, Identifier *ident, int flags);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
char *mangle();
|
||||
const char *kind();
|
||||
void finalizeSize();
|
||||
#if DMDV1
|
||||
Expression *cloneMembers();
|
||||
#endif
|
||||
#if DMDV2
|
||||
int needOpAssign();
|
||||
int needOpEquals();
|
||||
FuncDeclaration *buildOpAssign(Scope *sc);
|
||||
FuncDeclaration *buildOpEquals(Scope *sc);
|
||||
FuncDeclaration *buildPostBlit(Scope *sc);
|
||||
FuncDeclaration *buildCpCtor(Scope *sc);
|
||||
|
||||
FuncDeclaration *buildXopEquals(Scope *sc);
|
||||
#endif
|
||||
void toDocBuffer(OutBuffer *buf);
|
||||
|
||||
PROT getAccess(Dsymbol *smember); // determine access to smember
|
||||
|
||||
#if IN_DMD
|
||||
void toObjFile(int multiobj); // compile to .obj file
|
||||
void toDt(dt_t **pdt);
|
||||
void toDebug(); // to symbolic debug info
|
||||
#endif
|
||||
|
||||
StructDeclaration *isStructDeclaration() { return this; }
|
||||
|
||||
#if IN_LLVM
|
||||
void codegen(Ir*);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct UnionDeclaration : StructDeclaration
|
||||
{
|
||||
UnionDeclaration(Loc loc, Identifier *id);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
const char *kind();
|
||||
|
||||
UnionDeclaration *isUnionDeclaration() { return this; }
|
||||
};
|
||||
|
||||
// warning: two classes with the same base class share the same
|
||||
// BaseClass instance.
|
||||
struct BaseClass
|
||||
{
|
||||
Type *type; // (before semantic processing)
|
||||
enum PROT protection; // protection for the base interface
|
||||
|
||||
ClassDeclaration *base;
|
||||
int offset; // 'this' pointer offset
|
||||
FuncDeclarations vtbl; // for interfaces: Array of FuncDeclaration's
|
||||
// making up the vtbl[]
|
||||
|
||||
size_t baseInterfaces_dim;
|
||||
BaseClass *baseInterfaces; // if BaseClass is an interface, these
|
||||
// are a copy of the InterfaceDeclaration::interfaces
|
||||
|
||||
BaseClass();
|
||||
BaseClass(Type *type, enum PROT protection);
|
||||
|
||||
int fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance);
|
||||
void copyBaseInterfaces(BaseClasses *);
|
||||
};
|
||||
|
||||
#if DMDV2
|
||||
#define CLASSINFO_SIZE_64 0x98 // value of ClassInfo.size
|
||||
#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size
|
||||
#else
|
||||
#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size
|
||||
#endif
|
||||
|
||||
struct ClassDeclaration : AggregateDeclaration
|
||||
{
|
||||
static ClassDeclaration *object;
|
||||
static ClassDeclaration *classinfo;
|
||||
static ClassDeclaration *throwable;
|
||||
static ClassDeclaration *exception;
|
||||
static ClassDeclaration *errorException;
|
||||
|
||||
ClassDeclaration *baseClass; // NULL only if this is Object
|
||||
#if DMDV1
|
||||
CtorDeclaration *ctor;
|
||||
CtorDeclaration *defaultCtor; // default constructor
|
||||
#endif
|
||||
FuncDeclaration *staticCtor;
|
||||
FuncDeclaration *staticDtor;
|
||||
Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[]
|
||||
Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[]
|
||||
|
||||
BaseClasses *baseclasses; // Array of BaseClass's; first is super,
|
||||
// rest are Interface's
|
||||
|
||||
size_t interfaces_dim;
|
||||
BaseClass **interfaces; // interfaces[interfaces_dim] for this class
|
||||
// (does not include baseClass)
|
||||
|
||||
BaseClasses *vtblInterfaces; // array of base interfaces that have
|
||||
// their own vtbl[]
|
||||
TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration
|
||||
int com; // !=0 if this is a COM class (meaning
|
||||
// it derives from IUnknown)
|
||||
int isscope; // !=0 if this is an auto class
|
||||
int isabstract; // !=0 if abstract class
|
||||
#if DMDV1
|
||||
int isnested; // !=0 if is nested
|
||||
VarDeclaration *vthis; // 'this' parameter if this class is nested
|
||||
#endif
|
||||
int inuse; // to prevent recursive attempts
|
||||
|
||||
ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void semantic(Scope *sc);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
int isBaseOf2(ClassDeclaration *cd);
|
||||
|
||||
#define OFFSET_RUNTIME 0x76543210
|
||||
virtual int isBaseOf(ClassDeclaration *cd, int *poffset);
|
||||
|
||||
virtual int isBaseInfoComplete();
|
||||
Dsymbol *search(Loc, Identifier *ident, int flags);
|
||||
Dsymbol *searchBase(Loc, Identifier *ident);
|
||||
#if DMDV2
|
||||
int isFuncHidden(FuncDeclaration *fd);
|
||||
#endif
|
||||
FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
|
||||
void interfaceSemantic(Scope *sc);
|
||||
#if DMDV1
|
||||
int isNested();
|
||||
#endif
|
||||
int isCOMclass();
|
||||
virtual int isCOMinterface();
|
||||
#if DMDV2
|
||||
virtual int isCPPinterface();
|
||||
#endif
|
||||
int isAbstract();
|
||||
virtual int vtblOffset();
|
||||
const char *kind();
|
||||
char *mangle();
|
||||
void toDocBuffer(OutBuffer *buf);
|
||||
|
||||
PROT getAccess(Dsymbol *smember); // determine access to smember
|
||||
|
||||
void addLocalClass(ClassDeclarations *);
|
||||
|
||||
#if IN_DMD
|
||||
// Back end
|
||||
void toObjFile(int multiobj); // compile to .obj file
|
||||
void toDebug();
|
||||
unsigned baseVtblOffset(BaseClass *bc);
|
||||
Symbol *toSymbol();
|
||||
Symbol *toVtblSymbol();
|
||||
void toDt(dt_t **pdt);
|
||||
void toDt2(dt_t **pdt, ClassDeclaration *cd);
|
||||
|
||||
Symbol *vtblsym;
|
||||
#endif
|
||||
|
||||
ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
|
||||
|
||||
#if IN_LLVM
|
||||
virtual void codegen(Ir*);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct InterfaceDeclaration : ClassDeclaration
|
||||
{
|
||||
#if DMDV2
|
||||
int cpp; // !=0 if this is a C++ interface
|
||||
#endif
|
||||
InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void semantic(Scope *sc);
|
||||
int isBaseOf(ClassDeclaration *cd, int *poffset);
|
||||
int isBaseOf(BaseClass *bc, int *poffset);
|
||||
const char *kind();
|
||||
int isBaseInfoComplete();
|
||||
int vtblOffset();
|
||||
#if DMDV2
|
||||
int isCPPinterface();
|
||||
#endif
|
||||
virtual int isCOMinterface();
|
||||
|
||||
#if IN_DMD
|
||||
void toObjFile(int multiobj); // compile to .obj file
|
||||
Symbol *toSymbol();
|
||||
#endif
|
||||
|
||||
InterfaceDeclaration *isInterfaceDeclaration() { return this; }
|
||||
|
||||
#if IN_LLVM
|
||||
void codegen(Ir*);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* DMD_AGGREGATE_H */
|
||||
79
dmd2/aliasthis.c
Normal file
79
dmd2/aliasthis.c
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 2009-2009 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mars.h"
|
||||
#include "identifier.h"
|
||||
#include "aliasthis.h"
|
||||
#include "scope.h"
|
||||
#include "aggregate.h"
|
||||
#include "dsymbol.h"
|
||||
|
||||
#if DMDV2
|
||||
|
||||
|
||||
AliasThis::AliasThis(Loc loc, Identifier *ident)
|
||||
: Dsymbol(NULL) // it's anonymous (no identifier)
|
||||
{
|
||||
this->loc = loc;
|
||||
this->ident = ident;
|
||||
}
|
||||
|
||||
Dsymbol *AliasThis::syntaxCopy(Dsymbol *s)
|
||||
{
|
||||
assert(!s);
|
||||
/* Since there is no semantic information stored here,
|
||||
* we don't need to copy it.
|
||||
*/
|
||||
return this;
|
||||
}
|
||||
|
||||
void AliasThis::semantic(Scope *sc)
|
||||
{
|
||||
Dsymbol *parent = sc->parent;
|
||||
if (parent)
|
||||
parent = parent->pastMixin();
|
||||
AggregateDeclaration *ad = NULL;
|
||||
if (parent)
|
||||
ad = parent->isAggregateDeclaration();
|
||||
if (ad)
|
||||
{
|
||||
assert(ad->members);
|
||||
Dsymbol *s = ad->search(loc, ident, 0);
|
||||
if (!s)
|
||||
{ s = sc->search(loc, ident, 0);
|
||||
if (s)
|
||||
::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars());
|
||||
else
|
||||
::error(loc, "undefined identifier %s", ident->toChars());
|
||||
}
|
||||
else if (ad->aliasthis && s != ad->aliasthis)
|
||||
error("there can be only one alias this");
|
||||
ad->aliasthis = s;
|
||||
}
|
||||
else
|
||||
error("alias this can only appear in struct or class declaration, not %s", parent ? parent->toChars() : "nowhere");
|
||||
}
|
||||
|
||||
const char *AliasThis::kind()
|
||||
{
|
||||
return "alias this";
|
||||
}
|
||||
|
||||
void AliasThis::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
buf->writestring("alias ");
|
||||
buf->writestring(ident->toChars());
|
||||
buf->writestring(" this;\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
41
dmd2/aliasthis.h
Normal file
41
dmd2/aliasthis.h
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 2009-2009 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_ALIASTHIS_H
|
||||
#define DMD_ALIASTHIS_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
#include "mars.h"
|
||||
#include "dsymbol.h"
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
#if DMDV2
|
||||
|
||||
struct AliasThis : Dsymbol
|
||||
{
|
||||
// alias Identifier this;
|
||||
Identifier *ident;
|
||||
|
||||
AliasThis(Loc loc, Identifier *ident);
|
||||
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
void semantic(Scope *sc);
|
||||
const char *kind();
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
AliasThis *isAliasThis() { return this; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
165
dmd2/apply.c
Normal file
165
dmd2/apply.c
Normal file
@@ -0,0 +1,165 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mars.h"
|
||||
#include "expression.h"
|
||||
|
||||
|
||||
/**************************************
|
||||
* An Expression tree walker that will visit each Expression e in the tree,
|
||||
* in depth-first evaluation order, and call fp(e,param) on it.
|
||||
* fp() signals whether the walking continues with its return value:
|
||||
* Returns:
|
||||
* 0 continue
|
||||
* 1 done
|
||||
* It's a bit slower than using virtual functions, but more encapsulated and less brittle.
|
||||
* Creating an iterator for this would be much more complex.
|
||||
*/
|
||||
|
||||
typedef int (*fp_t)(Expression *, void *);
|
||||
|
||||
int Expression::apply(fp_t fp, void *param)
|
||||
{
|
||||
return (*fp)(this, param);
|
||||
}
|
||||
|
||||
/******************************
|
||||
* Perform apply() on an array of Expressions.
|
||||
*/
|
||||
|
||||
int arrayExpressionApply(Expressions *a, fp_t fp, void *param)
|
||||
{
|
||||
//printf("arrayExpressionApply(%p)\n", a);
|
||||
if (a)
|
||||
{
|
||||
for (size_t i = 0; i < a->dim; i++)
|
||||
{ Expression *e = (*a)[i];
|
||||
|
||||
if (e)
|
||||
{
|
||||
if (e->apply(fp, param))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NewExp::apply(int (*fp)(Expression *, void *), void *param)
|
||||
{
|
||||
//printf("NewExp::apply(): %s\n", toChars());
|
||||
|
||||
return ((thisexp ? thisexp->apply(fp, param) : 0) ||
|
||||
arrayExpressionApply(newargs, fp, param) ||
|
||||
arrayExpressionApply(arguments, fp, param) ||
|
||||
(*fp)(this, param));
|
||||
}
|
||||
|
||||
int NewAnonClassExp::apply(int (*fp)(Expression *, void *), void *param)
|
||||
{
|
||||
//printf("NewAnonClassExp::apply(): %s\n", toChars());
|
||||
|
||||
return ((thisexp ? thisexp->apply(fp, param) : 0) ||
|
||||
arrayExpressionApply(newargs, fp, param) ||
|
||||
arrayExpressionApply(arguments, fp, param) ||
|
||||
(*fp)(this, param));
|
||||
}
|
||||
|
||||
int UnaExp::apply(fp_t fp, void *param)
|
||||
{
|
||||
return e1->apply(fp, param) ||
|
||||
(*fp)(this, param);
|
||||
}
|
||||
|
||||
int BinExp::apply(fp_t fp, void *param)
|
||||
{
|
||||
return e1->apply(fp, param) ||
|
||||
e2->apply(fp, param) ||
|
||||
(*fp)(this, param);
|
||||
}
|
||||
|
||||
int AssertExp::apply(fp_t fp, void *param)
|
||||
{
|
||||
//printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars());
|
||||
return e1->apply(fp, param) ||
|
||||
(msg ? msg->apply(fp, param) : 0) ||
|
||||
(*fp)(this, param);
|
||||
}
|
||||
|
||||
|
||||
int CallExp::apply(fp_t fp, void *param)
|
||||
{
|
||||
//printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars());
|
||||
return e1->apply(fp, param) ||
|
||||
arrayExpressionApply(arguments, fp, param) ||
|
||||
(*fp)(this, param);
|
||||
}
|
||||
|
||||
|
||||
int ArrayExp::apply(fp_t fp, void *param)
|
||||
{
|
||||
//printf("ArrayExp::apply(fp_t fp, void *param): %s\n", toChars());
|
||||
return e1->apply(fp, param) ||
|
||||
arrayExpressionApply(arguments, fp, param) ||
|
||||
(*fp)(this, param);
|
||||
}
|
||||
|
||||
|
||||
int SliceExp::apply(fp_t fp, void *param)
|
||||
{
|
||||
return e1->apply(fp, param) ||
|
||||
(lwr ? lwr->apply(fp, param) : 0) ||
|
||||
(upr ? upr->apply(fp, param) : 0) ||
|
||||
(*fp)(this, param);
|
||||
}
|
||||
|
||||
|
||||
int ArrayLiteralExp::apply(fp_t fp, void *param)
|
||||
{
|
||||
return arrayExpressionApply(elements, fp, param) ||
|
||||
(*fp)(this, param);
|
||||
}
|
||||
|
||||
|
||||
int AssocArrayLiteralExp::apply(fp_t fp, void *param)
|
||||
{
|
||||
return arrayExpressionApply(keys, fp, param) ||
|
||||
arrayExpressionApply(values, fp, param) ||
|
||||
(*fp)(this, param);
|
||||
}
|
||||
|
||||
|
||||
int StructLiteralExp::apply(fp_t fp, void *param)
|
||||
{
|
||||
return arrayExpressionApply(elements, fp, param) ||
|
||||
(*fp)(this, param);
|
||||
}
|
||||
|
||||
|
||||
int TupleExp::apply(fp_t fp, void *param)
|
||||
{
|
||||
return arrayExpressionApply(exps, fp, param) ||
|
||||
(*fp)(this, param);
|
||||
}
|
||||
|
||||
|
||||
int CondExp::apply(fp_t fp, void *param)
|
||||
{
|
||||
return econd->apply(fp, param) ||
|
||||
e1->apply(fp, param) ||
|
||||
e2->apply(fp, param) ||
|
||||
(*fp)(this, param);
|
||||
}
|
||||
|
||||
|
||||
|
||||
193
dmd2/argtypes.c
Normal file
193
dmd2/argtypes.c
Normal file
@@ -0,0 +1,193 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 2010-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// http://www.dsource.org/projects/dmd/browser/branches/dmd-1.x/src/argtypes.c
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mars.h"
|
||||
#include "dsymbol.h"
|
||||
#include "mtype.h"
|
||||
#include "scope.h"
|
||||
#include "init.h"
|
||||
#include "expression.h"
|
||||
#include "attrib.h"
|
||||
#include "declaration.h"
|
||||
#include "template.h"
|
||||
#include "id.h"
|
||||
#include "enum.h"
|
||||
#include "import.h"
|
||||
#include "aggregate.h"
|
||||
#include "hdrgen.h"
|
||||
|
||||
/****************************************************
|
||||
* This breaks a type down into 'simpler' types that can be passed to a function
|
||||
* in registers, and returned in registers.
|
||||
* It's highly platform dependent.
|
||||
* Returning a tuple of zero length means the type cannot be passed/returned in registers.
|
||||
*/
|
||||
|
||||
|
||||
TypeTuple *Type::toArgTypes()
|
||||
{
|
||||
return NULL; // not valid for a parameter
|
||||
}
|
||||
|
||||
|
||||
TypeTuple *TypeBasic::toArgTypes()
|
||||
{ Type *t1 = NULL;
|
||||
Type *t2 = NULL;
|
||||
switch (ty)
|
||||
{
|
||||
case Tvoid:
|
||||
return NULL;
|
||||
|
||||
case Tbool:
|
||||
case Tint8:
|
||||
case Tuns8:
|
||||
case Tint16:
|
||||
case Tuns16:
|
||||
case Tint32:
|
||||
case Tuns32:
|
||||
case Tfloat32:
|
||||
case Tint64:
|
||||
case Tuns64:
|
||||
case Tfloat64:
|
||||
case Tfloat80:
|
||||
t1 = this;
|
||||
break;
|
||||
|
||||
case Timaginary32:
|
||||
t1 = Type::tfloat32;
|
||||
break;
|
||||
|
||||
case Timaginary64:
|
||||
t1 = Type::tfloat64;
|
||||
break;
|
||||
|
||||
case Timaginary80:
|
||||
t1 = Type::tfloat80;
|
||||
break;
|
||||
|
||||
case Tcomplex32:
|
||||
if (global.params.is64bit)
|
||||
t1 = Type::tfloat64; // weird, eh?
|
||||
else
|
||||
{
|
||||
t1 = Type::tfloat64;
|
||||
t2 = Type::tfloat64;
|
||||
}
|
||||
break;
|
||||
|
||||
case Tcomplex64:
|
||||
t1 = Type::tfloat64;
|
||||
t2 = Type::tfloat64;
|
||||
break;
|
||||
|
||||
case Tcomplex80:
|
||||
t1 = Type::tfloat80;
|
||||
t2 = Type::tfloat80;
|
||||
break;
|
||||
|
||||
case Tascii:
|
||||
t1 = Type::tuns8;
|
||||
break;
|
||||
|
||||
case Twchar:
|
||||
t1 = Type::tuns16;
|
||||
break;
|
||||
|
||||
case Tdchar:
|
||||
t1 = Type::tuns32;
|
||||
break;
|
||||
|
||||
default: assert(0);
|
||||
}
|
||||
|
||||
TypeTuple *t;
|
||||
if (t1)
|
||||
{
|
||||
if (t2)
|
||||
t = new TypeTuple(t1, t2);
|
||||
else
|
||||
t = new TypeTuple(t1);
|
||||
}
|
||||
else
|
||||
t = new TypeTuple();
|
||||
return t;
|
||||
}
|
||||
|
||||
TypeTuple *TypeVector::toArgTypes()
|
||||
{
|
||||
return new TypeTuple(Type::tfloat64);
|
||||
}
|
||||
|
||||
TypeTuple *TypeSArray::toArgTypes()
|
||||
{
|
||||
#if DMDV2
|
||||
return new TypeTuple(); // pass on the stack for efficiency
|
||||
#else
|
||||
return new TypeTuple(Type::tvoidptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
TypeTuple *TypeDArray::toArgTypes()
|
||||
{
|
||||
return new TypeTuple(); // pass on the stack for efficiency
|
||||
}
|
||||
|
||||
TypeTuple *TypeAArray::toArgTypes()
|
||||
{
|
||||
return new TypeTuple(Type::tvoidptr);
|
||||
}
|
||||
|
||||
TypeTuple *TypePointer::toArgTypes()
|
||||
{
|
||||
return new TypeTuple(this);
|
||||
}
|
||||
|
||||
TypeTuple *TypeDelegate::toArgTypes()
|
||||
{
|
||||
return new TypeTuple(); // pass on the stack for efficiency
|
||||
}
|
||||
|
||||
TypeTuple *TypeStruct::toArgTypes()
|
||||
{
|
||||
d_uns64 sz = size(0);
|
||||
assert(sz < 0xFFFFFFFF);
|
||||
switch ((unsigned)sz)
|
||||
{
|
||||
case 1:
|
||||
return new TypeTuple(Type::tint8);
|
||||
case 2:
|
||||
return new TypeTuple(Type::tint16);
|
||||
case 4:
|
||||
return new TypeTuple(Type::tint32);
|
||||
case 8:
|
||||
return new TypeTuple(Type::tint64);
|
||||
}
|
||||
return new TypeTuple(); // pass on the stack
|
||||
}
|
||||
|
||||
TypeTuple *TypeEnum::toArgTypes()
|
||||
{
|
||||
return toBasetype()->toArgTypes();
|
||||
}
|
||||
|
||||
TypeTuple *TypeTypedef::toArgTypes()
|
||||
{
|
||||
return sym->basetype->toArgTypes();
|
||||
}
|
||||
|
||||
TypeTuple *TypeClass::toArgTypes()
|
||||
{
|
||||
return new TypeTuple(Type::tvoidptr);
|
||||
}
|
||||
|
||||
682
dmd2/arrayop.c
Normal file
682
dmd2/arrayop.c
Normal file
@@ -0,0 +1,682 @@
|
||||
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "rmem.h"
|
||||
|
||||
#include "aav.h"
|
||||
|
||||
#include "expression.h"
|
||||
#include "statement.h"
|
||||
#include "mtype.h"
|
||||
#include "declaration.h"
|
||||
#include "scope.h"
|
||||
#include "id.h"
|
||||
#include "module.h"
|
||||
#include "init.h"
|
||||
|
||||
#if IN_DMD
|
||||
extern int binary(const char *p , const char **tab, int high);
|
||||
|
||||
/**************************************
|
||||
* Hash table of array op functions already generated or known about.
|
||||
*/
|
||||
|
||||
AA *arrayfuncs;
|
||||
#else
|
||||
int binary(const char *p , const char **tab, int high)
|
||||
{
|
||||
int i = 0, j = high, k, l;
|
||||
do
|
||||
{
|
||||
k = (i + j) / 2;
|
||||
l = strcmp(p, tab[k]);
|
||||
if (!l)
|
||||
return k;
|
||||
else if (l < 0)
|
||||
j = k;
|
||||
else
|
||||
i = k + 1;
|
||||
}
|
||||
while (i != j);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************************************
|
||||
* Check that there are no uses of arrays without [].
|
||||
*/
|
||||
bool isArrayOpValid(Expression *e)
|
||||
{
|
||||
if (e->op == TOKslice)
|
||||
return true;
|
||||
Type *tb = e->type->toBasetype();
|
||||
|
||||
if ( (tb->ty == Tarray) || (tb->ty == Tsarray) )
|
||||
{
|
||||
switch (e->op)
|
||||
{
|
||||
case TOKadd:
|
||||
case TOKmin:
|
||||
case TOKmul:
|
||||
case TOKdiv:
|
||||
case TOKmod:
|
||||
case TOKxor:
|
||||
case TOKand:
|
||||
case TOKor:
|
||||
case TOKassign:
|
||||
case TOKaddass:
|
||||
case TOKminass:
|
||||
case TOKmulass:
|
||||
case TOKdivass:
|
||||
case TOKmodass:
|
||||
case TOKxorass:
|
||||
case TOKandass:
|
||||
case TOKorass:
|
||||
#if DMDV2
|
||||
case TOKpow:
|
||||
case TOKpowass:
|
||||
#endif
|
||||
return isArrayOpValid(((BinExp *)e)->e1) && isArrayOpValid(((BinExp *)e)->e2);
|
||||
|
||||
case TOKcall:
|
||||
return false; // TODO: Decide if [] is required after arrayop calls.
|
||||
|
||||
case TOKneg:
|
||||
case TOKtilde:
|
||||
return isArrayOpValid(((UnaExp *)e)->e1);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* Construct the array operation expression.
|
||||
*/
|
||||
|
||||
Expression *BinExp::arrayOp(Scope *sc)
|
||||
{
|
||||
|
||||
Type *tb = type->toBasetype();
|
||||
assert(tb->ty == Tarray || tb->ty == Tsarray);
|
||||
if (tb->nextOf()->toBasetype()->ty == Tvoid)
|
||||
{
|
||||
error("Cannot perform array operations on void[] arrays");
|
||||
return new ErrorExp();
|
||||
}
|
||||
|
||||
if (!isArrayOpValid(e2))
|
||||
{
|
||||
e2->error("invalid array operation %s (did you forget a [] ?)", toChars());
|
||||
return new ErrorExp();
|
||||
}
|
||||
|
||||
Expressions *arguments = new Expressions();
|
||||
|
||||
/* The expression to generate an array operation for is mangled
|
||||
* into a name to use as the array operation function name.
|
||||
* Mangle in the operands and operators in RPN order, and type.
|
||||
*/
|
||||
OutBuffer buf;
|
||||
buf.writestring("_array");
|
||||
buildArrayIdent(&buf, arguments);
|
||||
buf.writeByte('_');
|
||||
|
||||
/* Append deco of array element type
|
||||
*/
|
||||
#if DMDV2
|
||||
buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
|
||||
#else
|
||||
buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco);
|
||||
#endif
|
||||
|
||||
size_t namelen = buf.offset;
|
||||
buf.writeByte(0);
|
||||
char *name = buf.toChars();
|
||||
Identifier *ident = Lexer::idPool(name);
|
||||
|
||||
/* Look up name in hash table
|
||||
*/
|
||||
#if IN_LLVM
|
||||
FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&sc->module->arrayfuncs, ident);
|
||||
#else
|
||||
FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&arrayfuncs, ident);
|
||||
#endif
|
||||
FuncDeclaration *fd = (FuncDeclaration *)*pfd;
|
||||
if (!fd)
|
||||
{
|
||||
/* Some of the array op functions are written as library functions,
|
||||
* presumably to optimize them with special CPU vector instructions.
|
||||
* List those library functions here, in alpha order.
|
||||
*/
|
||||
static const char *libArrayopFuncs[] =
|
||||
{
|
||||
"_arrayExpSliceAddass_a",
|
||||
"_arrayExpSliceAddass_d", // T[]+=T
|
||||
"_arrayExpSliceAddass_f", // T[]+=T
|
||||
"_arrayExpSliceAddass_g",
|
||||
"_arrayExpSliceAddass_h",
|
||||
"_arrayExpSliceAddass_i",
|
||||
"_arrayExpSliceAddass_k",
|
||||
"_arrayExpSliceAddass_s",
|
||||
"_arrayExpSliceAddass_t",
|
||||
"_arrayExpSliceAddass_u",
|
||||
"_arrayExpSliceAddass_w",
|
||||
|
||||
"_arrayExpSliceDivass_d", // T[]/=T
|
||||
"_arrayExpSliceDivass_f", // T[]/=T
|
||||
|
||||
"_arrayExpSliceMinSliceAssign_a",
|
||||
"_arrayExpSliceMinSliceAssign_d", // T[]=T-T[]
|
||||
"_arrayExpSliceMinSliceAssign_f", // T[]=T-T[]
|
||||
"_arrayExpSliceMinSliceAssign_g",
|
||||
"_arrayExpSliceMinSliceAssign_h",
|
||||
"_arrayExpSliceMinSliceAssign_i",
|
||||
"_arrayExpSliceMinSliceAssign_k",
|
||||
"_arrayExpSliceMinSliceAssign_s",
|
||||
"_arrayExpSliceMinSliceAssign_t",
|
||||
"_arrayExpSliceMinSliceAssign_u",
|
||||
"_arrayExpSliceMinSliceAssign_w",
|
||||
|
||||
"_arrayExpSliceMinass_a",
|
||||
"_arrayExpSliceMinass_d", // T[]-=T
|
||||
"_arrayExpSliceMinass_f", // T[]-=T
|
||||
"_arrayExpSliceMinass_g",
|
||||
"_arrayExpSliceMinass_h",
|
||||
"_arrayExpSliceMinass_i",
|
||||
"_arrayExpSliceMinass_k",
|
||||
"_arrayExpSliceMinass_s",
|
||||
"_arrayExpSliceMinass_t",
|
||||
"_arrayExpSliceMinass_u",
|
||||
"_arrayExpSliceMinass_w",
|
||||
|
||||
"_arrayExpSliceMulass_d", // T[]*=T
|
||||
"_arrayExpSliceMulass_f", // T[]*=T
|
||||
"_arrayExpSliceMulass_i",
|
||||
"_arrayExpSliceMulass_k",
|
||||
"_arrayExpSliceMulass_s",
|
||||
"_arrayExpSliceMulass_t",
|
||||
"_arrayExpSliceMulass_u",
|
||||
"_arrayExpSliceMulass_w",
|
||||
|
||||
"_arraySliceExpAddSliceAssign_a",
|
||||
"_arraySliceExpAddSliceAssign_d", // T[]=T[]+T
|
||||
"_arraySliceExpAddSliceAssign_f", // T[]=T[]+T
|
||||
"_arraySliceExpAddSliceAssign_g",
|
||||
"_arraySliceExpAddSliceAssign_h",
|
||||
"_arraySliceExpAddSliceAssign_i",
|
||||
"_arraySliceExpAddSliceAssign_k",
|
||||
"_arraySliceExpAddSliceAssign_s",
|
||||
"_arraySliceExpAddSliceAssign_t",
|
||||
"_arraySliceExpAddSliceAssign_u",
|
||||
"_arraySliceExpAddSliceAssign_w",
|
||||
|
||||
"_arraySliceExpDivSliceAssign_d", // T[]=T[]/T
|
||||
"_arraySliceExpDivSliceAssign_f", // T[]=T[]/T
|
||||
|
||||
"_arraySliceExpMinSliceAssign_a",
|
||||
"_arraySliceExpMinSliceAssign_d", // T[]=T[]-T
|
||||
"_arraySliceExpMinSliceAssign_f", // T[]=T[]-T
|
||||
"_arraySliceExpMinSliceAssign_g",
|
||||
"_arraySliceExpMinSliceAssign_h",
|
||||
"_arraySliceExpMinSliceAssign_i",
|
||||
"_arraySliceExpMinSliceAssign_k",
|
||||
"_arraySliceExpMinSliceAssign_s",
|
||||
"_arraySliceExpMinSliceAssign_t",
|
||||
"_arraySliceExpMinSliceAssign_u",
|
||||
"_arraySliceExpMinSliceAssign_w",
|
||||
|
||||
"_arraySliceExpMulSliceAddass_d", // T[] += T[]*T
|
||||
"_arraySliceExpMulSliceAddass_f",
|
||||
"_arraySliceExpMulSliceAddass_r",
|
||||
|
||||
"_arraySliceExpMulSliceAssign_d", // T[]=T[]*T
|
||||
"_arraySliceExpMulSliceAssign_f", // T[]=T[]*T
|
||||
"_arraySliceExpMulSliceAssign_i",
|
||||
"_arraySliceExpMulSliceAssign_k",
|
||||
"_arraySliceExpMulSliceAssign_s",
|
||||
"_arraySliceExpMulSliceAssign_t",
|
||||
"_arraySliceExpMulSliceAssign_u",
|
||||
"_arraySliceExpMulSliceAssign_w",
|
||||
|
||||
"_arraySliceExpMulSliceMinass_d", // T[] -= T[]*T
|
||||
"_arraySliceExpMulSliceMinass_f",
|
||||
"_arraySliceExpMulSliceMinass_r",
|
||||
|
||||
"_arraySliceSliceAddSliceAssign_a",
|
||||
"_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[]
|
||||
"_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[]
|
||||
"_arraySliceSliceAddSliceAssign_g",
|
||||
"_arraySliceSliceAddSliceAssign_h",
|
||||
"_arraySliceSliceAddSliceAssign_i",
|
||||
"_arraySliceSliceAddSliceAssign_k",
|
||||
"_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[]
|
||||
"_arraySliceSliceAddSliceAssign_s",
|
||||
"_arraySliceSliceAddSliceAssign_t",
|
||||
"_arraySliceSliceAddSliceAssign_u",
|
||||
"_arraySliceSliceAddSliceAssign_w",
|
||||
|
||||
"_arraySliceSliceAddass_a",
|
||||
"_arraySliceSliceAddass_d", // T[]+=T[]
|
||||
"_arraySliceSliceAddass_f", // T[]+=T[]
|
||||
"_arraySliceSliceAddass_g",
|
||||
"_arraySliceSliceAddass_h",
|
||||
"_arraySliceSliceAddass_i",
|
||||
"_arraySliceSliceAddass_k",
|
||||
"_arraySliceSliceAddass_s",
|
||||
"_arraySliceSliceAddass_t",
|
||||
"_arraySliceSliceAddass_u",
|
||||
"_arraySliceSliceAddass_w",
|
||||
|
||||
"_arraySliceSliceMinSliceAssign_a",
|
||||
"_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[]
|
||||
"_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[]
|
||||
"_arraySliceSliceMinSliceAssign_g",
|
||||
"_arraySliceSliceMinSliceAssign_h",
|
||||
"_arraySliceSliceMinSliceAssign_i",
|
||||
"_arraySliceSliceMinSliceAssign_k",
|
||||
"_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[]
|
||||
"_arraySliceSliceMinSliceAssign_s",
|
||||
"_arraySliceSliceMinSliceAssign_t",
|
||||
"_arraySliceSliceMinSliceAssign_u",
|
||||
"_arraySliceSliceMinSliceAssign_w",
|
||||
|
||||
"_arraySliceSliceMinass_a",
|
||||
"_arraySliceSliceMinass_d", // T[]-=T[]
|
||||
"_arraySliceSliceMinass_f", // T[]-=T[]
|
||||
"_arraySliceSliceMinass_g",
|
||||
"_arraySliceSliceMinass_h",
|
||||
"_arraySliceSliceMinass_i",
|
||||
"_arraySliceSliceMinass_k",
|
||||
"_arraySliceSliceMinass_s",
|
||||
"_arraySliceSliceMinass_t",
|
||||
"_arraySliceSliceMinass_u",
|
||||
"_arraySliceSliceMinass_w",
|
||||
|
||||
"_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[]
|
||||
"_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[]
|
||||
"_arraySliceSliceMulSliceAssign_i",
|
||||
"_arraySliceSliceMulSliceAssign_k",
|
||||
"_arraySliceSliceMulSliceAssign_s",
|
||||
"_arraySliceSliceMulSliceAssign_t",
|
||||
"_arraySliceSliceMulSliceAssign_u",
|
||||
"_arraySliceSliceMulSliceAssign_w",
|
||||
|
||||
"_arraySliceSliceMulass_d", // T[]*=T[]
|
||||
"_arraySliceSliceMulass_f", // T[]*=T[]
|
||||
"_arraySliceSliceMulass_i",
|
||||
"_arraySliceSliceMulass_k",
|
||||
"_arraySliceSliceMulass_s",
|
||||
"_arraySliceSliceMulass_t",
|
||||
"_arraySliceSliceMulass_u",
|
||||
"_arraySliceSliceMulass_w",
|
||||
};
|
||||
|
||||
int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *));
|
||||
if (i == -1)
|
||||
{
|
||||
#ifdef DEBUG // Make sure our array is alphabetized
|
||||
for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++)
|
||||
{
|
||||
if (strcmp(name, libArrayopFuncs[i]) == 0)
|
||||
assert(0);
|
||||
}
|
||||
#endif
|
||||
/* Not in library, so generate it.
|
||||
* Construct the function body:
|
||||
* foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++)
|
||||
* loopbody;
|
||||
* return p;
|
||||
*/
|
||||
|
||||
Parameters *fparams = new Parameters();
|
||||
Expression *loopbody = buildArrayLoop(fparams);
|
||||
Parameter *p = (*fparams)[0 /*fparams->dim - 1*/];
|
||||
#if DMDV1
|
||||
// for (size_t i = 0; i < p.length; i++)
|
||||
Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t));
|
||||
Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init);
|
||||
Statement *s1 = new ForStatement(0,
|
||||
new DeclarationStatement(0, d),
|
||||
new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))),
|
||||
new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)),
|
||||
new ExpStatement(0, loopbody));
|
||||
#else
|
||||
// foreach (i; 0 .. p.length)
|
||||
Statement *s1 = new ForeachRangeStatement(0, TOKforeach,
|
||||
new Parameter(0, NULL, Id::p, NULL),
|
||||
new IntegerExp(0, 0, Type::tint32),
|
||||
new ArrayLengthExp(0, new IdentifierExp(0, p->ident)),
|
||||
new ExpStatement(0, loopbody));
|
||||
#endif
|
||||
Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident));
|
||||
//printf("s2: %s\n", s2->toChars());
|
||||
Statement *fbody = new CompoundStatement(0, s1, s2);
|
||||
|
||||
/* Construct the function
|
||||
*/
|
||||
TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc);
|
||||
//printf("ftype: %s\n", ftype->toChars());
|
||||
fd = new FuncDeclaration(loc, 0, ident, STCundefined, ftype);
|
||||
fd->fbody = fbody;
|
||||
fd->protection = PROTpublic;
|
||||
fd->linkage = LINKd;
|
||||
fd->isArrayOp = 1;
|
||||
|
||||
sc->module->importedFrom->members->push(fd);
|
||||
|
||||
sc = sc->push();
|
||||
sc->parent = sc->module->importedFrom;
|
||||
sc->stc = 0;
|
||||
sc->linkage = LINKc;
|
||||
fd->semantic(sc);
|
||||
fd->semantic2(sc);
|
||||
fd->semantic3(sc);
|
||||
sc->pop();
|
||||
}
|
||||
#if IN_LLVM
|
||||
else
|
||||
{ /* In library, refer to it.
|
||||
*/
|
||||
Parameters *fparams = new Parameters();
|
||||
buildArrayLoop(fparams);
|
||||
fd = FuncDeclaration::genCfunc(fparams, type, ident);
|
||||
fd->isArrayOp = 2;
|
||||
}
|
||||
#else
|
||||
else
|
||||
{ /* In library, refer to it.
|
||||
*/
|
||||
fd = FuncDeclaration::genCfunc(type, ident);
|
||||
}
|
||||
#endif
|
||||
*pfd = fd; // cache symbol in hash table
|
||||
}
|
||||
|
||||
/* Call the function fd(arguments)
|
||||
*/
|
||||
Expression *ec = new VarExp(0, fd);
|
||||
Expression *e = new CallExp(loc, ec, arguments);
|
||||
e->type = type;
|
||||
return e;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Construct the identifier for the array operation function,
|
||||
* and build the argument list to pass to it.
|
||||
*/
|
||||
|
||||
void Expression::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
|
||||
{
|
||||
buf->writestring("Exp");
|
||||
arguments->shift(this);
|
||||
}
|
||||
|
||||
void CastExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
|
||||
{
|
||||
Type *tb = type->toBasetype();
|
||||
if (tb->ty == Tarray || tb->ty == Tsarray)
|
||||
{
|
||||
e1->buildArrayIdent(buf, arguments);
|
||||
}
|
||||
else
|
||||
Expression::buildArrayIdent(buf, arguments);
|
||||
}
|
||||
|
||||
void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
|
||||
{
|
||||
buf->writestring("Slice");
|
||||
arguments->shift(this);
|
||||
}
|
||||
|
||||
void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
|
||||
{
|
||||
/* Evaluate assign expressions right to left
|
||||
*/
|
||||
e2->buildArrayIdent(buf, arguments);
|
||||
e1->buildArrayIdent(buf, arguments);
|
||||
buf->writestring("Assign");
|
||||
}
|
||||
|
||||
#define X(Str) \
|
||||
void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \
|
||||
{ \
|
||||
/* Evaluate assign expressions right to left \
|
||||
*/ \
|
||||
e2->buildArrayIdent(buf, arguments); \
|
||||
e1->buildArrayIdent(buf, arguments); \
|
||||
buf->writestring(#Str); \
|
||||
buf->writestring("ass"); \
|
||||
}
|
||||
|
||||
X(Add)
|
||||
X(Min)
|
||||
X(Mul)
|
||||
X(Div)
|
||||
X(Mod)
|
||||
X(Xor)
|
||||
X(And)
|
||||
X(Or)
|
||||
#if DMDV2
|
||||
X(Pow)
|
||||
#endif
|
||||
|
||||
#undef X
|
||||
|
||||
void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
|
||||
{
|
||||
e1->buildArrayIdent(buf, arguments);
|
||||
buf->writestring("Neg");
|
||||
}
|
||||
|
||||
void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
|
||||
{
|
||||
e1->buildArrayIdent(buf, arguments);
|
||||
buf->writestring("Com");
|
||||
}
|
||||
|
||||
#define X(Str) \
|
||||
void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \
|
||||
{ \
|
||||
/* Evaluate assign expressions left to right \
|
||||
*/ \
|
||||
e1->buildArrayIdent(buf, arguments); \
|
||||
e2->buildArrayIdent(buf, arguments); \
|
||||
buf->writestring(#Str); \
|
||||
}
|
||||
|
||||
X(Add)
|
||||
X(Min)
|
||||
X(Mul)
|
||||
X(Div)
|
||||
X(Mod)
|
||||
X(Xor)
|
||||
X(And)
|
||||
X(Or)
|
||||
#if DMDV2
|
||||
X(Pow)
|
||||
#endif
|
||||
|
||||
#undef X
|
||||
|
||||
/******************************************
|
||||
* Construct the inner loop for the array operation function,
|
||||
* and build the parameter list.
|
||||
*/
|
||||
|
||||
Expression *Expression::buildArrayLoop(Parameters *fparams)
|
||||
{
|
||||
Identifier *id = Identifier::generateId("c", fparams->dim);
|
||||
Parameter *param = new Parameter(0, type, id, NULL);
|
||||
fparams->shift(param);
|
||||
Expression *e = new IdentifierExp(0, id);
|
||||
return e;
|
||||
}
|
||||
|
||||
Expression *CastExp::buildArrayLoop(Parameters *fparams)
|
||||
{
|
||||
Type *tb = type->toBasetype();
|
||||
if (tb->ty == Tarray || tb->ty == Tsarray)
|
||||
{
|
||||
return e1->buildArrayLoop(fparams);
|
||||
}
|
||||
else
|
||||
return Expression::buildArrayLoop(fparams);
|
||||
}
|
||||
|
||||
Expression *SliceExp::buildArrayLoop(Parameters *fparams)
|
||||
{
|
||||
Identifier *id = Identifier::generateId("p", fparams->dim);
|
||||
Parameter *param = new Parameter(STCconst, type, id, NULL);
|
||||
fparams->shift(param);
|
||||
Expression *e = new IdentifierExp(0, id);
|
||||
Expressions *arguments = new Expressions();
|
||||
Expression *index = new IdentifierExp(0, Id::p);
|
||||
arguments->push(index);
|
||||
e = new ArrayExp(0, e, arguments);
|
||||
return e;
|
||||
}
|
||||
|
||||
Expression *AssignExp::buildArrayLoop(Parameters *fparams)
|
||||
{
|
||||
/* Evaluate assign expressions right to left
|
||||
*/
|
||||
Expression *ex2 = e2->buildArrayLoop(fparams);
|
||||
#if DMDV2
|
||||
/* Need the cast because:
|
||||
* b = c + p[i];
|
||||
* where b is a byte fails because (c + p[i]) is an int
|
||||
* which cannot be implicitly cast to byte.
|
||||
*/
|
||||
ex2 = new CastExp(0, ex2, e1->type->nextOf());
|
||||
#endif
|
||||
Expression *ex1 = e1->buildArrayLoop(fparams);
|
||||
Parameter *param = (*fparams)[0];
|
||||
param->storageClass = 0;
|
||||
Expression *e = new AssignExp(0, ex1, ex2);
|
||||
return e;
|
||||
}
|
||||
|
||||
#define X(Str) \
|
||||
Expression *Str##AssignExp::buildArrayLoop(Parameters *fparams) \
|
||||
{ \
|
||||
/* Evaluate assign expressions right to left \
|
||||
*/ \
|
||||
Expression *ex2 = e2->buildArrayLoop(fparams); \
|
||||
Expression *ex1 = e1->buildArrayLoop(fparams); \
|
||||
Parameter *param = (*fparams)[0]; \
|
||||
param->storageClass = 0; \
|
||||
Expression *e = new Str##AssignExp(loc, ex1, ex2); \
|
||||
return e; \
|
||||
}
|
||||
|
||||
X(Add)
|
||||
X(Min)
|
||||
X(Mul)
|
||||
X(Div)
|
||||
X(Mod)
|
||||
X(Xor)
|
||||
X(And)
|
||||
X(Or)
|
||||
#if DMDV2
|
||||
X(Pow)
|
||||
#endif
|
||||
|
||||
#undef X
|
||||
|
||||
Expression *NegExp::buildArrayLoop(Parameters *fparams)
|
||||
{
|
||||
Expression *ex1 = e1->buildArrayLoop(fparams);
|
||||
Expression *e = new NegExp(0, ex1);
|
||||
return e;
|
||||
}
|
||||
|
||||
Expression *ComExp::buildArrayLoop(Parameters *fparams)
|
||||
{
|
||||
Expression *ex1 = e1->buildArrayLoop(fparams);
|
||||
Expression *e = new ComExp(0, ex1);
|
||||
return e;
|
||||
}
|
||||
|
||||
#define X(Str) \
|
||||
Expression *Str##Exp::buildArrayLoop(Parameters *fparams) \
|
||||
{ \
|
||||
/* Evaluate assign expressions left to right \
|
||||
*/ \
|
||||
Expression *ex1 = e1->buildArrayLoop(fparams); \
|
||||
Expression *ex2 = e2->buildArrayLoop(fparams); \
|
||||
Expression *e = new Str##Exp(0, ex1, ex2); \
|
||||
return e; \
|
||||
}
|
||||
|
||||
X(Add)
|
||||
X(Min)
|
||||
X(Mul)
|
||||
X(Div)
|
||||
X(Mod)
|
||||
X(Xor)
|
||||
X(And)
|
||||
X(Or)
|
||||
#if DMDV2
|
||||
X(Pow)
|
||||
#endif
|
||||
|
||||
#undef X
|
||||
|
||||
|
||||
/***********************************************
|
||||
* Test if operand is a valid array op operand.
|
||||
*/
|
||||
|
||||
int Expression::isArrayOperand()
|
||||
{
|
||||
//printf("Expression::isArrayOperand() %s\n", toChars());
|
||||
if (op == TOKslice)
|
||||
return 1;
|
||||
if (type->toBasetype()->ty == Tarray)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case TOKadd:
|
||||
case TOKmin:
|
||||
case TOKmul:
|
||||
case TOKdiv:
|
||||
case TOKmod:
|
||||
case TOKxor:
|
||||
case TOKand:
|
||||
case TOKor:
|
||||
case TOKassign:
|
||||
case TOKaddass:
|
||||
case TOKminass:
|
||||
case TOKmulass:
|
||||
case TOKdivass:
|
||||
case TOKmodass:
|
||||
case TOKxorass:
|
||||
case TOKandass:
|
||||
case TOKorass:
|
||||
#if DMDV2
|
||||
case TOKpow:
|
||||
case TOKpowass:
|
||||
#endif
|
||||
case TOKneg:
|
||||
case TOKtilde:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
77
dmd2/arraytypes.h
Normal file
77
dmd2/arraytypes.h
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 2006-2007 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_ARRAYTYPES_H
|
||||
#define DMD_ARRAYTYPES_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
|
||||
#include "root.h"
|
||||
|
||||
typedef ArrayBase<struct TemplateParameter> TemplateParameters;
|
||||
|
||||
typedef ArrayBase<struct Expression> Expressions;
|
||||
|
||||
typedef ArrayBase<struct Statement> Statements;
|
||||
|
||||
typedef ArrayBase<struct BaseClass> BaseClasses;
|
||||
|
||||
typedef ArrayBase<struct ClassDeclaration> ClassDeclarations;
|
||||
|
||||
typedef ArrayBase<struct Dsymbol> Dsymbols;
|
||||
|
||||
typedef ArrayBase<struct Object> Objects;
|
||||
|
||||
typedef ArrayBase<struct FuncDeclaration> FuncDeclarations;
|
||||
|
||||
typedef ArrayBase<struct Parameter> Parameters;
|
||||
|
||||
typedef ArrayBase<struct Identifier> Identifiers;
|
||||
|
||||
typedef ArrayBase<struct Initializer> Initializers;
|
||||
|
||||
typedef ArrayBase<struct VarDeclaration> VarDeclarations;
|
||||
|
||||
typedef ArrayBase<struct Type> Types;
|
||||
|
||||
typedef ArrayBase<struct ScopeDsymbol> ScopeDsymbols;
|
||||
|
||||
typedef ArrayBase<struct Catch> Catches;
|
||||
|
||||
typedef ArrayBase<struct StaticDtorDeclaration> StaticDtorDeclarations;
|
||||
|
||||
typedef ArrayBase<struct SharedStaticDtorDeclaration> SharedStaticDtorDeclarations;
|
||||
|
||||
typedef ArrayBase<struct AliasDeclaration> AliasDeclarations;
|
||||
|
||||
typedef ArrayBase<struct Module> Modules;
|
||||
|
||||
typedef ArrayBase<struct File> Files;
|
||||
|
||||
typedef ArrayBase<struct CaseStatement> CaseStatements;
|
||||
|
||||
typedef ArrayBase<struct CompoundStatement> CompoundStatements;
|
||||
|
||||
typedef ArrayBase<struct GotoCaseStatement> GotoCaseStatements;
|
||||
|
||||
typedef ArrayBase<struct TemplateInstance> TemplateInstances;
|
||||
|
||||
//typedef ArrayBase<char> Strings;
|
||||
|
||||
typedef ArrayBase<void> Voids;
|
||||
|
||||
typedef ArrayBase<struct block> Blocks;
|
||||
|
||||
typedef ArrayBase<struct Symbol> Symbols;
|
||||
|
||||
#endif
|
||||
117
dmd2/artistic.txt
Normal file
117
dmd2/artistic.txt
Normal file
@@ -0,0 +1,117 @@
|
||||
|
||||
|
||||
|
||||
|
||||
The "Artistic License"
|
||||
|
||||
Preamble
|
||||
|
||||
The intent of this document is to state the conditions under which a
|
||||
Package may be copied, such that the Copyright Holder maintains some
|
||||
semblance of artistic control over the development of the package,
|
||||
while giving the users of the package the right to use and distribute
|
||||
the Package in a more-or-less customary fashion, plus the right to make
|
||||
reasonable modifications.
|
||||
|
||||
Definitions:
|
||||
|
||||
"Package" refers to the collection of files distributed by the
|
||||
Copyright Holder, and derivatives of that collection of files
|
||||
created through textual modification.
|
||||
|
||||
"Standard Version" refers to such a Package if it has not been
|
||||
modified, or has been modified in accordance with the wishes
|
||||
of the Copyright Holder as specified below.
|
||||
|
||||
"Copyright Holder" is whoever is named in the copyright or
|
||||
copyrights for the package.
|
||||
|
||||
"You" is you, if you're thinking about copying or distributing
|
||||
this Package.
|
||||
|
||||
"Reasonable copying fee" is whatever you can justify on the
|
||||
basis of media cost, duplication charges, time of people involved,
|
||||
and so on. (You will not be required to justify it to the
|
||||
Copyright Holder, but only to the computing community at large
|
||||
as a market that must bear the fee.)
|
||||
|
||||
"Freely Available" means that no fee is charged for the item
|
||||
itself, though there may be fees involved in handling the item.
|
||||
It also means that recipients of the item may redistribute it
|
||||
under the same conditions they received it.
|
||||
|
||||
1. You may make and give away verbatim copies of the source form of the
|
||||
Standard Version of this Package without restriction, provided that you
|
||||
duplicate all of the original copyright notices and associated disclaimers.
|
||||
|
||||
2. You may apply bug fixes, portability fixes and other modifications
|
||||
derived from the Public Domain or from the Copyright Holder. A Package
|
||||
modified in such a way shall still be considered the Standard Version.
|
||||
|
||||
3. You may otherwise modify your copy of this Package in any way, provided
|
||||
that you insert a prominent notice in each changed file stating how and
|
||||
when you changed that file, and provided that you do at least ONE of the
|
||||
following:
|
||||
|
||||
a) place your modifications in the Public Domain or otherwise make them
|
||||
Freely Available, such as by posting said modifications to Usenet or
|
||||
an equivalent medium, or placing the modifications on a major archive
|
||||
site such as uunet.uu.net, or by allowing the Copyright Holder to include
|
||||
your modifications in the Standard Version of the Package.
|
||||
|
||||
b) use the modified Package only within your corporation or organization.
|
||||
|
||||
c) rename any non-standard executables so the names do not conflict
|
||||
with standard executables, which must also be provided, and provide
|
||||
a separate manual page for each non-standard executable that clearly
|
||||
documents how it differs from the Standard Version.
|
||||
|
||||
d) make other distribution arrangements with the Copyright Holder.
|
||||
|
||||
4. You may distribute the programs of this Package in object code or
|
||||
executable form, provided that you do at least ONE of the following:
|
||||
|
||||
a) distribute a Standard Version of the executables and library files,
|
||||
together with instructions (in the manual page or equivalent) on where
|
||||
to get the Standard Version.
|
||||
|
||||
b) accompany the distribution with the machine-readable source of
|
||||
the Package with your modifications.
|
||||
|
||||
c) give non-standard executables non-standard names, and clearly
|
||||
document the differences in manual pages (or equivalent), together
|
||||
with instructions on where to get the Standard Version.
|
||||
|
||||
d) make other distribution arrangements with the Copyright Holder.
|
||||
|
||||
5. You may charge a reasonable copying fee for any distribution of this
|
||||
Package. You may charge any fee you choose for support of this
|
||||
Package. You may not charge a fee for this Package itself. However,
|
||||
you may distribute this Package in aggregate with other (possibly
|
||||
commercial) programs as part of a larger (possibly commercial) software
|
||||
distribution provided that you do not advertise this Package as a
|
||||
product of your own. You may embed this Package's interpreter within
|
||||
an executable of yours (by linking); this shall be construed as a mere
|
||||
form of aggregation, provided that the complete Standard Version of the
|
||||
interpreter is so embedded.
|
||||
|
||||
6. The source code and object code supplied as input to or produced as
|
||||
output from the programs of this Package do not automatically fall
|
||||
under the copyright of this Package, but belong to whoever generated
|
||||
them, and may be sold commercially, and may be aggregated with this
|
||||
Package.
|
||||
|
||||
7. Aggregation of this Package with a commercial distribution is always
|
||||
permitted provided that the use of this Package is embedded; that is,
|
||||
when no overt attempt is made to make this Package's interfaces visible
|
||||
to the end user of the commercial distribution. Such use shall not be
|
||||
construed as a distribution of this Package.
|
||||
|
||||
8. The name of the Copyright Holder may not be used to endorse or promote
|
||||
products derived from this software without specific prior written permission.
|
||||
|
||||
9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
The End
|
||||
1565
dmd2/attrib.c
Normal file
1565
dmd2/attrib.c
Normal file
File diff suppressed because it is too large
Load Diff
202
dmd2/attrib.h
Normal file
202
dmd2/attrib.h
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_ATTRIB_H
|
||||
#define DMD_ATTRIB_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
#include "dsymbol.h"
|
||||
|
||||
struct Expression;
|
||||
struct Statement;
|
||||
struct LabelDsymbol;
|
||||
struct Initializer;
|
||||
struct Module;
|
||||
struct Condition;
|
||||
struct HdrGenState;
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
struct AttribDeclaration : Dsymbol
|
||||
{
|
||||
Dsymbols *decl; // array of Dsymbol's
|
||||
|
||||
AttribDeclaration(Dsymbols *decl);
|
||||
virtual Dsymbols *include(Scope *sc, ScopeDsymbol *s);
|
||||
int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
|
||||
void setScopeNewSc(Scope *sc,
|
||||
StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection,
|
||||
unsigned structalign);
|
||||
void semanticNewSc(Scope *sc,
|
||||
StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection,
|
||||
unsigned structalign);
|
||||
void semantic(Scope *sc);
|
||||
void semantic2(Scope *sc);
|
||||
void semantic3(Scope *sc);
|
||||
void inlineScan();
|
||||
void addComment(unsigned char *comment);
|
||||
void emitComment(Scope *sc);
|
||||
const char *kind();
|
||||
int oneMember(Dsymbol **ps, Identifier *ident);
|
||||
int hasPointers();
|
||||
bool hasStaticCtorOrDtor();
|
||||
void checkCtorConstInit();
|
||||
void addLocalClass(ClassDeclarations *);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
void toJsonBuffer(OutBuffer *buf);
|
||||
AttribDeclaration *isAttribDeclaration() { return this; }
|
||||
|
||||
#if IN_DMD
|
||||
void toObjFile(int multiobj); // compile to .obj file
|
||||
int cvMember(unsigned char *p);
|
||||
#endif
|
||||
|
||||
#if IN_LLVM
|
||||
virtual void codegen(Ir*);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct StorageClassDeclaration: AttribDeclaration
|
||||
{
|
||||
StorageClass stc;
|
||||
|
||||
StorageClassDeclaration(StorageClass stc, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void setScope(Scope *sc);
|
||||
void semantic(Scope *sc);
|
||||
int oneMember(Dsymbol **ps, Identifier *ident);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
|
||||
static void stcToCBuffer(OutBuffer *buf, StorageClass stc);
|
||||
};
|
||||
|
||||
struct LinkDeclaration : AttribDeclaration
|
||||
{
|
||||
enum LINK linkage;
|
||||
|
||||
LinkDeclaration(enum LINK p, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void setScope(Scope *sc);
|
||||
void semantic(Scope *sc);
|
||||
void semantic3(Scope *sc);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
char *toChars();
|
||||
};
|
||||
|
||||
struct ProtDeclaration : AttribDeclaration
|
||||
{
|
||||
enum PROT protection;
|
||||
|
||||
ProtDeclaration(enum PROT p, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void importAll(Scope *sc);
|
||||
void setScope(Scope *sc);
|
||||
void semantic(Scope *sc);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
|
||||
static void protectionToCBuffer(OutBuffer *buf, enum PROT protection);
|
||||
};
|
||||
|
||||
struct AlignDeclaration : AttribDeclaration
|
||||
{
|
||||
unsigned salign;
|
||||
|
||||
AlignDeclaration(Loc loc, unsigned sa, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void setScope(Scope *sc);
|
||||
void semantic(Scope *sc);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
};
|
||||
|
||||
struct AnonDeclaration : AttribDeclaration
|
||||
{
|
||||
int isunion;
|
||||
int sem; // 1 if successful semantic()
|
||||
|
||||
AnonDeclaration(Loc loc, int isunion, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void semantic(Scope *sc);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
const char *kind();
|
||||
};
|
||||
|
||||
struct PragmaDeclaration : AttribDeclaration
|
||||
{
|
||||
Expressions *args; // array of Expression's
|
||||
|
||||
PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void semantic(Scope *sc);
|
||||
void setScope(Scope *sc);
|
||||
int oneMember(Dsymbol **ps, Identifier *ident);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
const char *kind();
|
||||
|
||||
#if IN_DMD
|
||||
void toObjFile(int multiobj); // compile to .obj file
|
||||
#endif
|
||||
|
||||
#if IN_LLVM
|
||||
void codegen(Ir*);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ConditionalDeclaration : AttribDeclaration
|
||||
{
|
||||
Condition *condition;
|
||||
Dsymbols *elsedecl; // array of Dsymbol's for else block
|
||||
|
||||
ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
int oneMember(Dsymbol **ps, Identifier *ident);
|
||||
void emitComment(Scope *sc);
|
||||
Dsymbols *include(Scope *sc, ScopeDsymbol *s);
|
||||
void addComment(unsigned char *comment);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
void toJsonBuffer(OutBuffer *buf);
|
||||
void importAll(Scope *sc);
|
||||
void setScope(Scope *sc);
|
||||
};
|
||||
|
||||
struct StaticIfDeclaration : ConditionalDeclaration
|
||||
{
|
||||
ScopeDsymbol *sd;
|
||||
int addisdone;
|
||||
|
||||
StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
|
||||
void semantic(Scope *sc);
|
||||
void importAll(Scope *sc);
|
||||
void setScope(Scope *sc);
|
||||
const char *kind();
|
||||
};
|
||||
|
||||
// Mixin declarations
|
||||
|
||||
struct CompileDeclaration : AttribDeclaration
|
||||
{
|
||||
Expression *exp;
|
||||
|
||||
ScopeDsymbol *sd;
|
||||
int compiled;
|
||||
|
||||
CompileDeclaration(Loc loc, Expression *exp);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
int addMember(Scope *sc, ScopeDsymbol *sd, int memnum);
|
||||
void compileIt(Scope *sc);
|
||||
void semantic(Scope *sc);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
};
|
||||
|
||||
#endif /* DMD_ATTRIB_H */
|
||||
234
dmd2/builtin.c
Normal file
234
dmd2/builtin.c
Normal file
@@ -0,0 +1,234 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2009 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#if __FreeBSD__
|
||||
extern "C"
|
||||
{
|
||||
long double sinl(long double);
|
||||
long double cosl(long double);
|
||||
long double tanl(long double);
|
||||
long double sqrtl(long double);
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "mars.h"
|
||||
#include "declaration.h"
|
||||
#include "attrib.h"
|
||||
#include "expression.h"
|
||||
#include "scope.h"
|
||||
#include "mtype.h"
|
||||
#include "aggregate.h"
|
||||
#include "identifier.h"
|
||||
#include "id.h"
|
||||
#include "module.h"
|
||||
|
||||
#if DMDV2
|
||||
|
||||
/**********************************
|
||||
* Determine if function is a builtin one that we can
|
||||
* evaluate at compile time.
|
||||
*/
|
||||
enum BUILTIN FuncDeclaration::isBuiltin()
|
||||
{
|
||||
static const char FeZe [] = "FNaNbNfeZe"; // @safe pure nothrow real function(real)
|
||||
static const char FeZe2[] = "FNaNbNeeZe"; // @trusted pure nothrow real function(real)
|
||||
static const char FuintZint[] = "FNaNbkZi"; // pure nothrow int function(uint)
|
||||
static const char FuintZuint[] = "FNaNbkZk"; // pure nothrow uint function(uint)
|
||||
static const char FulongZulong[] = "FNaNbkZk"; // pure nothrow int function(ulong)
|
||||
static const char FulongZint[] = "FNaNbmZi"; // pure nothrow int function(uint)
|
||||
static const char FrealrealZreal [] = "FNaNbNfeeZe"; // @safe pure nothrow real function(real, real)
|
||||
static const char FrealZlong [] = "FNaNbNfeZl"; // @safe pure nothrow long function(real)
|
||||
|
||||
//printf("FuncDeclaration::isBuiltin() %s, %d\n", toChars(), builtin);
|
||||
if (builtin == BUILTINunknown)
|
||||
{
|
||||
builtin = BUILTINnot;
|
||||
if (parent && parent->isModule())
|
||||
{
|
||||
// If it's in the std.math package
|
||||
if (parent->ident == Id::math &&
|
||||
parent->parent && (parent->parent->ident == Id::std || parent->parent->ident == Id::core) &&
|
||||
!parent->parent->parent)
|
||||
{
|
||||
//printf("deco = %s\n", type->deco);
|
||||
if (strcmp(type->deco, FeZe) == 0 || strcmp(type->deco, FeZe2) == 0)
|
||||
{
|
||||
if (ident == Id::sin)
|
||||
builtin = BUILTINsin;
|
||||
else if (ident == Id::cos)
|
||||
builtin = BUILTINcos;
|
||||
else if (ident == Id::tan)
|
||||
builtin = BUILTINtan;
|
||||
else if (ident == Id::_sqrt)
|
||||
builtin = BUILTINsqrt;
|
||||
else if (ident == Id::fabs)
|
||||
builtin = BUILTINfabs;
|
||||
else if (ident == Id::expm1)
|
||||
builtin = BUILTINexpm1;
|
||||
else if (ident == Id::exp2)
|
||||
builtin = BUILTINexp2;
|
||||
//printf("builtin = %d\n", builtin);
|
||||
}
|
||||
// if float or double versions
|
||||
else if (strcmp(type->deco, "FNaNbNfdZd") == 0 ||
|
||||
strcmp(type->deco, "FNaNbNffZf") == 0)
|
||||
{
|
||||
if (ident == Id::_sqrt)
|
||||
builtin = BUILTINsqrt;
|
||||
}
|
||||
else if (strcmp(type->deco, FrealrealZreal) == 0)
|
||||
{
|
||||
if (ident == Id::atan2)
|
||||
builtin = BUILTINatan2;
|
||||
else if (ident == Id::yl2x)
|
||||
builtin = BUILTINyl2x;
|
||||
else if (ident == Id::yl2xp1)
|
||||
builtin = BUILTINyl2xp1;
|
||||
}
|
||||
else if (strcmp(type->deco, FrealZlong) == 0 && ident == Id::rndtol)
|
||||
builtin = BUILTINrndtol;
|
||||
}
|
||||
if (parent->ident == Id::bitop &&
|
||||
parent->parent && parent->parent->ident == Id::core &&
|
||||
!parent->parent->parent)
|
||||
{
|
||||
//printf("deco = %s\n", type->deco);
|
||||
if (strcmp(type->deco, FuintZint) == 0 || strcmp(type->deco, FulongZint) == 0)
|
||||
{
|
||||
if (ident == Id::bsf)
|
||||
builtin = BUILTINbsf;
|
||||
else if (ident == Id::bsr)
|
||||
builtin = BUILTINbsr;
|
||||
}
|
||||
else if (strcmp(type->deco, FuintZuint) == 0)
|
||||
{
|
||||
if (ident == Id::bswap)
|
||||
builtin = BUILTINbswap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return builtin;
|
||||
}
|
||||
|
||||
int eval_bsf(uinteger_t n)
|
||||
{
|
||||
n = (n ^ (n - 1)) >> 1; // convert trailing 0s to 1, and zero rest
|
||||
int k = 0;
|
||||
while( n )
|
||||
{ ++k;
|
||||
n >>=1;
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
int eval_bsr(uinteger_t n)
|
||||
{ int k= 0;
|
||||
while(n>>=1)
|
||||
{
|
||||
++k;
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
uinteger_t eval_bswap(Expression *arg0)
|
||||
{ uinteger_t n = arg0->toInteger();
|
||||
#define BYTEMASK 0x00FF00FF00FF00FFLL
|
||||
#define SHORTMASK 0x0000FFFF0000FFFFLL
|
||||
#define INTMASK 0x0000FFFF0000FFFFLL
|
||||
// swap adjacent ubytes
|
||||
n = ((n >> 8 ) & BYTEMASK) | ((n & BYTEMASK) << 8 );
|
||||
// swap adjacent ushorts
|
||||
n = ((n >> 16) & SHORTMASK) | ((n & SHORTMASK) << 16);
|
||||
TY ty = arg0->type->toBasetype()->ty;
|
||||
// If 64 bits, we need to swap high and low uints
|
||||
if (ty == Tint64 || ty == Tuns64)
|
||||
n = ((n >> 32) & INTMASK) | ((n & INTMASK) << 32);
|
||||
return n;
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Evaluate builtin function.
|
||||
* Return result; NULL if cannot evaluate it.
|
||||
*/
|
||||
|
||||
Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments)
|
||||
{
|
||||
assert(arguments && arguments->dim);
|
||||
Expression *arg0 = arguments->tdata()[0];
|
||||
Expression *e = NULL;
|
||||
switch (builtin)
|
||||
{
|
||||
case BUILTINsin:
|
||||
if (arg0->op == TOKfloat64)
|
||||
e = new RealExp(0, sinl(arg0->toReal()), arg0->type);
|
||||
break;
|
||||
|
||||
case BUILTINcos:
|
||||
if (arg0->op == TOKfloat64)
|
||||
e = new RealExp(0, cosl(arg0->toReal()), arg0->type);
|
||||
break;
|
||||
|
||||
case BUILTINtan:
|
||||
if (arg0->op == TOKfloat64)
|
||||
e = new RealExp(0, tanl(arg0->toReal()), arg0->type);
|
||||
break;
|
||||
|
||||
case BUILTINsqrt:
|
||||
if (arg0->op == TOKfloat64)
|
||||
e = new RealExp(0, sqrtl(arg0->toReal()), arg0->type);
|
||||
break;
|
||||
|
||||
case BUILTINfabs:
|
||||
if (arg0->op == TOKfloat64)
|
||||
e = new RealExp(0, fabsl(arg0->toReal()), arg0->type);
|
||||
break;
|
||||
// These math intrinsics are not yet implemented
|
||||
case BUILTINatan2:
|
||||
break;
|
||||
case BUILTINrndtol:
|
||||
break;
|
||||
case BUILTINexpm1:
|
||||
break;
|
||||
case BUILTINexp2:
|
||||
break;
|
||||
case BUILTINyl2x:
|
||||
break;
|
||||
case BUILTINyl2xp1:
|
||||
break;
|
||||
case BUILTINbsf:
|
||||
if (arg0->op == TOKint64)
|
||||
{ if (arg0->toInteger()==0)
|
||||
error(loc, "bsf(0) is undefined");
|
||||
else
|
||||
e = new IntegerExp(loc, eval_bsf(arg0->toInteger()), Type::tint32);
|
||||
}
|
||||
break;
|
||||
case BUILTINbsr:
|
||||
if (arg0->op == TOKint64)
|
||||
{ if (arg0->toInteger()==0)
|
||||
error(loc, "bsr(0) is undefined");
|
||||
else
|
||||
e = new IntegerExp(loc, eval_bsr(arg0->toInteger()), Type::tint32);
|
||||
}
|
||||
break;
|
||||
case BUILTINbswap:
|
||||
if (arg0->op == TOKint64)
|
||||
e = new IntegerExp(loc, eval_bswap(arg0), arg0->type);
|
||||
break;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
#endif
|
||||
189
dmd2/canthrow.c
Normal file
189
dmd2/canthrow.c
Normal file
@@ -0,0 +1,189 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mars.h"
|
||||
#include "init.h"
|
||||
#include "expression.h"
|
||||
#include "template.h"
|
||||
#include "statement.h"
|
||||
#include "mtype.h"
|
||||
#include "utf.h"
|
||||
#include "declaration.h"
|
||||
#include "aggregate.h"
|
||||
#include "scope.h"
|
||||
#include "attrib.h"
|
||||
|
||||
int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow);
|
||||
int lambdaCanThrow(Expression *e, void *param);
|
||||
|
||||
/********************************************
|
||||
* Convert from expression to delegate that returns the expression,
|
||||
* i.e. convert:
|
||||
* expr
|
||||
* to:
|
||||
* t delegate() { return expr; }
|
||||
*/
|
||||
|
||||
struct CanThrow
|
||||
{
|
||||
bool can;
|
||||
bool mustnot;
|
||||
};
|
||||
|
||||
int Expression::canThrow(bool mustNotThrow)
|
||||
{
|
||||
CanThrow ct;
|
||||
ct.can = FALSE;
|
||||
ct.mustnot = mustNotThrow;
|
||||
apply(&lambdaCanThrow, &ct);
|
||||
return ct.can;
|
||||
}
|
||||
|
||||
int lambdaCanThrow(Expression *e, void *param)
|
||||
{
|
||||
CanThrow *pct = (CanThrow *)param;
|
||||
switch (e->op)
|
||||
{
|
||||
case TOKdeclaration:
|
||||
{ DeclarationExp *de = (DeclarationExp *)e;
|
||||
pct->can = Dsymbol_canThrow(de->declaration, pct->mustnot);
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKcall:
|
||||
{ CallExp *ce = (CallExp *)e;
|
||||
|
||||
if (global.errors && !ce->e1->type)
|
||||
break; // error recovery
|
||||
|
||||
/* If calling a function or delegate that is typed as nothrow,
|
||||
* then this expression cannot throw.
|
||||
* Note that pure functions can throw.
|
||||
*/
|
||||
Type *t = ce->e1->type->toBasetype();
|
||||
if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow)
|
||||
;
|
||||
else if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow)
|
||||
;
|
||||
else
|
||||
{
|
||||
if (pct->mustnot)
|
||||
e->error("%s is not nothrow", ce->e1->toChars());
|
||||
pct->can = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKnew:
|
||||
{ NewExp *ne = (NewExp *)e;
|
||||
if (ne->member)
|
||||
{
|
||||
// See if constructor call can throw
|
||||
Type *t = ne->member->type->toBasetype();
|
||||
if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
|
||||
{
|
||||
if (pct->mustnot)
|
||||
e->error("constructor %s is not nothrow", ne->member->toChars());
|
||||
pct->can = TRUE;
|
||||
}
|
||||
}
|
||||
// regard storage allocation failures as not recoverable
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKnewanonclass:
|
||||
assert(0); // should have been lowered by semantic()
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return pct->can; // stop walking if we determine this expression can throw
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Does symbol, when initialized, throw?
|
||||
* Mirrors logic in Dsymbol_toElem().
|
||||
*/
|
||||
|
||||
int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow)
|
||||
{
|
||||
AttribDeclaration *ad;
|
||||
VarDeclaration *vd;
|
||||
TemplateMixin *tm;
|
||||
TupleDeclaration *td;
|
||||
|
||||
//printf("Dsymbol_toElem() %s\n", s->toChars());
|
||||
ad = s->isAttribDeclaration();
|
||||
if (ad)
|
||||
{
|
||||
Dsymbols *decl = ad->include(NULL, NULL);
|
||||
if (decl && decl->dim)
|
||||
{
|
||||
for (size_t i = 0; i < decl->dim; i++)
|
||||
{
|
||||
s = decl->tdata()[i];
|
||||
if (Dsymbol_canThrow(s, mustNotThrow))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((vd = s->isVarDeclaration()) != NULL)
|
||||
{
|
||||
s = s->toAlias();
|
||||
if (s != vd)
|
||||
return Dsymbol_canThrow(s, mustNotThrow);
|
||||
if (vd->storage_class & STCmanifest)
|
||||
;
|
||||
else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared))
|
||||
;
|
||||
else
|
||||
{
|
||||
if (vd->init)
|
||||
{ ExpInitializer *ie = vd->init->isExpInitializer();
|
||||
if (ie && ie->exp->canThrow(mustNotThrow))
|
||||
return 1;
|
||||
}
|
||||
if (vd->edtor && !vd->noscope)
|
||||
return vd->edtor->canThrow(mustNotThrow);
|
||||
}
|
||||
}
|
||||
else if ((tm = s->isTemplateMixin()) != NULL)
|
||||
{
|
||||
//printf("%s\n", tm->toChars());
|
||||
if (tm->members)
|
||||
{
|
||||
for (size_t i = 0; i < tm->members->dim; i++)
|
||||
{
|
||||
Dsymbol *sm = tm->members->tdata()[i];
|
||||
if (Dsymbol_canThrow(sm, mustNotThrow))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((td = s->isTupleDeclaration()) != NULL)
|
||||
{
|
||||
for (size_t i = 0; i < td->objects->dim; i++)
|
||||
{ Object *o = td->objects->tdata()[i];
|
||||
if (o->dyncast() == DYNCAST_EXPRESSION)
|
||||
{ Expression *eo = (Expression *)o;
|
||||
if (eo->op == TOKdsymbol)
|
||||
{ DsymbolExp *se = (DsymbolExp *)eo;
|
||||
if (Dsymbol_canThrow(se->s, mustNotThrow))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
2641
dmd2/cast.c
Normal file
2641
dmd2/cast.c
Normal file
File diff suppressed because it is too large
Load Diff
1656
dmd2/class.c
Normal file
1656
dmd2/class.c
Normal file
File diff suppressed because it is too large
Load Diff
694
dmd2/clone.c
Normal file
694
dmd2/clone.c
Normal file
@@ -0,0 +1,694 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "root.h"
|
||||
#include "aggregate.h"
|
||||
#include "scope.h"
|
||||
#include "mtype.h"
|
||||
#include "declaration.h"
|
||||
#include "module.h"
|
||||
#include "id.h"
|
||||
#include "expression.h"
|
||||
#include "statement.h"
|
||||
#include "init.h"
|
||||
#include "template.h"
|
||||
|
||||
|
||||
/*******************************************
|
||||
* We need an opAssign for the struct if
|
||||
* it has a destructor or a postblit.
|
||||
* We need to generate one if a user-specified one does not exist.
|
||||
*/
|
||||
|
||||
int StructDeclaration::needOpAssign()
|
||||
{
|
||||
#define X 0
|
||||
if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars());
|
||||
if (hasIdentityAssign)
|
||||
goto Ldontneed;
|
||||
|
||||
if (dtor || postblit)
|
||||
goto Lneed;
|
||||
|
||||
/* If any of the fields need an opAssign, then we
|
||||
* need it too.
|
||||
*/
|
||||
for (size_t i = 0; i < fields.dim; i++)
|
||||
{
|
||||
Dsymbol *s = fields.tdata()[i];
|
||||
VarDeclaration *v = s->isVarDeclaration();
|
||||
assert(v && v->storage_class & STCfield);
|
||||
if (v->storage_class & STCref)
|
||||
continue;
|
||||
Type *tv = v->type->toBasetype();
|
||||
while (tv->ty == Tsarray)
|
||||
{ TypeSArray *ta = (TypeSArray *)tv;
|
||||
tv = tv->nextOf()->toBasetype();
|
||||
}
|
||||
if (tv->ty == Tstruct)
|
||||
{ TypeStruct *ts = (TypeStruct *)tv;
|
||||
StructDeclaration *sd = ts->sym;
|
||||
if (sd->needOpAssign())
|
||||
goto Lneed;
|
||||
}
|
||||
}
|
||||
Ldontneed:
|
||||
if (X) printf("\tdontneed\n");
|
||||
return 0;
|
||||
|
||||
Lneed:
|
||||
if (X) printf("\tneed\n");
|
||||
return 1;
|
||||
#undef X
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Build opAssign for struct.
|
||||
* S* opAssign(S s) { ... }
|
||||
*
|
||||
* Note that s will be constructed onto the stack, probably copy-constructed.
|
||||
* Then, the body is:
|
||||
* S tmp = *this; // bit copy
|
||||
* *this = s; // bit copy
|
||||
* tmp.dtor();
|
||||
* Instead of running the destructor on s, run it on tmp instead.
|
||||
*/
|
||||
|
||||
FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
|
||||
{
|
||||
if (!needOpAssign())
|
||||
return NULL;
|
||||
|
||||
//printf("StructDeclaration::buildOpAssign() %s\n", toChars());
|
||||
|
||||
FuncDeclaration *fop = NULL;
|
||||
|
||||
Parameters *fparams = new Parameters;
|
||||
fparams->push(new Parameter(STCnodtor, type, Id::p, NULL));
|
||||
Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd);
|
||||
#if STRUCTTHISREF
|
||||
((TypeFunction *)ftype)->isref = 1;
|
||||
#endif
|
||||
|
||||
fop = new FuncDeclaration(loc, 0, Id::assign, STCundefined, ftype);
|
||||
|
||||
Expression *e = NULL;
|
||||
if (postblit)
|
||||
{ /* Swap:
|
||||
* tmp = *this; *this = s; tmp.dtor();
|
||||
*/
|
||||
//printf("\tswap copy\n");
|
||||
Identifier *idtmp = Lexer::uniqueId("__tmp");
|
||||
VarDeclaration *tmp;
|
||||
AssignExp *ec = NULL;
|
||||
if (dtor)
|
||||
{
|
||||
tmp = new VarDeclaration(0, type, idtmp, new VoidInitializer(0));
|
||||
tmp->noscope = 1;
|
||||
tmp->storage_class |= STCctfe;
|
||||
e = new DeclarationExp(0, tmp);
|
||||
ec = new AssignExp(0,
|
||||
new VarExp(0, tmp),
|
||||
#if STRUCTTHISREF
|
||||
new ThisExp(0)
|
||||
#else
|
||||
new PtrExp(0, new ThisExp(0))
|
||||
#endif
|
||||
);
|
||||
ec->op = TOKblit;
|
||||
e = Expression::combine(e, ec);
|
||||
}
|
||||
ec = new AssignExp(0,
|
||||
#if STRUCTTHISREF
|
||||
new ThisExp(0),
|
||||
#else
|
||||
new PtrExp(0, new ThisExp(0)),
|
||||
#endif
|
||||
new IdentifierExp(0, Id::p));
|
||||
ec->op = TOKblit;
|
||||
e = Expression::combine(e, ec);
|
||||
if (dtor)
|
||||
{
|
||||
/* Instead of running the destructor on s, run it
|
||||
* on tmp. This avoids needing to copy tmp back in to s.
|
||||
*/
|
||||
Expression *ec2 = new DotVarExp(0, new VarExp(0, tmp), dtor, 0);
|
||||
ec2 = new CallExp(0, ec2);
|
||||
e = Expression::combine(e, ec2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* Do memberwise copy
|
||||
*/
|
||||
//printf("\tmemberwise copy\n");
|
||||
for (size_t i = 0; i < fields.dim; i++)
|
||||
{
|
||||
Dsymbol *s = fields.tdata()[i];
|
||||
VarDeclaration *v = s->isVarDeclaration();
|
||||
assert(v && v->storage_class & STCfield);
|
||||
// this.v = s.v;
|
||||
AssignExp *ec = new AssignExp(0,
|
||||
new DotVarExp(0, new ThisExp(0), v, 0),
|
||||
new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0));
|
||||
ec->op = TOKblit;
|
||||
e = Expression::combine(e, ec);
|
||||
}
|
||||
}
|
||||
Statement *s1 = new ExpStatement(0, e);
|
||||
|
||||
/* Add:
|
||||
* return this;
|
||||
*/
|
||||
e = new ThisExp(0);
|
||||
Statement *s2 = new ReturnStatement(0, e);
|
||||
|
||||
fop->fbody = new CompoundStatement(0, s1, s2);
|
||||
|
||||
members->push(fop);
|
||||
fop->addMember(sc, this, 1);
|
||||
|
||||
sc = sc->push();
|
||||
sc->stc = 0;
|
||||
sc->linkage = LINKd;
|
||||
|
||||
fop->semantic(sc);
|
||||
|
||||
sc->pop();
|
||||
|
||||
//printf("-StructDeclaration::buildOpAssign() %s\n", toChars());
|
||||
|
||||
return fop;
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* We need an opEquals for the struct if
|
||||
* any fields has an opEquals.
|
||||
* Generate one if a user-specified one does not exist.
|
||||
*/
|
||||
|
||||
int StructDeclaration::needOpEquals()
|
||||
{
|
||||
#define X 0
|
||||
if (X) printf("StructDeclaration::needOpEquals() %s\n", toChars());
|
||||
|
||||
if (hasIdentityEquals)
|
||||
goto Lneed;
|
||||
|
||||
/* If any of the fields has an opEquals, then we
|
||||
* need it too.
|
||||
*/
|
||||
for (size_t i = 0; i < fields.dim; i++)
|
||||
{
|
||||
Dsymbol *s = fields.tdata()[i];
|
||||
VarDeclaration *v = s->isVarDeclaration();
|
||||
assert(v && v->storage_class & STCfield);
|
||||
if (v->storage_class & STCref)
|
||||
continue;
|
||||
Type *tv = v->type->toBasetype();
|
||||
while (tv->ty == Tsarray)
|
||||
{ TypeSArray *ta = (TypeSArray *)tv;
|
||||
tv = tv->nextOf()->toBasetype();
|
||||
}
|
||||
if (tv->ty == Tstruct)
|
||||
{ TypeStruct *ts = (TypeStruct *)tv;
|
||||
StructDeclaration *sd = ts->sym;
|
||||
if (sd->needOpEquals())
|
||||
goto Lneed;
|
||||
}
|
||||
}
|
||||
if (X) printf("\tdontneed\n");
|
||||
return 0;
|
||||
|
||||
Lneed:
|
||||
if (X) printf("\tneed\n");
|
||||
return 1;
|
||||
#undef X
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Build opEquals for struct.
|
||||
* const bool opEquals(const S s) { ... }
|
||||
*/
|
||||
|
||||
FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc)
|
||||
{
|
||||
Dsymbol *eq = search_function(this, Id::eq);
|
||||
if (eq)
|
||||
{
|
||||
for (size_t i = 0; i <= 1; i++)
|
||||
{
|
||||
Expression *e =
|
||||
i == 0 ? new NullExp(loc, type->constOf()) // dummy rvalue
|
||||
: type->constOf()->defaultInit(); // dummy lvalue
|
||||
Expressions *arguments = new Expressions();
|
||||
arguments->push(e);
|
||||
|
||||
// check identity opEquals exists
|
||||
FuncDeclaration *fd = eq->isFuncDeclaration();
|
||||
if (fd)
|
||||
{ fd = fd->overloadResolve(loc, e, arguments, 1);
|
||||
if (fd && !(fd->storage_class & STCdisable))
|
||||
return fd;
|
||||
}
|
||||
|
||||
TemplateDeclaration *td = eq->isTemplateDeclaration();
|
||||
if (td)
|
||||
{ fd = td->deduceFunctionTemplate(sc, loc, NULL, e, arguments, 1);
|
||||
if (fd && !(fd->storage_class & STCdisable))
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!needOpEquals())
|
||||
return NULL;
|
||||
|
||||
//printf("StructDeclaration::buildOpEquals() %s\n", toChars());
|
||||
|
||||
Parameters *parameters = new Parameters;
|
||||
parameters->push(new Parameter(STCin, type, Id::p, NULL));
|
||||
TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
|
||||
tf->mod = MODconst;
|
||||
tf = (TypeFunction *)tf->semantic(loc, sc);
|
||||
|
||||
FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::eq, STCundefined, tf);
|
||||
|
||||
Expression *e = NULL;
|
||||
/* Do memberwise compare
|
||||
*/
|
||||
//printf("\tmemberwise compare\n");
|
||||
for (size_t i = 0; i < fields.dim; i++)
|
||||
{
|
||||
Dsymbol *s = fields.tdata()[i];
|
||||
VarDeclaration *v = s->isVarDeclaration();
|
||||
assert(v && v->storage_class & STCfield);
|
||||
if (v->storage_class & STCref)
|
||||
assert(0); // what should we do with this?
|
||||
// this.v == s.v;
|
||||
EqualExp *ec = new EqualExp(TOKequal, loc,
|
||||
new DotVarExp(loc, new ThisExp(loc), v, 0),
|
||||
new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0));
|
||||
if (e)
|
||||
e = new AndAndExp(loc, e, ec);
|
||||
else
|
||||
e = ec;
|
||||
}
|
||||
if (!e)
|
||||
e = new IntegerExp(loc, 1, Type::tbool);
|
||||
fop->fbody = new ReturnStatement(loc, e);
|
||||
|
||||
members->push(fop);
|
||||
fop->addMember(sc, this, 1);
|
||||
|
||||
sc = sc->push();
|
||||
sc->stc = 0;
|
||||
sc->linkage = LINKd;
|
||||
|
||||
fop->semantic(sc);
|
||||
|
||||
sc->pop();
|
||||
|
||||
//printf("-StructDeclaration::buildOpEquals() %s\n", toChars());
|
||||
|
||||
return fop;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Build __xopEquals for TypeInfo_Struct
|
||||
* bool __xopEquals(in void* p, in void* q) { ... }
|
||||
*/
|
||||
|
||||
FuncDeclaration *StructDeclaration::buildXopEquals(Scope *sc)
|
||||
{
|
||||
if (!search_function(this, Id::eq))
|
||||
return NULL;
|
||||
|
||||
/* static bool__xopEquals(in void* p, in void* q) {
|
||||
* return ( *cast(const S*)(p) ).opEquals( *cast(const S*)(q) );
|
||||
* }
|
||||
*/
|
||||
|
||||
Parameters *parameters = new Parameters;
|
||||
parameters->push(new Parameter(STCin, Type::tvoidptr, Id::p, NULL));
|
||||
parameters->push(new Parameter(STCin, Type::tvoidptr, Id::q, NULL));
|
||||
TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
|
||||
tf = (TypeFunction *)tf->semantic(loc, sc);
|
||||
|
||||
Identifier *id = Lexer::idPool("__xopEquals");
|
||||
FuncDeclaration *fop = new FuncDeclaration(loc, 0, id, STCstatic, tf);
|
||||
|
||||
Expression *e = new CallExp(0,
|
||||
new DotIdExp(0,
|
||||
new PtrExp(0, new CastExp(0,
|
||||
new IdentifierExp(0, Id::p), type->pointerTo()->constOf())),
|
||||
Id::eq),
|
||||
new PtrExp(0, new CastExp(0,
|
||||
new IdentifierExp(0, Id::q), type->pointerTo()->constOf())));
|
||||
|
||||
fop->fbody = new ReturnStatement(loc, e);
|
||||
|
||||
size_t index = members->dim;
|
||||
members->push(fop);
|
||||
|
||||
sc = sc->push();
|
||||
sc->stc = 0;
|
||||
sc->linkage = LINKd;
|
||||
|
||||
unsigned errors = global.startGagging();
|
||||
fop->semantic(sc);
|
||||
if (errors == global.gaggedErrors)
|
||||
{ fop->semantic2(sc);
|
||||
if (errors == global.gaggedErrors)
|
||||
{ fop->semantic3(sc);
|
||||
if (errors == global.gaggedErrors)
|
||||
fop->addMember(sc, this, 1);
|
||||
}
|
||||
}
|
||||
if (global.endGagging(errors)) // if errors happened
|
||||
{
|
||||
members->remove(index);
|
||||
|
||||
if (!xerreq)
|
||||
{
|
||||
Expression *e = new IdentifierExp(loc, Id::empty);
|
||||
e = new DotIdExp(loc, e, Id::object);
|
||||
e = new DotIdExp(loc, e, Lexer::idPool("_xopEquals"));
|
||||
e = e->semantic(sc);
|
||||
Dsymbol *s = getDsymbol(e);
|
||||
FuncDeclaration *fd = s->isFuncDeclaration();
|
||||
|
||||
xerreq = fd;
|
||||
}
|
||||
fop = xerreq;
|
||||
}
|
||||
|
||||
sc->pop();
|
||||
|
||||
return fop;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************
|
||||
* Build copy constructor for struct.
|
||||
* Copy constructors are compiler generated only, and are only
|
||||
* callable from the compiler. They are not user accessible.
|
||||
* A copy constructor is:
|
||||
* void cpctpr(ref const S s) const
|
||||
* {
|
||||
* (*cast(S*)&this) = *cast(S*)s;
|
||||
* (*cast(S*)&this).postBlit();
|
||||
* }
|
||||
* This is done so:
|
||||
* - postBlit() never sees uninitialized data
|
||||
* - memcpy can be much more efficient than memberwise copy
|
||||
* - no fields are overlooked
|
||||
*/
|
||||
|
||||
FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
|
||||
{
|
||||
//printf("StructDeclaration::buildCpCtor() %s\n", toChars());
|
||||
FuncDeclaration *fcp = NULL;
|
||||
|
||||
/* Copy constructor is only necessary if there is a postblit function,
|
||||
* otherwise the code generator will just do a bit copy.
|
||||
*/
|
||||
if (postblit)
|
||||
{
|
||||
//printf("generating cpctor\n");
|
||||
|
||||
StorageClass stc = postblit->storage_class &
|
||||
(STCdisable | STCsafe | STCtrusted | STCsystem | STCpure | STCnothrow);
|
||||
if (stc & (STCsafe | STCtrusted))
|
||||
stc = stc & ~STCsafe | STCtrusted;
|
||||
|
||||
Parameters *fparams = new Parameters;
|
||||
fparams->push(new Parameter(STCref, type->constOf(), Id::p, NULL));
|
||||
Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd, stc);
|
||||
ftype->mod = MODconst;
|
||||
|
||||
fcp = new FuncDeclaration(loc, 0, Id::cpctor, stc, ftype);
|
||||
|
||||
if (!(fcp->storage_class & STCdisable))
|
||||
{
|
||||
// Build *this = p;
|
||||
Expression *e = new ThisExp(0);
|
||||
#if !STRUCTTHISREF
|
||||
e = new PtrExp(0, e);
|
||||
#endif
|
||||
AssignExp *ea = new AssignExp(0,
|
||||
new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo())),
|
||||
new PtrExp(0, new CastExp(0, new AddrExp(0, new IdentifierExp(0, Id::p)), type->mutableOf()->pointerTo()))
|
||||
);
|
||||
ea->op = TOKblit;
|
||||
Statement *s = new ExpStatement(0, ea);
|
||||
|
||||
// Build postBlit();
|
||||
e = new ThisExp(0);
|
||||
#if !STRUCTTHISREF
|
||||
e = new PtrExp(0, e);
|
||||
#endif
|
||||
e = new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo()));
|
||||
e = new DotVarExp(0, e, postblit, 0);
|
||||
e = new CallExp(0, e);
|
||||
|
||||
s = new CompoundStatement(0, s, new ExpStatement(0, e));
|
||||
fcp->fbody = s;
|
||||
}
|
||||
else
|
||||
fcp->fbody = new ExpStatement(0, (Expression *)NULL);
|
||||
|
||||
members->push(fcp);
|
||||
|
||||
sc = sc->push();
|
||||
sc->stc = 0;
|
||||
sc->linkage = LINKd;
|
||||
|
||||
fcp->semantic(sc);
|
||||
|
||||
sc->pop();
|
||||
}
|
||||
|
||||
return fcp;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Create inclusive postblit for struct by aggregating
|
||||
* all the postblits in postblits[] with the postblits for
|
||||
* all the members.
|
||||
* Note the close similarity with AggregateDeclaration::buildDtor(),
|
||||
* and the ordering changes (runs forward instead of backwards).
|
||||
*/
|
||||
|
||||
#if DMDV2
|
||||
FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc)
|
||||
{
|
||||
//printf("StructDeclaration::buildPostBlit() %s\n", toChars());
|
||||
Expression *e = NULL;
|
||||
StorageClass stc = 0;
|
||||
|
||||
for (size_t i = 0; i < fields.dim; i++)
|
||||
{
|
||||
Dsymbol *s = fields.tdata()[i];
|
||||
VarDeclaration *v = s->isVarDeclaration();
|
||||
assert(v && v->storage_class & STCfield);
|
||||
if (v->storage_class & STCref)
|
||||
continue;
|
||||
Type *tv = v->type->toBasetype();
|
||||
dinteger_t dim = (tv->ty == Tsarray ? 1 : 0);
|
||||
while (tv->ty == Tsarray)
|
||||
{ TypeSArray *ta = (TypeSArray *)tv;
|
||||
dim *= ((TypeSArray *)tv)->dim->toInteger();
|
||||
tv = tv->nextOf()->toBasetype();
|
||||
}
|
||||
if (tv->ty == Tstruct)
|
||||
{ TypeStruct *ts = (TypeStruct *)tv;
|
||||
StructDeclaration *sd = ts->sym;
|
||||
if (sd->postblit)
|
||||
{
|
||||
stc |= sd->postblit->storage_class & STCdisable;
|
||||
|
||||
if (stc & STCdisable)
|
||||
{
|
||||
e = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
// this.v
|
||||
Expression *ex = new ThisExp(0);
|
||||
ex = new DotVarExp(0, ex, v, 0);
|
||||
|
||||
if (dim == 0)
|
||||
{ // this.v.postblit()
|
||||
ex = new DotVarExp(0, ex, sd->postblit, 0);
|
||||
ex = new CallExp(0, ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Typeinfo.postblit(cast(void*)&this.v);
|
||||
Expression *ea = new AddrExp(0, ex);
|
||||
ea = new CastExp(0, ea, Type::tvoid->pointerTo());
|
||||
|
||||
Expression *et = v->type->getTypeInfo(sc);
|
||||
et = new DotIdExp(0, et, Id::postblit);
|
||||
|
||||
ex = new CallExp(0, et, ea);
|
||||
}
|
||||
e = Expression::combine(e, ex); // combine in forward order
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Build our own "postblit" which executes e
|
||||
*/
|
||||
if (e || (stc & STCdisable))
|
||||
{ //printf("Building __fieldPostBlit()\n");
|
||||
PostBlitDeclaration *dd = new PostBlitDeclaration(loc, 0, Lexer::idPool("__fieldPostBlit"));
|
||||
dd->storage_class |= stc;
|
||||
dd->fbody = new ExpStatement(0, e);
|
||||
postblits.shift(dd);
|
||||
members->push(dd);
|
||||
dd->semantic(sc);
|
||||
}
|
||||
|
||||
switch (postblits.dim)
|
||||
{
|
||||
case 0:
|
||||
return NULL;
|
||||
|
||||
case 1:
|
||||
return postblits.tdata()[0];
|
||||
|
||||
default:
|
||||
e = NULL;
|
||||
for (size_t i = 0; i < postblits.dim; i++)
|
||||
{ FuncDeclaration *fd = postblits.tdata()[i];
|
||||
stc |= fd->storage_class & STCdisable;
|
||||
if (stc & STCdisable)
|
||||
{
|
||||
e = NULL;
|
||||
break;
|
||||
}
|
||||
Expression *ex = new ThisExp(0);
|
||||
ex = new DotVarExp(0, ex, fd, 0);
|
||||
ex = new CallExp(0, ex);
|
||||
e = Expression::combine(e, ex);
|
||||
}
|
||||
PostBlitDeclaration *dd = new PostBlitDeclaration(loc, 0, Lexer::idPool("__aggrPostBlit"));
|
||||
dd->storage_class |= stc;
|
||||
dd->fbody = new ExpStatement(0, e);
|
||||
members->push(dd);
|
||||
dd->semantic(sc);
|
||||
return dd;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************
|
||||
* Create inclusive destructor for struct/class by aggregating
|
||||
* all the destructors in dtors[] with the destructors for
|
||||
* all the members.
|
||||
* Note the close similarity with StructDeclaration::buildPostBlit(),
|
||||
* and the ordering changes (runs backward instead of forwards).
|
||||
*/
|
||||
|
||||
FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc)
|
||||
{
|
||||
//printf("AggregateDeclaration::buildDtor() %s\n", toChars());
|
||||
Expression *e = NULL;
|
||||
|
||||
#if DMDV2
|
||||
for (size_t i = 0; i < fields.dim; i++)
|
||||
{
|
||||
Dsymbol *s = fields.tdata()[i];
|
||||
VarDeclaration *v = s->isVarDeclaration();
|
||||
assert(v && v->storage_class & STCfield);
|
||||
if (v->storage_class & STCref)
|
||||
continue;
|
||||
Type *tv = v->type->toBasetype();
|
||||
dinteger_t dim = (tv->ty == Tsarray ? 1 : 0);
|
||||
while (tv->ty == Tsarray)
|
||||
{ TypeSArray *ta = (TypeSArray *)tv;
|
||||
dim *= ((TypeSArray *)tv)->dim->toInteger();
|
||||
tv = tv->nextOf()->toBasetype();
|
||||
}
|
||||
if (tv->ty == Tstruct)
|
||||
{ TypeStruct *ts = (TypeStruct *)tv;
|
||||
StructDeclaration *sd = ts->sym;
|
||||
if (sd->dtor)
|
||||
{ Expression *ex;
|
||||
|
||||
// this.v
|
||||
ex = new ThisExp(0);
|
||||
ex = new DotVarExp(0, ex, v, 0);
|
||||
|
||||
if (dim == 0)
|
||||
{ // this.v.dtor()
|
||||
ex = new DotVarExp(0, ex, sd->dtor, 0);
|
||||
ex = new CallExp(0, ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Typeinfo.destroy(cast(void*)&this.v);
|
||||
Expression *ea = new AddrExp(0, ex);
|
||||
ea = new CastExp(0, ea, Type::tvoid->pointerTo());
|
||||
|
||||
Expression *et = v->type->getTypeInfo(sc);
|
||||
et = new DotIdExp(0, et, Id::destroy);
|
||||
|
||||
ex = new CallExp(0, et, ea);
|
||||
}
|
||||
e = Expression::combine(ex, e); // combine in reverse order
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Build our own "destructor" which executes e
|
||||
*/
|
||||
if (e)
|
||||
{ //printf("Building __fieldDtor()\n");
|
||||
DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__fieldDtor"));
|
||||
dd->fbody = new ExpStatement(0, e);
|
||||
dtors.shift(dd);
|
||||
members->push(dd);
|
||||
dd->semantic(sc);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (dtors.dim)
|
||||
{
|
||||
case 0:
|
||||
return NULL;
|
||||
|
||||
case 1:
|
||||
return dtors.tdata()[0];
|
||||
|
||||
default:
|
||||
e = NULL;
|
||||
for (size_t i = 0; i < dtors.dim; i++)
|
||||
{ FuncDeclaration *fd = dtors.tdata()[i];
|
||||
Expression *ex = new ThisExp(0);
|
||||
ex = new DotVarExp(0, ex, fd, 0);
|
||||
ex = new CallExp(0, ex);
|
||||
e = Expression::combine(ex, e);
|
||||
}
|
||||
DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__aggrDtor"));
|
||||
dd->fbody = new ExpStatement(0, e);
|
||||
members->push(dd);
|
||||
dd->semantic(sc);
|
||||
return dd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
74
dmd2/complex_t.h
Normal file
74
dmd2/complex_t.h
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2006 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright and Burton Radons
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_COMPLEX_T_H
|
||||
#define DMD_COMPLEX_T_H
|
||||
|
||||
/* Roll our own complex type for compilers that don't support complex
|
||||
*/
|
||||
|
||||
struct complex_t
|
||||
{
|
||||
long double re;
|
||||
long double im;
|
||||
|
||||
complex_t() { this->re = 0; this->im = 0; }
|
||||
complex_t(long double re) { this->re = re; this->im = 0; }
|
||||
complex_t(long double re, long double im) { this->re = re; this->im = im; }
|
||||
|
||||
complex_t operator + (complex_t y) { complex_t r; r.re = re + y.re; r.im = im + y.im; return r; }
|
||||
complex_t operator - (complex_t y) { complex_t r; r.re = re - y.re; r.im = im - y.im; return r; }
|
||||
complex_t operator - () { complex_t r; r.re = -re; r.im = -im; return r; }
|
||||
complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); }
|
||||
|
||||
complex_t operator / (complex_t y)
|
||||
{
|
||||
long double abs_y_re = y.re < 0 ? -y.re : y.re;
|
||||
long double abs_y_im = y.im < 0 ? -y.im : y.im;
|
||||
long double r, den;
|
||||
|
||||
if (abs_y_re < abs_y_im)
|
||||
{
|
||||
r = y.re / y.im;
|
||||
den = y.im + r * y.re;
|
||||
return complex_t((re * r + im) / den,
|
||||
(im * r - re) / den);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = y.im / y.re;
|
||||
den = y.re + r * y.im;
|
||||
return complex_t((re + r * im) / den,
|
||||
(im - r * re) / den);
|
||||
}
|
||||
}
|
||||
|
||||
operator bool () { return re || im; }
|
||||
|
||||
int operator == (complex_t y) { return re == y.re && im == y.im; }
|
||||
int operator != (complex_t y) { return re != y.re || im != y.im; }
|
||||
};
|
||||
|
||||
inline complex_t operator * (long double x, complex_t y) { return complex_t(x) * y; }
|
||||
inline complex_t operator * (complex_t x, long double y) { return x * complex_t(y); }
|
||||
inline complex_t operator / (complex_t x, long double y) { return x / complex_t(y); }
|
||||
|
||||
|
||||
inline long double creall(complex_t x)
|
||||
{
|
||||
return x.re;
|
||||
}
|
||||
|
||||
inline long double cimagl(complex_t x)
|
||||
{
|
||||
return x.im;
|
||||
}
|
||||
|
||||
#endif
|
||||
405
dmd2/cond.c
Normal file
405
dmd2/cond.c
Normal file
@@ -0,0 +1,405 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "id.h"
|
||||
#include "init.h"
|
||||
#include "declaration.h"
|
||||
#include "identifier.h"
|
||||
#include "expression.h"
|
||||
#include "cond.h"
|
||||
#include "module.h"
|
||||
#include "template.h"
|
||||
#include "lexer.h"
|
||||
#include "mtype.h"
|
||||
#include "scope.h"
|
||||
|
||||
int findCondition(Strings *ids, Identifier *ident)
|
||||
{
|
||||
if (ids)
|
||||
{
|
||||
for (size_t i = 0; i < ids->dim; i++)
|
||||
{
|
||||
const char *id = ids->tdata()[i];
|
||||
|
||||
if (strcmp(id, ident->toChars()) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
Condition::Condition(Loc loc)
|
||||
{
|
||||
this->loc = loc;
|
||||
inc = 0;
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
|
||||
: Condition(0)
|
||||
{
|
||||
this->mod = mod;
|
||||
this->level = level;
|
||||
this->ident = ident;
|
||||
}
|
||||
|
||||
Condition *DVCondition::syntaxCopy()
|
||||
{
|
||||
return this; // don't need to copy
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
void DebugCondition::setGlobalLevel(unsigned level)
|
||||
{
|
||||
global.params.debuglevel = level;
|
||||
}
|
||||
|
||||
void DebugCondition::addGlobalIdent(const char *ident)
|
||||
{
|
||||
if (!global.params.debugids)
|
||||
global.params.debugids = new Strings();
|
||||
global.params.debugids->push((char *)ident);
|
||||
}
|
||||
|
||||
|
||||
DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
|
||||
: DVCondition(mod, level, ident)
|
||||
{
|
||||
}
|
||||
|
||||
int DebugCondition::include(Scope *sc, ScopeDsymbol *s)
|
||||
{
|
||||
//printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
|
||||
if (inc == 0)
|
||||
{
|
||||
inc = 2;
|
||||
if (ident)
|
||||
{
|
||||
if (findCondition(mod->debugids, ident))
|
||||
inc = 1;
|
||||
else if (findCondition(global.params.debugids, ident))
|
||||
inc = 1;
|
||||
else
|
||||
{ if (!mod->debugidsNot)
|
||||
mod->debugidsNot = new Strings();
|
||||
mod->debugidsNot->push(ident->toChars());
|
||||
}
|
||||
}
|
||||
else if (level <= global.params.debuglevel || level <= mod->debuglevel)
|
||||
inc = 1;
|
||||
}
|
||||
return (inc == 1);
|
||||
}
|
||||
|
||||
void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
if (ident)
|
||||
buf->printf("debug (%s)", ident->toChars());
|
||||
else
|
||||
buf->printf("debug (%u)", level);
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
void VersionCondition::setGlobalLevel(unsigned level)
|
||||
{
|
||||
global.params.versionlevel = level;
|
||||
}
|
||||
|
||||
void VersionCondition::checkPredefined(Loc loc, const char *ident)
|
||||
{
|
||||
static const char* reserved[] =
|
||||
{
|
||||
"DigitalMars", "X86", "X86_64",
|
||||
"Windows", "Win32", "Win64",
|
||||
"linux",
|
||||
#if DMDV2
|
||||
/* Although Posix is predefined by D1, disallowing its
|
||||
* redefinition breaks makefiles and older builds.
|
||||
*/
|
||||
"Posix",
|
||||
"D_NET",
|
||||
#endif
|
||||
"OSX", "FreeBSD",
|
||||
"OpenBSD",
|
||||
"Solaris",
|
||||
"LittleEndian", "BigEndian",
|
||||
"all",
|
||||
"none",
|
||||
|
||||
#if IN_LLVM
|
||||
"LLVM", "LDC", "LLVM64",
|
||||
"PPC", "PPC64",
|
||||
"darwin","solaris","freebsd"
|
||||
#endif
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++)
|
||||
{
|
||||
if (strcmp(ident, reserved[i]) == 0)
|
||||
goto Lerror;
|
||||
}
|
||||
|
||||
if (ident[0] == 'D' && ident[1] == '_')
|
||||
goto Lerror;
|
||||
|
||||
return;
|
||||
|
||||
Lerror:
|
||||
error(loc, "version identifier '%s' is reserved and cannot be set", ident);
|
||||
}
|
||||
|
||||
void VersionCondition::addGlobalIdent(const char *ident)
|
||||
{
|
||||
checkPredefined(0, ident);
|
||||
addPredefinedGlobalIdent(ident);
|
||||
}
|
||||
|
||||
void VersionCondition::addPredefinedGlobalIdent(const char *ident)
|
||||
{
|
||||
if (!global.params.versionids)
|
||||
global.params.versionids = new Strings();
|
||||
global.params.versionids->push((char *)ident);
|
||||
}
|
||||
|
||||
|
||||
VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
|
||||
: DVCondition(mod, level, ident)
|
||||
{
|
||||
}
|
||||
|
||||
int VersionCondition::include(Scope *sc, ScopeDsymbol *s)
|
||||
{
|
||||
//printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
|
||||
//if (ident) printf("\tident = '%s'\n", ident->toChars());
|
||||
if (inc == 0)
|
||||
{
|
||||
inc = 2;
|
||||
if (ident)
|
||||
{
|
||||
if (findCondition(mod->versionids, ident))
|
||||
inc = 1;
|
||||
else if (findCondition(global.params.versionids, ident))
|
||||
inc = 1;
|
||||
else
|
||||
{
|
||||
if (!mod->versionidsNot)
|
||||
mod->versionidsNot = new Strings();
|
||||
mod->versionidsNot->push(ident->toChars());
|
||||
}
|
||||
}
|
||||
else if (level <= global.params.versionlevel || level <= mod->versionlevel)
|
||||
inc = 1;
|
||||
}
|
||||
return (inc == 1);
|
||||
}
|
||||
|
||||
void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
if (ident)
|
||||
buf->printf("version (%s)", ident->toChars());
|
||||
else
|
||||
buf->printf("version (%u)", level);
|
||||
}
|
||||
|
||||
|
||||
/**************************** StaticIfCondition *******************************/
|
||||
|
||||
StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
|
||||
: Condition(loc)
|
||||
{
|
||||
this->exp = exp;
|
||||
}
|
||||
|
||||
Condition *StaticIfCondition::syntaxCopy()
|
||||
{
|
||||
return new StaticIfCondition(loc, exp->syntaxCopy());
|
||||
}
|
||||
|
||||
int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s)
|
||||
{
|
||||
#if 0
|
||||
printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s);
|
||||
if (s)
|
||||
{
|
||||
printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind());
|
||||
}
|
||||
#endif
|
||||
if (inc == 0)
|
||||
{
|
||||
if (!sc)
|
||||
{
|
||||
error(loc, "static if conditional cannot be at global scope");
|
||||
inc = 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sc = sc->push(sc->scopesym);
|
||||
sc->sd = s; // s gets any addMember()
|
||||
sc->flags |= SCOPEstaticif;
|
||||
Expression *e = exp->semantic(sc);
|
||||
sc->pop();
|
||||
e = e->optimize(WANTvalue | WANTinterpret);
|
||||
if (e->isBool(TRUE))
|
||||
inc = 1;
|
||||
else if (e->isBool(FALSE))
|
||||
inc = 2;
|
||||
else
|
||||
{
|
||||
e->error("expression %s is not constant or does not evaluate to a bool", e->toChars());
|
||||
inc = 2;
|
||||
}
|
||||
}
|
||||
return (inc == 1);
|
||||
}
|
||||
|
||||
void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
buf->writestring("static if(");
|
||||
exp->toCBuffer(buf, hgs);
|
||||
buf->writeByte(')');
|
||||
}
|
||||
|
||||
|
||||
/**************************** IftypeCondition *******************************/
|
||||
|
||||
IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec)
|
||||
: Condition(loc)
|
||||
{
|
||||
this->targ = targ;
|
||||
this->id = id;
|
||||
this->tok = tok;
|
||||
this->tspec = tspec;
|
||||
}
|
||||
|
||||
Condition *IftypeCondition::syntaxCopy()
|
||||
{
|
||||
return new IftypeCondition(loc,
|
||||
targ->syntaxCopy(),
|
||||
id,
|
||||
tok,
|
||||
tspec ? tspec->syntaxCopy() : NULL);
|
||||
}
|
||||
|
||||
int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd)
|
||||
{
|
||||
//printf("IftypeCondition::include()\n");
|
||||
if (inc == 0)
|
||||
{
|
||||
if (!sc)
|
||||
{
|
||||
error(loc, "iftype conditional cannot be at global scope");
|
||||
inc = 2;
|
||||
return 0;
|
||||
}
|
||||
Type *t = targ->trySemantic(loc, sc);
|
||||
if (t)
|
||||
targ = t;
|
||||
else
|
||||
inc = 2; // condition is false
|
||||
|
||||
if (!t)
|
||||
{
|
||||
}
|
||||
else if (id && tspec)
|
||||
{
|
||||
/* Evaluate to TRUE if targ matches tspec.
|
||||
* If TRUE, declare id as an alias for the specialized type.
|
||||
*/
|
||||
|
||||
MATCH m;
|
||||
TemplateTypeParameter tp(loc, id, NULL, NULL);
|
||||
|
||||
TemplateParameters parameters;
|
||||
parameters.setDim(1);
|
||||
parameters.tdata()[0] = &tp;
|
||||
|
||||
Objects dedtypes;
|
||||
dedtypes.setDim(1);
|
||||
|
||||
m = targ->deduceType(sc, tspec, ¶meters, &dedtypes);
|
||||
if (m == MATCHnomatch ||
|
||||
(m != MATCHexact && tok == TOKequal))
|
||||
inc = 2;
|
||||
else
|
||||
{
|
||||
inc = 1;
|
||||
Type *tded = (Type *)dedtypes.tdata()[0];
|
||||
if (!tded)
|
||||
tded = targ;
|
||||
Dsymbol *s = new AliasDeclaration(loc, id, tded);
|
||||
s->semantic(sc);
|
||||
sc->insert(s);
|
||||
if (sd)
|
||||
s->addMember(sc, sd, 1);
|
||||
}
|
||||
}
|
||||
else if (id)
|
||||
{
|
||||
/* Declare id as an alias for type targ. Evaluate to TRUE
|
||||
*/
|
||||
Dsymbol *s = new AliasDeclaration(loc, id, targ);
|
||||
s->semantic(sc);
|
||||
sc->insert(s);
|
||||
if (sd)
|
||||
s->addMember(sc, sd, 1);
|
||||
inc = 1;
|
||||
}
|
||||
else if (tspec)
|
||||
{
|
||||
/* Evaluate to TRUE if targ matches tspec
|
||||
*/
|
||||
tspec = tspec->semantic(loc, sc);
|
||||
//printf("targ = %s\n", targ->toChars());
|
||||
//printf("tspec = %s\n", tspec->toChars());
|
||||
if (tok == TOKcolon)
|
||||
{ if (targ->implicitConvTo(tspec))
|
||||
inc = 1;
|
||||
else
|
||||
inc = 2;
|
||||
}
|
||||
else /* == */
|
||||
{ if (targ->equals(tspec))
|
||||
inc = 1;
|
||||
else
|
||||
inc = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
inc = 1;
|
||||
//printf("inc = %d\n", inc);
|
||||
}
|
||||
return (inc == 1);
|
||||
}
|
||||
|
||||
void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
buf->writestring("iftype(");
|
||||
targ->toCBuffer(buf, id, hgs);
|
||||
if (tspec)
|
||||
{
|
||||
if (tok == TOKcolon)
|
||||
buf->writestring(" : ");
|
||||
else
|
||||
buf->writestring(" == ");
|
||||
tspec->toCBuffer(buf, NULL, hgs);
|
||||
}
|
||||
buf->writeByte(')');
|
||||
}
|
||||
|
||||
|
||||
105
dmd2/cond.h
Normal file
105
dmd2/cond.h
Normal file
@@ -0,0 +1,105 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_DEBCOND_H
|
||||
#define DMD_DEBCOND_H
|
||||
|
||||
struct Expression;
|
||||
struct Identifier;
|
||||
struct OutBuffer;
|
||||
struct Module;
|
||||
struct Scope;
|
||||
struct ScopeDsymbol;
|
||||
struct DebugCondition;
|
||||
#include "lexer.h" // dmdhg
|
||||
enum TOK;
|
||||
struct HdrGenState;
|
||||
|
||||
int findCondition(Strings *ids, Identifier *ident);
|
||||
|
||||
struct Condition
|
||||
{
|
||||
Loc loc;
|
||||
int inc; // 0: not computed yet
|
||||
// 1: include
|
||||
// 2: do not include
|
||||
|
||||
Condition(Loc loc);
|
||||
|
||||
virtual Condition *syntaxCopy() = 0;
|
||||
virtual int include(Scope *sc, ScopeDsymbol *s) = 0;
|
||||
virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0;
|
||||
virtual DebugCondition *isDebugCondition() { return NULL; }
|
||||
};
|
||||
|
||||
struct DVCondition : Condition
|
||||
{
|
||||
unsigned level;
|
||||
Identifier *ident;
|
||||
Module *mod;
|
||||
|
||||
DVCondition(Module *mod, unsigned level, Identifier *ident);
|
||||
|
||||
Condition *syntaxCopy();
|
||||
};
|
||||
|
||||
struct DebugCondition : DVCondition
|
||||
{
|
||||
static void setGlobalLevel(unsigned level);
|
||||
static void addGlobalIdent(const char *ident);
|
||||
static void addPredefinedGlobalIdent(const char *ident);
|
||||
|
||||
DebugCondition(Module *mod, unsigned level, Identifier *ident);
|
||||
|
||||
int include(Scope *sc, ScopeDsymbol *s);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
DebugCondition *isDebugCondition() { return this; }
|
||||
};
|
||||
|
||||
struct VersionCondition : DVCondition
|
||||
{
|
||||
static void setGlobalLevel(unsigned level);
|
||||
static void checkPredefined(Loc loc, const char *ident);
|
||||
static void addGlobalIdent(const char *ident);
|
||||
static void addPredefinedGlobalIdent(const char *ident);
|
||||
|
||||
VersionCondition(Module *mod, unsigned level, Identifier *ident);
|
||||
|
||||
int include(Scope *sc, ScopeDsymbol *s);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
};
|
||||
|
||||
struct StaticIfCondition : Condition
|
||||
{
|
||||
Expression *exp;
|
||||
|
||||
StaticIfCondition(Loc loc, Expression *exp);
|
||||
Condition *syntaxCopy();
|
||||
int include(Scope *sc, ScopeDsymbol *s);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
};
|
||||
|
||||
struct IftypeCondition : Condition
|
||||
{
|
||||
/* iftype (targ id tok tspec)
|
||||
*/
|
||||
Type *targ;
|
||||
Identifier *id; // can be NULL
|
||||
enum TOK tok; // ':' or '=='
|
||||
Type *tspec; // can be NULL
|
||||
|
||||
IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec);
|
||||
Condition *syntaxCopy();
|
||||
int include(Scope *sc, ScopeDsymbol *s);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
1876
dmd2/constfold.c
Normal file
1876
dmd2/constfold.c
Normal file
File diff suppressed because it is too large
Load Diff
454
dmd2/cppmangle.c
Normal file
454
dmd2/cppmangle.c
Normal file
@@ -0,0 +1,454 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2010 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mars.h"
|
||||
#include "dsymbol.h"
|
||||
#include "mtype.h"
|
||||
#include "scope.h"
|
||||
#include "init.h"
|
||||
#include "expression.h"
|
||||
#include "attrib.h"
|
||||
#include "declaration.h"
|
||||
#include "template.h"
|
||||
#include "id.h"
|
||||
#include "enum.h"
|
||||
#include "import.h"
|
||||
#include "aggregate.h"
|
||||
|
||||
#if CPP_MANGLE
|
||||
|
||||
/* Do mangling for C++ linkage.
|
||||
* Follows Itanium C++ ABI 1.86
|
||||
* No attempt is made to support mangling of templates, operator
|
||||
* overloading, or special functions.
|
||||
*
|
||||
* So why don't we use the C++ ABI for D name mangling?
|
||||
* Because D supports a lot of things (like modules) that the C++
|
||||
* ABI has no concept of. These affect every D mangled name,
|
||||
* so nothing would be compatible anyway.
|
||||
*/
|
||||
|
||||
struct CppMangleState
|
||||
{
|
||||
static Voids components;
|
||||
|
||||
int substitute(OutBuffer *buf, void *p);
|
||||
int exist(void *p);
|
||||
void store(void *p);
|
||||
};
|
||||
|
||||
Voids CppMangleState::components;
|
||||
|
||||
|
||||
void writeBase36(OutBuffer *buf, unsigned i)
|
||||
{
|
||||
if (i >= 36)
|
||||
{
|
||||
writeBase36(buf, i / 36);
|
||||
i %= 36;
|
||||
}
|
||||
if (i < 10)
|
||||
buf->writeByte(i + '0');
|
||||
else if (i < 36)
|
||||
buf->writeByte(i - 10 + 'A');
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
|
||||
int CppMangleState::substitute(OutBuffer *buf, void *p)
|
||||
{
|
||||
for (size_t i = 0; i < components.dim; i++)
|
||||
{
|
||||
if (p == components.tdata()[i])
|
||||
{
|
||||
/* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ...
|
||||
*/
|
||||
buf->writeByte('S');
|
||||
if (i)
|
||||
writeBase36(buf, i - 1);
|
||||
buf->writeByte('_');
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
components.push(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CppMangleState::exist(void *p)
|
||||
{
|
||||
for (size_t i = 0; i < components.dim; i++)
|
||||
{
|
||||
if (p == components.tdata()[i])
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CppMangleState::store(void *p)
|
||||
{
|
||||
components.push(p);
|
||||
}
|
||||
|
||||
void source_name(OutBuffer *buf, Dsymbol *s)
|
||||
{
|
||||
char *name = s->ident->toChars();
|
||||
buf->printf("%d%s", strlen(name), name);
|
||||
}
|
||||
|
||||
void prefix_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s)
|
||||
{
|
||||
if (!cms->substitute(buf, s))
|
||||
{
|
||||
Dsymbol *p = s->toParent();
|
||||
if (p && !p->isModule())
|
||||
{
|
||||
prefix_name(buf, cms, p);
|
||||
}
|
||||
source_name(buf, s);
|
||||
}
|
||||
}
|
||||
|
||||
void cpp_mangle_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s)
|
||||
{
|
||||
Dsymbol *p = s->toParent();
|
||||
if (p && !p->isModule())
|
||||
{
|
||||
buf->writeByte('N');
|
||||
|
||||
FuncDeclaration *fd = s->isFuncDeclaration();
|
||||
if (!fd)
|
||||
{
|
||||
s->error("C++ static variables not supported");
|
||||
}
|
||||
else
|
||||
if (fd->isConst())
|
||||
buf->writeByte('K');
|
||||
|
||||
prefix_name(buf, cms, p);
|
||||
source_name(buf, s);
|
||||
|
||||
buf->writeByte('E');
|
||||
}
|
||||
else
|
||||
source_name(buf, s);
|
||||
}
|
||||
|
||||
|
||||
char *cpp_mangle(Dsymbol *s)
|
||||
{
|
||||
/*
|
||||
* <mangled-name> ::= _Z <encoding>
|
||||
* <encoding> ::= <function name> <bare-function-type>
|
||||
* ::= <data name>
|
||||
* ::= <special-name>
|
||||
*/
|
||||
|
||||
CppMangleState cms;
|
||||
memset(&cms, 0, sizeof(cms));
|
||||
cms.components.setDim(0);
|
||||
|
||||
OutBuffer buf;
|
||||
#if MACHOBJ
|
||||
buf.writestring("__Z");
|
||||
#else
|
||||
buf.writestring("_Z");
|
||||
#endif
|
||||
|
||||
cpp_mangle_name(&buf, &cms, s);
|
||||
|
||||
FuncDeclaration *fd = s->isFuncDeclaration();
|
||||
if (fd)
|
||||
{ // add <bare-function-type>
|
||||
TypeFunction *tf = (TypeFunction *)fd->type;
|
||||
assert(tf->ty == Tfunction);
|
||||
Parameter::argsCppMangle(&buf, &cms, tf->parameters, tf->varargs);
|
||||
}
|
||||
buf.writeByte(0);
|
||||
return (char *)buf.extractData();
|
||||
}
|
||||
|
||||
/* ============= Type Encodings ============================================= */
|
||||
|
||||
void Type::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{
|
||||
/* Make this the 'vendor extended type' when there is no
|
||||
* C++ analog.
|
||||
* u <source-name>
|
||||
*/
|
||||
if (!cms->substitute(buf, this))
|
||||
{ assert(deco);
|
||||
buf->printf("u%d%s", strlen(deco), deco);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeBasic::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{ char c;
|
||||
char p = 0;
|
||||
|
||||
/* ABI spec says:
|
||||
* v void
|
||||
* w wchar_t
|
||||
* b bool
|
||||
* c char
|
||||
* a signed char
|
||||
* h unsigned char
|
||||
* s short
|
||||
* t unsigned short
|
||||
* i int
|
||||
* j unsigned int
|
||||
* l long
|
||||
* m unsigned long
|
||||
* x long long, __int64
|
||||
* y unsigned long long, __int64
|
||||
* n __int128
|
||||
* o unsigned __int128
|
||||
* f float
|
||||
* d double
|
||||
* e long double, __float80
|
||||
* g __float128
|
||||
* z ellipsis
|
||||
* u <source-name> # vendor extended type
|
||||
*/
|
||||
|
||||
switch (ty)
|
||||
{
|
||||
case Tvoid: c = 'v'; break;
|
||||
case Tint8: c = 'a'; break;
|
||||
case Tuns8: c = 'h'; break;
|
||||
case Tint16: c = 's'; break;
|
||||
case Tuns16: c = 't'; break;
|
||||
case Tint32: c = 'i'; break;
|
||||
case Tuns32: c = 'j'; break;
|
||||
case Tfloat32: c = 'f'; break;
|
||||
case Tint64: c = 'x'; break;
|
||||
case Tuns64: c = 'y'; break;
|
||||
case Tfloat64: c = 'd'; break;
|
||||
case Tfloat80: c = 'e'; break;
|
||||
case Tbool: c = 'b'; break;
|
||||
case Tchar: c = 'c'; break;
|
||||
case Twchar: c = 't'; break;
|
||||
case Tdchar: c = 'w'; break;
|
||||
|
||||
case Timaginary32: p = 'G'; c = 'f'; break;
|
||||
case Timaginary64: p = 'G'; c = 'd'; break;
|
||||
case Timaginary80: p = 'G'; c = 'e'; break;
|
||||
case Tcomplex32: p = 'C'; c = 'f'; break;
|
||||
case Tcomplex64: p = 'C'; c = 'd'; break;
|
||||
case Tcomplex80: p = 'C'; c = 'e'; break;
|
||||
|
||||
default: assert(0);
|
||||
}
|
||||
if (p || isConst())
|
||||
{
|
||||
if (cms->substitute(buf, this))
|
||||
return;
|
||||
}
|
||||
|
||||
if (isConst())
|
||||
buf->writeByte('K');
|
||||
|
||||
if (p)
|
||||
buf->writeByte(p);
|
||||
|
||||
buf->writeByte(c);
|
||||
}
|
||||
|
||||
|
||||
void TypeVector::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{
|
||||
if (!cms->substitute(buf, this))
|
||||
{ buf->writestring("U8__vector");
|
||||
basetype->toCppMangle(buf, cms);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeSArray::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{
|
||||
if (!cms->substitute(buf, this))
|
||||
{ buf->printf("A%ju_", dim ? dim->toInteger() : 0);
|
||||
next->toCppMangle(buf, cms);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeDArray::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{
|
||||
Type::toCppMangle(buf, cms);
|
||||
}
|
||||
|
||||
|
||||
void TypeAArray::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{
|
||||
Type::toCppMangle(buf, cms);
|
||||
}
|
||||
|
||||
|
||||
void TypePointer::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{
|
||||
if (!cms->exist(this))
|
||||
{ buf->writeByte('P');
|
||||
next->toCppMangle(buf, cms);
|
||||
cms->store(this);
|
||||
}
|
||||
else
|
||||
cms->substitute(buf, this);
|
||||
}
|
||||
|
||||
|
||||
void TypeReference::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{
|
||||
if (!cms->exist(this))
|
||||
{ buf->writeByte('R');
|
||||
next->toCppMangle(buf, cms);
|
||||
cms->store(this);
|
||||
}
|
||||
else
|
||||
cms->substitute(buf, this);
|
||||
}
|
||||
|
||||
|
||||
void TypeFunction::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{ /*
|
||||
* <function-type> ::= F [Y] <bare-function-type> E
|
||||
* <bare-function-type> ::= <signature type>+
|
||||
* # types are possible return type, then parameter types
|
||||
*/
|
||||
|
||||
/* ABI says:
|
||||
"The type of a non-static member function is considered to be different,
|
||||
for the purposes of substitution, from the type of a namespace-scope or
|
||||
static member function whose type appears similar. The types of two
|
||||
non-static member functions are considered to be different, for the
|
||||
purposes of substitution, if the functions are members of different
|
||||
classes. In other words, for the purposes of substitution, the class of
|
||||
which the function is a member is considered part of the type of
|
||||
function."
|
||||
|
||||
BUG: Right now, types of functions are never merged, so our simplistic
|
||||
component matcher always finds them to be different.
|
||||
We should use Type::equals on these, and use different
|
||||
TypeFunctions for non-static member functions, and non-static
|
||||
member functions of different classes.
|
||||
*/
|
||||
if (!cms->substitute(buf, this))
|
||||
{
|
||||
buf->writeByte('F');
|
||||
if (linkage == LINKc)
|
||||
buf->writeByte('Y');
|
||||
next->toCppMangle(buf, cms);
|
||||
Parameter::argsCppMangle(buf, cms, parameters, varargs);
|
||||
buf->writeByte('E');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TypeDelegate::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{
|
||||
Type::toCppMangle(buf, cms);
|
||||
}
|
||||
|
||||
|
||||
void TypeStruct::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{
|
||||
if (!cms->exist(this))
|
||||
{
|
||||
if (isConst())
|
||||
buf->writeByte('K');
|
||||
|
||||
if (!cms->substitute(buf, sym))
|
||||
cpp_mangle_name(buf, cms, sym);
|
||||
|
||||
if (isConst())
|
||||
cms->store(this);
|
||||
}
|
||||
else
|
||||
cms->substitute(buf, this);
|
||||
}
|
||||
|
||||
|
||||
void TypeEnum::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{
|
||||
if (!cms->exist(this))
|
||||
{
|
||||
if (isConst())
|
||||
buf->writeByte('K');
|
||||
|
||||
if (!cms->substitute(buf, sym))
|
||||
cpp_mangle_name(buf, cms, sym);
|
||||
|
||||
if (isConst())
|
||||
cms->store(this);
|
||||
}
|
||||
else
|
||||
cms->substitute(buf, this);
|
||||
}
|
||||
|
||||
|
||||
void TypeTypedef::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{
|
||||
Type::toCppMangle(buf, cms);
|
||||
}
|
||||
|
||||
|
||||
void TypeClass::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||
{
|
||||
if (!cms->substitute(buf, this))
|
||||
{ buf->writeByte('P');
|
||||
if (!cms->substitute(buf, sym))
|
||||
cpp_mangle_name(buf, cms, sym);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Parameter::argsCppMangle(OutBuffer *buf, CppMangleState *cms, Parameters *arguments, int varargs)
|
||||
{ int n = 0;
|
||||
if (arguments)
|
||||
{
|
||||
for (size_t i = 0; i < arguments->dim; i++)
|
||||
{ Parameter *arg = arguments->tdata()[i];
|
||||
Type *t = arg->type;
|
||||
if (arg->storageClass & (STCout | STCref))
|
||||
t = t->referenceTo();
|
||||
else if (arg->storageClass & STClazy)
|
||||
{ // Mangle as delegate
|
||||
Type *td = new TypeFunction(NULL, t, 0, LINKd);
|
||||
td = new TypeDelegate(td);
|
||||
t = t->merge();
|
||||
}
|
||||
if (t->ty == Tsarray)
|
||||
{ // Mangle static arrays as pointers
|
||||
t = t->pointerTo();
|
||||
}
|
||||
|
||||
/* If it is a basic, enum or struct type,
|
||||
* then don't mark it const
|
||||
*/
|
||||
if ((t->ty == Tenum || t->ty == Tstruct || t->isTypeBasic()) && t->isConst())
|
||||
t->mutableOf()->toCppMangle(buf, cms);
|
||||
else
|
||||
t->toCppMangle(buf, cms);
|
||||
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (varargs)
|
||||
buf->writestring("z");
|
||||
else if (!n)
|
||||
buf->writeByte('v'); // encode ( ) arguments
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
2327
dmd2/declaration.c
Normal file
2327
dmd2/declaration.c
Normal file
File diff suppressed because it is too large
Load Diff
1107
dmd2/declaration.h
Normal file
1107
dmd2/declaration.h
Normal file
File diff suppressed because it is too large
Load Diff
140
dmd2/delegatize.c
Normal file
140
dmd2/delegatize.c
Normal file
@@ -0,0 +1,140 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mars.h"
|
||||
#include "expression.h"
|
||||
#include "statement.h"
|
||||
#include "mtype.h"
|
||||
#include "utf.h"
|
||||
#include "declaration.h"
|
||||
#include "aggregate.h"
|
||||
#include "scope.h"
|
||||
|
||||
/********************************************
|
||||
* Convert from expression to delegate that returns the expression,
|
||||
* i.e. convert:
|
||||
* expr
|
||||
* to:
|
||||
* t delegate() { return expr; }
|
||||
*/
|
||||
|
||||
int lambdaSetParent(Expression *e, void *param);
|
||||
int lambdaCheckForNestedRef(Expression *e, void *param);
|
||||
|
||||
Expression *Expression::toDelegate(Scope *sc, Type *t)
|
||||
{
|
||||
//printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), toChars());
|
||||
TypeFunction *tf = new TypeFunction(NULL, t, 0, LINKd);
|
||||
FuncLiteralDeclaration *fld =
|
||||
new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL);
|
||||
Expression *e;
|
||||
sc = sc->push();
|
||||
sc->parent = fld; // set current function to be the delegate
|
||||
e = this;
|
||||
e->apply(&lambdaSetParent, sc);
|
||||
e->apply(&lambdaCheckForNestedRef, sc);
|
||||
sc = sc->pop();
|
||||
Statement *s;
|
||||
if (t->ty == Tvoid)
|
||||
s = new ExpStatement(loc, e);
|
||||
else
|
||||
s = new ReturnStatement(loc, e);
|
||||
fld->fbody = s;
|
||||
e = new FuncExp(loc, fld);
|
||||
e = e->semantic(sc);
|
||||
return e;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Patch the parent of declarations to be the new function literal.
|
||||
*/
|
||||
int lambdaSetParent(Expression *e, void *param)
|
||||
{
|
||||
Scope *sc = (Scope *)param;
|
||||
/* We could use virtual functions instead of a switch,
|
||||
* but it doesn't seem worth the bother.
|
||||
*/
|
||||
switch (e->op)
|
||||
{
|
||||
case TOKdeclaration:
|
||||
{ DeclarationExp *de = (DeclarationExp *)e;
|
||||
de->declaration->parent = sc->parent;
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKindex:
|
||||
{ IndexExp *de = (IndexExp *)e;
|
||||
if (de->lengthVar)
|
||||
{ //printf("lengthVar\n");
|
||||
de->lengthVar->parent = sc->parent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKslice:
|
||||
{ SliceExp *se = (SliceExp *)e;
|
||||
if (se->lengthVar)
|
||||
{ //printf("lengthVar\n");
|
||||
se->lengthVar->parent = sc->parent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* Look for references to variables in a scope enclosing the new function literal.
|
||||
*/
|
||||
int lambdaCheckForNestedRef(Expression *e, void *param)
|
||||
{
|
||||
Scope *sc = (Scope *)param;
|
||||
/* We could use virtual functions instead of a switch,
|
||||
* but it doesn't seem worth the bother.
|
||||
*/
|
||||
switch (e->op)
|
||||
{
|
||||
case TOKsymoff:
|
||||
{ SymOffExp *se = (SymOffExp *)e;
|
||||
VarDeclaration *v = se->var->isVarDeclaration();
|
||||
if (v)
|
||||
v->checkNestedReference(sc, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKvar:
|
||||
{ VarExp *ve = (VarExp *)e;
|
||||
VarDeclaration *v = ve->var->isVarDeclaration();
|
||||
if (v)
|
||||
v->checkNestedReference(sc, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKthis:
|
||||
case TOKsuper:
|
||||
{ ThisExp *te = (ThisExp *)e;
|
||||
VarDeclaration *v = te->var->isVarDeclaration();
|
||||
if (v)
|
||||
v->checkNestedReference(sc, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
2226
dmd2/doc.c
Normal file
2226
dmd2/doc.c
Normal file
File diff suppressed because it is too large
Load Diff
20
dmd2/doc.h
Normal file
20
dmd2/doc.h
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2006 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_DOC_H
|
||||
#define DMD_DOC_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
void escapeDdocString(OutBuffer *buf, unsigned start);
|
||||
|
||||
#endif
|
||||
1476
dmd2/dsymbol.c
Normal file
1476
dmd2/dsymbol.c
Normal file
File diff suppressed because it is too large
Load Diff
389
dmd2/dsymbol.h
Normal file
389
dmd2/dsymbol.h
Normal file
@@ -0,0 +1,389 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_DSYMBOL_H
|
||||
#define DMD_DSYMBOL_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
#include "root.h"
|
||||
#include "stringtable.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "arraytypes.h"
|
||||
|
||||
#if IN_LLVM
|
||||
#if defined(_MSC_VER)
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
#include "../ir/irdsymbol.h"
|
||||
#endif
|
||||
|
||||
struct Identifier;
|
||||
struct Scope;
|
||||
struct DsymbolTable;
|
||||
struct Declaration;
|
||||
struct ThisDeclaration;
|
||||
struct TupleDeclaration;
|
||||
struct TypedefDeclaration;
|
||||
struct AliasDeclaration;
|
||||
struct AggregateDeclaration;
|
||||
struct EnumDeclaration;
|
||||
struct ClassDeclaration;
|
||||
struct InterfaceDeclaration;
|
||||
struct StructDeclaration;
|
||||
struct UnionDeclaration;
|
||||
struct FuncDeclaration;
|
||||
struct FuncAliasDeclaration;
|
||||
struct FuncLiteralDeclaration;
|
||||
struct CtorDeclaration;
|
||||
struct PostBlitDeclaration;
|
||||
struct DtorDeclaration;
|
||||
struct StaticCtorDeclaration;
|
||||
struct StaticDtorDeclaration;
|
||||
struct SharedStaticCtorDeclaration;
|
||||
struct SharedStaticDtorDeclaration;
|
||||
struct InvariantDeclaration;
|
||||
struct UnitTestDeclaration;
|
||||
struct NewDeclaration;
|
||||
struct VarDeclaration;
|
||||
struct AttribDeclaration;
|
||||
#if IN_DMD
|
||||
struct Symbol;
|
||||
#endif
|
||||
struct Package;
|
||||
struct Module;
|
||||
struct Import;
|
||||
struct Type;
|
||||
struct TypeTuple;
|
||||
struct WithStatement;
|
||||
struct LabelDsymbol;
|
||||
struct ScopeDsymbol;
|
||||
struct TemplateDeclaration;
|
||||
struct TemplateInstance;
|
||||
struct TemplateMixin;
|
||||
struct EnumMember;
|
||||
struct ScopeDsymbol;
|
||||
struct WithScopeSymbol;
|
||||
struct ArrayScopeSymbol;
|
||||
struct StaticStructInitDeclaration;
|
||||
struct Expression;
|
||||
struct DeleteDeclaration;
|
||||
struct HdrGenState;
|
||||
struct OverloadSet;
|
||||
struct AA;
|
||||
#if TARGET_NET
|
||||
struct PragmaScope;
|
||||
#endif
|
||||
#if IN_LLVM
|
||||
struct TypeInfoDeclaration;
|
||||
struct ClassInfoDeclaration;
|
||||
#endif
|
||||
|
||||
#if IN_GCC
|
||||
union tree_node;
|
||||
typedef union tree_node TYPE;
|
||||
#else
|
||||
struct TYPE;
|
||||
#endif
|
||||
|
||||
#if IN_LLVM
|
||||
class Ir;
|
||||
class IrSymbol;
|
||||
namespace llvm
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
#endif
|
||||
#if IN_DMD
|
||||
// Back end
|
||||
struct Classsym;
|
||||
#endif
|
||||
|
||||
enum PROT
|
||||
{
|
||||
PROTundefined,
|
||||
PROTnone, // no access
|
||||
PROTprivate,
|
||||
PROTpackage,
|
||||
PROTprotected,
|
||||
PROTpublic,
|
||||
PROTexport,
|
||||
};
|
||||
|
||||
/* State of symbol in winding its way through the passes of the compiler
|
||||
*/
|
||||
enum PASS
|
||||
{
|
||||
PASSinit, // initial state
|
||||
PASSsemantic, // semantic() started
|
||||
PASSsemanticdone, // semantic() done
|
||||
PASSsemantic2, // semantic2() run
|
||||
PASSsemantic3, // semantic3() started
|
||||
PASSsemantic3done, // semantic3() done
|
||||
PASSobj, // toObjFile() run
|
||||
};
|
||||
|
||||
struct Dsymbol : Object
|
||||
{
|
||||
Identifier *ident;
|
||||
Identifier *c_ident;
|
||||
Dsymbol *parent;
|
||||
#if IN_DMD
|
||||
Symbol *csym; // symbol for code generator
|
||||
Symbol *isym; // import version of csym
|
||||
#endif
|
||||
unsigned char *comment; // documentation comment for this Dsymbol
|
||||
Loc loc; // where defined
|
||||
Scope *scope; // !=NULL means context to use for semantic()
|
||||
|
||||
Dsymbol();
|
||||
Dsymbol(Identifier *);
|
||||
char *toChars();
|
||||
char *locToChars();
|
||||
int equals(Object *o);
|
||||
int isAnonymous();
|
||||
void error(Loc loc, const char *format, ...) IS_PRINTF(3);
|
||||
void error(const char *format, ...) IS_PRINTF(2);
|
||||
void verror(Loc loc, const char *format, va_list ap);
|
||||
void checkDeprecated(Loc loc, Scope *sc);
|
||||
Module *getModule(); // module where declared
|
||||
Module *getAccessModule();
|
||||
Dsymbol *pastMixin();
|
||||
Dsymbol *toParent();
|
||||
Dsymbol *toParent2();
|
||||
TemplateInstance *inTemplateInstance();
|
||||
|
||||
int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol()
|
||||
|
||||
static Dsymbols *arraySyntaxCopy(Dsymbols *a);
|
||||
|
||||
virtual const char *toPrettyChars();
|
||||
virtual const char *kind();
|
||||
virtual Dsymbol *toAlias(); // resolve real symbol
|
||||
virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
|
||||
virtual void setScope(Scope *sc);
|
||||
virtual void importAll(Scope *sc);
|
||||
virtual void semantic0(Scope *sc);
|
||||
virtual void semantic(Scope *sc);
|
||||
virtual void semantic2(Scope *sc);
|
||||
virtual void semantic3(Scope *sc);
|
||||
virtual void inlineScan();
|
||||
virtual Dsymbol *search(Loc loc, Identifier *ident, int flags);
|
||||
Dsymbol *search_correct(Identifier *id);
|
||||
Dsymbol *searchX(Loc loc, Scope *sc, Identifier *id);
|
||||
virtual int overloadInsert(Dsymbol *s);
|
||||
char *toHChars();
|
||||
virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
virtual void toDocBuffer(OutBuffer *buf);
|
||||
virtual void toJsonBuffer(OutBuffer *buf);
|
||||
virtual unsigned size(Loc loc);
|
||||
virtual int isforwardRef();
|
||||
virtual void defineRef(Dsymbol *s);
|
||||
virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member
|
||||
AggregateDeclaration *isAggregateMember(); // are we a member of an aggregate?
|
||||
ClassDeclaration *isClassMember(); // are we a member of a class?
|
||||
virtual int isExport(); // is Dsymbol exported?
|
||||
virtual int isImportedSymbol(); // is Dsymbol imported?
|
||||
virtual int isDeprecated(); // is Dsymbol deprecated?
|
||||
#if DMDV2
|
||||
virtual int isOverloadable();
|
||||
#endif
|
||||
virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol?
|
||||
virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration?
|
||||
virtual Type *getType(); // is this a type?
|
||||
virtual char *mangle();
|
||||
virtual int needThis(); // need a 'this' pointer?
|
||||
virtual enum PROT prot();
|
||||
virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
|
||||
virtual int oneMember(Dsymbol **ps, Identifier *ident);
|
||||
static int oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident = NULL);
|
||||
virtual int hasPointers();
|
||||
virtual bool hasStaticCtorOrDtor();
|
||||
virtual void addLocalClass(ClassDeclarations *) { }
|
||||
virtual void checkCtorConstInit() { }
|
||||
|
||||
virtual void addComment(unsigned char *comment);
|
||||
virtual void emitComment(Scope *sc);
|
||||
void emitDitto(Scope *sc);
|
||||
|
||||
#if IN_DMD
|
||||
// Backend
|
||||
|
||||
virtual Symbol *toSymbol(); // to backend symbol
|
||||
virtual void toObjFile(int multiobj); // compile to .obj file
|
||||
virtual int cvMember(unsigned char *p); // emit cv debug info for member
|
||||
|
||||
Symbol *toImport(); // to backend import symbol
|
||||
static Symbol *toImport(Symbol *s); // to backend import symbol
|
||||
|
||||
Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix); // helper
|
||||
#endif
|
||||
|
||||
// Eliminate need for dynamic_cast
|
||||
virtual Package *isPackage() { return NULL; }
|
||||
virtual Module *isModule() { return NULL; }
|
||||
virtual EnumMember *isEnumMember() { return NULL; }
|
||||
virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; }
|
||||
virtual TemplateInstance *isTemplateInstance() { return NULL; }
|
||||
virtual TemplateMixin *isTemplateMixin() { return NULL; }
|
||||
virtual Declaration *isDeclaration() { return NULL; }
|
||||
virtual ThisDeclaration *isThisDeclaration() { return NULL; }
|
||||
virtual TupleDeclaration *isTupleDeclaration() { return NULL; }
|
||||
virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; }
|
||||
virtual AliasDeclaration *isAliasDeclaration() { return NULL; }
|
||||
virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; }
|
||||
virtual FuncDeclaration *isFuncDeclaration() { return NULL; }
|
||||
virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; }
|
||||
virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; }
|
||||
virtual CtorDeclaration *isCtorDeclaration() { return NULL; }
|
||||
virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; }
|
||||
virtual DtorDeclaration *isDtorDeclaration() { return NULL; }
|
||||
virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; }
|
||||
virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; }
|
||||
virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; }
|
||||
virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; }
|
||||
virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; }
|
||||
virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; }
|
||||
virtual NewDeclaration *isNewDeclaration() { return NULL; }
|
||||
virtual VarDeclaration *isVarDeclaration() { return NULL; }
|
||||
virtual ClassDeclaration *isClassDeclaration() { return NULL; }
|
||||
virtual StructDeclaration *isStructDeclaration() { return NULL; }
|
||||
virtual UnionDeclaration *isUnionDeclaration() { return NULL; }
|
||||
virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; }
|
||||
virtual ScopeDsymbol *isScopeDsymbol() { return NULL; }
|
||||
virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; }
|
||||
virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; }
|
||||
virtual Import *isImport() { return NULL; }
|
||||
virtual EnumDeclaration *isEnumDeclaration() { return NULL; }
|
||||
virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; }
|
||||
virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; }
|
||||
virtual AttribDeclaration *isAttribDeclaration() { return NULL; }
|
||||
virtual OverloadSet *isOverloadSet() { return NULL; }
|
||||
virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; }
|
||||
virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; }
|
||||
#if TARGET_NET
|
||||
virtual PragmaScope* isPragmaScope() { return NULL; }
|
||||
#endif
|
||||
#if IN_LLVM
|
||||
/// Codegen traversal
|
||||
virtual void codegen(Ir* ir);
|
||||
|
||||
// llvm stuff
|
||||
int llvmInternal;
|
||||
|
||||
IrDsymbol ir;
|
||||
IrSymbol* irsym;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Dsymbol that generates a scope
|
||||
|
||||
struct ScopeDsymbol : Dsymbol
|
||||
{
|
||||
Dsymbols *members; // all Dsymbol's in this scope
|
||||
DsymbolTable *symtab; // members[] sorted into table
|
||||
|
||||
Dsymbols *imports; // imported Dsymbol's
|
||||
unsigned char *prots; // array of PROT, one for each import
|
||||
|
||||
ScopeDsymbol();
|
||||
ScopeDsymbol(Identifier *id);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
Dsymbol *search(Loc loc, Identifier *ident, int flags);
|
||||
void importScope(Dsymbol *s, enum PROT protection);
|
||||
int isforwardRef();
|
||||
void defineRef(Dsymbol *s);
|
||||
static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2);
|
||||
Dsymbol *nameCollision(Dsymbol *s);
|
||||
const char *kind();
|
||||
FuncDeclaration *findGetMembers();
|
||||
virtual Dsymbol *symtabInsert(Dsymbol *s);
|
||||
bool hasStaticCtorOrDtor();
|
||||
|
||||
void emitMemberComments(Scope *sc);
|
||||
|
||||
static size_t dim(Dsymbols *members);
|
||||
static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL);
|
||||
|
||||
typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s);
|
||||
static int foreach(Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn=NULL);
|
||||
|
||||
ScopeDsymbol *isScopeDsymbol() { return this; }
|
||||
};
|
||||
|
||||
// With statement scope
|
||||
|
||||
struct WithScopeSymbol : ScopeDsymbol
|
||||
{
|
||||
WithStatement *withstate;
|
||||
|
||||
WithScopeSymbol(WithStatement *withstate);
|
||||
Dsymbol *search(Loc loc, Identifier *ident, int flags);
|
||||
|
||||
WithScopeSymbol *isWithScopeSymbol() { return this; }
|
||||
};
|
||||
|
||||
// Array Index/Slice scope
|
||||
|
||||
struct ArrayScopeSymbol : ScopeDsymbol
|
||||
{
|
||||
Expression *exp; // IndexExp or SliceExp
|
||||
TypeTuple *type; // for tuple[length]
|
||||
TupleDeclaration *td; // for tuples of objects
|
||||
Scope *sc;
|
||||
|
||||
ArrayScopeSymbol(Scope *sc, Expression *e);
|
||||
ArrayScopeSymbol(Scope *sc, TypeTuple *t);
|
||||
ArrayScopeSymbol(Scope *sc, TupleDeclaration *td);
|
||||
Dsymbol *search(Loc loc, Identifier *ident, int flags);
|
||||
|
||||
ArrayScopeSymbol *isArrayScopeSymbol() { return this; }
|
||||
};
|
||||
|
||||
// Overload Sets
|
||||
|
||||
#if DMDV2
|
||||
struct OverloadSet : Dsymbol
|
||||
{
|
||||
Dsymbols a; // array of Dsymbols
|
||||
|
||||
OverloadSet();
|
||||
void push(Dsymbol *s);
|
||||
OverloadSet *isOverloadSet() { return this; }
|
||||
const char *kind();
|
||||
};
|
||||
#endif
|
||||
|
||||
// Table of Dsymbol's
|
||||
|
||||
struct DsymbolTable : Object
|
||||
{
|
||||
AA *tab;
|
||||
|
||||
DsymbolTable();
|
||||
~DsymbolTable();
|
||||
|
||||
// Look up Identifier. Return Dsymbol if found, NULL if not.
|
||||
Dsymbol *lookup(Identifier *ident);
|
||||
|
||||
// Insert Dsymbol in table. Return NULL if already there.
|
||||
Dsymbol *insert(Dsymbol *s);
|
||||
|
||||
// Look for Dsymbol in table. If there, return it. If not, insert s and return that.
|
||||
Dsymbol *update(Dsymbol *s);
|
||||
Dsymbol *insert(Identifier *ident, Dsymbol *s); // when ident and s are not the same
|
||||
};
|
||||
|
||||
#endif /* DMD_DSYMBOL_H */
|
||||
152
dmd2/dump.c
Normal file
152
dmd2/dump.c
Normal file
@@ -0,0 +1,152 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mars.h"
|
||||
#include "mtype.h"
|
||||
#include "declaration.h"
|
||||
#include "expression.h"
|
||||
#include "template.h"
|
||||
|
||||
static void indent(int indent)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < indent; i++)
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
static char *type_print(Type *type)
|
||||
{
|
||||
return type ? type->toChars() : (char *) "null";
|
||||
}
|
||||
|
||||
void dumpExpressions(int i, Expressions *exps)
|
||||
{
|
||||
if (exps)
|
||||
{
|
||||
for (size_t j = 0; j < exps->dim; j++)
|
||||
{ Expression *e = exps->tdata()[j];
|
||||
indent(i);
|
||||
printf("(\n");
|
||||
e->dump(i + 2);
|
||||
indent(i);
|
||||
printf(")\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Expression::dump(int i)
|
||||
{
|
||||
indent(i);
|
||||
printf("%p %s type=%s\n", this, Token::toChars(op), type_print(type));
|
||||
}
|
||||
|
||||
void IntegerExp::dump(int i)
|
||||
{
|
||||
indent(i);
|
||||
printf("%p %jd type=%s\n", this, (intmax_t)value, type_print(type));
|
||||
}
|
||||
|
||||
void IdentifierExp::dump(int i)
|
||||
{
|
||||
indent(i);
|
||||
printf("%p ident '%s' type=%s\n", this, ident->toChars(), type_print(type));
|
||||
}
|
||||
|
||||
void DsymbolExp::dump(int i)
|
||||
{
|
||||
indent(i);
|
||||
printf("%p %s type=%s\n", this, s->toChars(), type_print(type));
|
||||
}
|
||||
|
||||
void VarExp::dump(int i)
|
||||
{
|
||||
indent(i);
|
||||
printf("%p %s var=%s type=%s\n", this, Token::toChars(op), var->toChars(), type_print(type));
|
||||
}
|
||||
|
||||
void UnaExp::dump(int i)
|
||||
{
|
||||
indent(i);
|
||||
printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1);
|
||||
if (e1)
|
||||
e1->dump(i + 2);
|
||||
}
|
||||
|
||||
void CallExp::dump(int i)
|
||||
{
|
||||
UnaExp::dump(i);
|
||||
dumpExpressions(i, arguments);
|
||||
}
|
||||
|
||||
void SliceExp::dump(int i)
|
||||
{
|
||||
indent(i);
|
||||
printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1);
|
||||
if (e1)
|
||||
e1->dump(i + 2);
|
||||
if (lwr)
|
||||
lwr->dump(i + 2);
|
||||
if (upr)
|
||||
upr->dump(i + 2);
|
||||
}
|
||||
|
||||
void DotIdExp::dump(int i)
|
||||
{
|
||||
indent(i);
|
||||
printf("%p %s type=%s ident=%s e1=%p\n", this, Token::toChars(op), type_print(type), ident->toChars(), e1);
|
||||
if (e1)
|
||||
e1->dump(i + 2);
|
||||
}
|
||||
|
||||
void DotVarExp::dump(int i)
|
||||
{
|
||||
indent(i);
|
||||
printf("%p %s type=%s var='%s' e1=%p\n", this, Token::toChars(op), type_print(type), var->toChars(), e1);
|
||||
if (e1)
|
||||
e1->dump(i + 2);
|
||||
}
|
||||
|
||||
void DotTemplateInstanceExp::dump(int i)
|
||||
{
|
||||
indent(i);
|
||||
printf("%p %s type=%s ti='%s' e1=%p\n", this, Token::toChars(op), type_print(type), ti->toChars(), e1);
|
||||
if (e1)
|
||||
e1->dump(i + 2);
|
||||
}
|
||||
|
||||
void DelegateExp::dump(int i)
|
||||
{
|
||||
indent(i);
|
||||
printf("%p %s func=%s type=%s e1=%p\n", this, Token::toChars(op), func->toChars(), type_print(type), e1);
|
||||
if (e1)
|
||||
e1->dump(i + 2);
|
||||
}
|
||||
|
||||
void BinExp::dump(int i)
|
||||
{
|
||||
indent(i);
|
||||
const char *sop = Token::toChars(op);
|
||||
if (op == TOKblit)
|
||||
sop = "blit";
|
||||
else if (op == TOKconstruct)
|
||||
sop = "construct";
|
||||
printf("%p %s type=%s e1=%p e2=%p\n", this, sop, type_print(type), e1, e2);
|
||||
if (e1)
|
||||
e1->dump(i + 2);
|
||||
if (e2)
|
||||
e2->dump(i + 2);
|
||||
}
|
||||
|
||||
|
||||
2391
dmd2/entity.c
Normal file
2391
dmd2/entity.c
Normal file
File diff suppressed because it is too large
Load Diff
427
dmd2/enum.c
Normal file
427
dmd2/enum.c
Normal file
@@ -0,0 +1,427 @@
|
||||
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "root.h"
|
||||
#include "enum.h"
|
||||
#include "mtype.h"
|
||||
#include "scope.h"
|
||||
#include "id.h"
|
||||
#include "expression.h"
|
||||
#include "module.h"
|
||||
#include "declaration.h"
|
||||
|
||||
/********************************* EnumDeclaration ****************************/
|
||||
|
||||
EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
|
||||
: ScopeDsymbol(id)
|
||||
{
|
||||
this->loc = loc;
|
||||
type = new TypeEnum(this);
|
||||
this->memtype = memtype;
|
||||
maxval = NULL;
|
||||
minval = NULL;
|
||||
defaultval = NULL;
|
||||
#if IN_DMD
|
||||
sinit = NULL;
|
||||
#endif
|
||||
isdeprecated = 0;
|
||||
isdone = 0;
|
||||
}
|
||||
|
||||
Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s)
|
||||
{
|
||||
Type *t = NULL;
|
||||
if (memtype)
|
||||
t = memtype->syntaxCopy();
|
||||
|
||||
EnumDeclaration *ed;
|
||||
if (s)
|
||||
{ ed = (EnumDeclaration *)s;
|
||||
ed->memtype = t;
|
||||
}
|
||||
else
|
||||
ed = new EnumDeclaration(loc, ident, t);
|
||||
ScopeDsymbol::syntaxCopy(ed);
|
||||
return ed;
|
||||
}
|
||||
|
||||
void EnumDeclaration::semantic0(Scope *sc)
|
||||
{
|
||||
/* This function is a hack to get around a significant problem.
|
||||
* The members of anonymous enums, like:
|
||||
* enum { A, B, C }
|
||||
* don't get installed into the symbol table until after they are
|
||||
* semantically analyzed, yet they're supposed to go into the enclosing
|
||||
* scope's table. Hence, when forward referenced, they come out as
|
||||
* 'undefined'. The real fix is to add them in at addSymbol() time.
|
||||
* But to get code to compile, we'll just do this quick hack at the moment
|
||||
* to compile it if it doesn't depend on anything else.
|
||||
*/
|
||||
|
||||
if (isdone || !scope)
|
||||
return;
|
||||
if (!isAnonymous() || memtype)
|
||||
return;
|
||||
for (size_t i = 0; i < members->dim; i++)
|
||||
{
|
||||
EnumMember *em = (*members)[i]->isEnumMember();
|
||||
if (em && (em->type || em->value))
|
||||
return;
|
||||
}
|
||||
|
||||
// Can do it
|
||||
semantic(sc);
|
||||
}
|
||||
|
||||
void EnumDeclaration::semantic(Scope *sc)
|
||||
{
|
||||
Type *t;
|
||||
Scope *sce;
|
||||
|
||||
//printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars());
|
||||
//printf("EnumDeclaration::semantic() %s\n", toChars());
|
||||
if (!members) // enum ident;
|
||||
return;
|
||||
|
||||
if (!memtype && !isAnonymous())
|
||||
{ // Set memtype if we can to reduce fwd reference errors
|
||||
memtype = Type::tint32; // case 1) enum ident { ... }
|
||||
}
|
||||
|
||||
if (symtab) // if already done
|
||||
{ if (isdone || !scope)
|
||||
return; // semantic() already completed
|
||||
}
|
||||
else
|
||||
symtab = new DsymbolTable();
|
||||
|
||||
Scope *scx = NULL;
|
||||
if (scope)
|
||||
{ sc = scope;
|
||||
scx = scope; // save so we don't make redundant copies
|
||||
scope = NULL;
|
||||
}
|
||||
|
||||
unsigned dprogress_save = Module::dprogress;
|
||||
|
||||
if (sc->stc & STCdeprecated)
|
||||
isdeprecated = 1;
|
||||
|
||||
parent = sc->parent;
|
||||
|
||||
/* The separate, and distinct, cases are:
|
||||
* 1. enum { ... }
|
||||
* 2. enum : memtype { ... }
|
||||
* 3. enum ident { ... }
|
||||
* 4. enum ident : memtype { ... }
|
||||
*/
|
||||
|
||||
if (memtype)
|
||||
{
|
||||
memtype = memtype->semantic(loc, sc);
|
||||
|
||||
/* Check to see if memtype is forward referenced
|
||||
*/
|
||||
if (memtype->ty == Tenum)
|
||||
{ EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc);
|
||||
if (!sym->memtype || !sym->members || !sym->symtab || sym->scope)
|
||||
{ // memtype is forward referenced, so try again later
|
||||
scope = scx ? scx : new Scope(*sc);
|
||||
scope->setNoFree();
|
||||
scope->module->addDeferredSemantic(this);
|
||||
Module::dprogress = dprogress_save;
|
||||
//printf("\tdeferring %s\n", toChars());
|
||||
return;
|
||||
}
|
||||
}
|
||||
#if 0 // Decided to abandon this restriction for D 2.0
|
||||
if (!memtype->isintegral())
|
||||
{ error("base type must be of integral type, not %s", memtype->toChars());
|
||||
memtype = Type::tint32;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
isdone = 1;
|
||||
Module::dprogress++;
|
||||
|
||||
type = type->semantic(loc, sc);
|
||||
if (isAnonymous())
|
||||
sce = sc;
|
||||
else
|
||||
{ sce = sc->push(this);
|
||||
sce->parent = this;
|
||||
}
|
||||
if (members->dim == 0)
|
||||
error("enum %s must have at least one member", toChars());
|
||||
int first = 1;
|
||||
Expression *elast = NULL;
|
||||
for (size_t i = 0; i < members->dim; i++)
|
||||
{
|
||||
EnumMember *em = (*members)[i]->isEnumMember();
|
||||
Expression *e;
|
||||
|
||||
if (!em)
|
||||
/* The e->semantic(sce) can insert other symbols, such as
|
||||
* template instances and function literals.
|
||||
*/
|
||||
continue;
|
||||
|
||||
//printf(" Enum member '%s'\n",em->toChars());
|
||||
if (em->type)
|
||||
em->type = em->type->semantic(em->loc, sce);
|
||||
e = em->value;
|
||||
if (e)
|
||||
{
|
||||
assert(e->dyncast() == DYNCAST_EXPRESSION);
|
||||
e = e->semantic(sce);
|
||||
e = e->optimize(WANTvalue | WANTinterpret);
|
||||
if (memtype)
|
||||
{
|
||||
e = e->implicitCastTo(sce, memtype);
|
||||
e = e->optimize(WANTvalue | WANTinterpret);
|
||||
if (!isAnonymous())
|
||||
e = e->castTo(sce, type);
|
||||
t = memtype;
|
||||
}
|
||||
else if (em->type)
|
||||
{
|
||||
e = e->implicitCastTo(sce, em->type);
|
||||
e = e->optimize(WANTvalue | WANTinterpret);
|
||||
assert(isAnonymous());
|
||||
t = e->type;
|
||||
}
|
||||
else
|
||||
t = e->type;
|
||||
}
|
||||
else if (first)
|
||||
{
|
||||
if (memtype)
|
||||
t = memtype;
|
||||
else if (em->type)
|
||||
t = em->type;
|
||||
else
|
||||
t = Type::tint32;
|
||||
e = new IntegerExp(em->loc, 0, Type::tint32);
|
||||
e = e->implicitCastTo(sce, t);
|
||||
e = e->optimize(WANTvalue | WANTinterpret);
|
||||
if (!isAnonymous())
|
||||
e = e->castTo(sce, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set value to (elast + 1).
|
||||
// But first check that (elast != t.max)
|
||||
assert(elast);
|
||||
e = new EqualExp(TOKequal, em->loc, elast, t->getProperty(0, Id::max));
|
||||
e = e->semantic(sce);
|
||||
e = e->optimize(WANTvalue | WANTinterpret);
|
||||
if (e->toInteger())
|
||||
error("overflow of enum value %s", elast->toChars());
|
||||
|
||||
// Now set e to (elast + 1)
|
||||
e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32));
|
||||
e = e->semantic(sce);
|
||||
e = e->castTo(sce, elast->type);
|
||||
e = e->optimize(WANTvalue | WANTinterpret);
|
||||
}
|
||||
elast = e;
|
||||
em->value = e;
|
||||
|
||||
// Add to symbol table only after evaluating 'value'
|
||||
if (isAnonymous())
|
||||
{
|
||||
/* Anonymous enum members get added to enclosing scope.
|
||||
*/
|
||||
for (Scope *sct = sce; sct; sct = sct->enclosing)
|
||||
{
|
||||
if (sct->scopesym)
|
||||
{
|
||||
if (!sct->scopesym->symtab)
|
||||
sct->scopesym->symtab = new DsymbolTable();
|
||||
em->addMember(sce, sct->scopesym, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
em->addMember(sc, this, 1);
|
||||
|
||||
/* Compute .min, .max and .default values.
|
||||
* If enum doesn't have a name, we can never identify the enum type,
|
||||
* so there is no purpose for a .min, .max or .default
|
||||
*/
|
||||
if (!isAnonymous())
|
||||
{
|
||||
if (first)
|
||||
{ defaultval = e;
|
||||
minval = e;
|
||||
maxval = e;
|
||||
}
|
||||
else
|
||||
{ Expression *ec;
|
||||
|
||||
/* In order to work successfully with UDTs,
|
||||
* build expressions to do the comparisons,
|
||||
* and let the semantic analyzer and constant
|
||||
* folder give us the result.
|
||||
*/
|
||||
|
||||
// Compute if(e < minval)
|
||||
ec = new CmpExp(TOKlt, em->loc, e, minval);
|
||||
ec = ec->semantic(sce);
|
||||
ec = ec->optimize(WANTvalue | WANTinterpret);
|
||||
if (ec->toInteger())
|
||||
minval = e;
|
||||
|
||||
ec = new CmpExp(TOKgt, em->loc, e, maxval);
|
||||
ec = ec->semantic(sce);
|
||||
ec = ec->optimize(WANTvalue | WANTinterpret);
|
||||
if (ec->toInteger())
|
||||
maxval = e;
|
||||
}
|
||||
}
|
||||
first = 0;
|
||||
}
|
||||
//printf("defaultval = %lld\n", defaultval);
|
||||
|
||||
//if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars());
|
||||
if (sc != sce)
|
||||
sce->pop();
|
||||
//members->print();
|
||||
}
|
||||
|
||||
int EnumDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
|
||||
{
|
||||
if (isAnonymous())
|
||||
return Dsymbol::oneMembers(members, ps, ident);
|
||||
return Dsymbol::oneMember(ps, ident);
|
||||
}
|
||||
|
||||
void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
buf->writestring("enum ");
|
||||
if (ident)
|
||||
{ buf->writestring(ident->toChars());
|
||||
buf->writeByte(' ');
|
||||
}
|
||||
if (memtype)
|
||||
{
|
||||
buf->writestring(": ");
|
||||
memtype->toCBuffer(buf, NULL, hgs);
|
||||
}
|
||||
if (!members)
|
||||
{
|
||||
buf->writeByte(';');
|
||||
buf->writenl();
|
||||
return;
|
||||
}
|
||||
buf->writenl();
|
||||
buf->writeByte('{');
|
||||
buf->writenl();
|
||||
for (size_t i = 0; i < members->dim; i++)
|
||||
{
|
||||
EnumMember *em = (*members)[i]->isEnumMember();
|
||||
if (!em)
|
||||
continue;
|
||||
//buf->writestring(" ");
|
||||
em->toCBuffer(buf, hgs);
|
||||
buf->writeByte(',');
|
||||
buf->writenl();
|
||||
}
|
||||
buf->writeByte('}');
|
||||
buf->writenl();
|
||||
}
|
||||
|
||||
Type *EnumDeclaration::getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
const char *EnumDeclaration::kind()
|
||||
{
|
||||
return "enum";
|
||||
}
|
||||
|
||||
int EnumDeclaration::isDeprecated()
|
||||
{
|
||||
return isdeprecated;
|
||||
}
|
||||
|
||||
Dsymbol *EnumDeclaration::search(Loc loc, Identifier *ident, int flags)
|
||||
{
|
||||
//printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars());
|
||||
if (scope)
|
||||
// Try one last time to resolve this enum
|
||||
semantic(scope);
|
||||
|
||||
if (!members || !symtab || scope)
|
||||
{ error("is forward referenced when looking for '%s'", ident->toChars());
|
||||
//*(char*)0=0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
|
||||
return s;
|
||||
}
|
||||
|
||||
/********************************* EnumMember ****************************/
|
||||
|
||||
EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *type)
|
||||
: Dsymbol(id)
|
||||
{
|
||||
this->value = value;
|
||||
this->type = type;
|
||||
this->loc = loc;
|
||||
}
|
||||
|
||||
Dsymbol *EnumMember::syntaxCopy(Dsymbol *s)
|
||||
{
|
||||
Expression *e = NULL;
|
||||
if (value)
|
||||
e = value->syntaxCopy();
|
||||
|
||||
Type *t = NULL;
|
||||
if (type)
|
||||
t = type->syntaxCopy();
|
||||
|
||||
EnumMember *em;
|
||||
if (s)
|
||||
{ em = (EnumMember *)s;
|
||||
em->loc = loc;
|
||||
em->value = e;
|
||||
em->type = t;
|
||||
}
|
||||
else
|
||||
em = new EnumMember(loc, ident, e, t);
|
||||
return em;
|
||||
}
|
||||
|
||||
void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
if (type)
|
||||
type->toCBuffer(buf, ident, hgs);
|
||||
else
|
||||
buf->writestring(ident->toChars());
|
||||
if (value)
|
||||
{
|
||||
buf->writestring(" = ");
|
||||
value->toCBuffer(buf, hgs);
|
||||
}
|
||||
}
|
||||
|
||||
const char *EnumMember::kind()
|
||||
{
|
||||
return "enum member";
|
||||
}
|
||||
|
||||
|
||||
97
dmd2/enum.h
Normal file
97
dmd2/enum.h
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2008 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_ENUM_H
|
||||
#define DMD_ENUM_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
#include "root.h"
|
||||
#include "dsymbol.h"
|
||||
|
||||
struct Identifier;
|
||||
struct Type;
|
||||
struct Expression;
|
||||
struct HdrGenState;
|
||||
|
||||
|
||||
struct EnumDeclaration : ScopeDsymbol
|
||||
{ /* enum ident : memtype { ... }
|
||||
*/
|
||||
Type *type; // the TypeEnum
|
||||
Type *memtype; // type of the members
|
||||
|
||||
#if DMDV1
|
||||
dinteger_t maxval;
|
||||
dinteger_t minval;
|
||||
dinteger_t defaultval; // default initializer
|
||||
#else
|
||||
Expression *maxval;
|
||||
Expression *minval;
|
||||
Expression *defaultval; // default initializer
|
||||
#endif
|
||||
int isdeprecated;
|
||||
int isdone; // 0: not done
|
||||
// 1: semantic() successfully completed
|
||||
|
||||
EnumDeclaration(Loc loc, Identifier *id, Type *memtype);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void semantic0(Scope *sc);
|
||||
void semantic(Scope *sc);
|
||||
int oneMember(Dsymbol **ps, Identifier *ident = NULL);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
Type *getType();
|
||||
const char *kind();
|
||||
#if DMDV2
|
||||
Dsymbol *search(Loc, Identifier *ident, int flags);
|
||||
#endif
|
||||
int isDeprecated(); // is Dsymbol deprecated?
|
||||
|
||||
void emitComment(Scope *sc);
|
||||
void toJsonBuffer(OutBuffer *buf);
|
||||
void toDocBuffer(OutBuffer *buf);
|
||||
|
||||
EnumDeclaration *isEnumDeclaration() { return this; }
|
||||
|
||||
#if IN_DMD
|
||||
void toObjFile(int multiobj); // compile to .obj file
|
||||
void toDebug();
|
||||
int cvMember(unsigned char *p);
|
||||
|
||||
Symbol *sinit;
|
||||
Symbol *toInitializer();
|
||||
#endif
|
||||
|
||||
#if IN_LLVM
|
||||
void codegen(Ir*);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
struct EnumMember : Dsymbol
|
||||
{
|
||||
Expression *value;
|
||||
Type *type;
|
||||
|
||||
EnumMember(Loc loc, Identifier *id, Expression *value, Type *type);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
const char *kind();
|
||||
|
||||
void emitComment(Scope *sc);
|
||||
void toJsonBuffer(OutBuffer *buf);
|
||||
void toDocBuffer(OutBuffer *buf);
|
||||
|
||||
EnumMember *isEnumMember() { return this; }
|
||||
};
|
||||
|
||||
#endif /* DMD_ENUM_H */
|
||||
12570
dmd2/expression.c
Normal file
12570
dmd2/expression.c
Normal file
File diff suppressed because it is too large
Load Diff
2141
dmd2/expression.h
Normal file
2141
dmd2/expression.h
Normal file
File diff suppressed because it is too large
Load Diff
4236
dmd2/func.c
Normal file
4236
dmd2/func.c
Normal file
File diff suppressed because it is too large
Load Diff
248
dmd2/gpl.txt
Normal file
248
dmd2/gpl.txt
Normal file
@@ -0,0 +1,248 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 1, February 1989
|
||||
|
||||
Copyright (C) 1989 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The license agreements of most software companies try to keep users
|
||||
at the mercy of those companies. By contrast, our General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. The
|
||||
General Public License applies to the Free Software Foundation's
|
||||
software and to any other program whose authors commit to using it.
|
||||
You can use it for your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Specifically, the General Public License is designed to make
|
||||
sure that you have the freedom to give away or sell copies of free
|
||||
software, that you receive source code or can get it if you want it,
|
||||
that you can change the software or use pieces of it in new free
|
||||
programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of a such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must tell them their rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any program or other work which
|
||||
contains a notice placed by the copyright holder saying it may be
|
||||
distributed under the terms of this General Public License. The
|
||||
"Program", below, refers to any such program or work, and a "work based
|
||||
on the Program" means either the Program or any work containing the
|
||||
Program or a portion of it, either verbatim or with modifications. Each
|
||||
licensee is addressed as "you".
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's source
|
||||
code as you receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice and
|
||||
disclaimer of warranty; keep intact all the notices that refer to this
|
||||
General Public License and to the absence of any warranty; and give any
|
||||
other recipients of the Program a copy of this General Public License
|
||||
along with the Program. You may charge a fee for the physical act of
|
||||
transferring a copy.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion of
|
||||
it, and copy and distribute such modifications under the terms of Paragraph
|
||||
1 above, provided that you also do the following:
|
||||
|
||||
a) cause the modified files to carry prominent notices stating that
|
||||
you changed the files and the date of any change; and
|
||||
|
||||
b) cause the whole of any work that you distribute or publish, that
|
||||
in whole or in part contains the Program or any part thereof, either
|
||||
with or without modifications, to be licensed at no charge to all
|
||||
third parties under the terms of this General Public License (except
|
||||
that you may choose to grant warranty protection to some or all
|
||||
third parties, at your option).
|
||||
|
||||
c) If the modified program normally reads commands interactively when
|
||||
run, you must cause it, when started running for such interactive use
|
||||
in the simplest and most usual way, to print or display an
|
||||
announcement including an appropriate copyright notice and a notice
|
||||
that there is no warranty (or else, saying that you provide a
|
||||
warranty) and that users may redistribute the program under these
|
||||
conditions, and telling the user how to view a copy of this General
|
||||
Public License.
|
||||
|
||||
d) You may charge a fee for the physical act of transferring a
|
||||
copy, and you may at your option offer warranty protection in
|
||||
exchange for a fee.
|
||||
|
||||
Mere aggregation of another independent work with the Program (or its
|
||||
derivative) on a volume of a storage or distribution medium does not bring
|
||||
the other work under the scope of these terms.
|
||||
|
||||
3. You may copy and distribute the Program (or a portion or derivative of
|
||||
it, under Paragraph 2) in object code or executable form under the terms of
|
||||
Paragraphs 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of
|
||||
Paragraphs 1 and 2 above; or,
|
||||
|
||||
b) accompany it with a written offer, valid for at least three
|
||||
years, to give any third party free (except for a nominal charge
|
||||
for the cost of distribution) a complete machine-readable copy of the
|
||||
corresponding source code, to be distributed under the terms of
|
||||
Paragraphs 1 and 2 above; or,
|
||||
|
||||
c) accompany it with the information you received as to where the
|
||||
corresponding source code may be obtained. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form alone.)
|
||||
|
||||
Source code for a work means the preferred form of the work for making
|
||||
modifications to it. For an executable file, complete source code means
|
||||
all the source code for all modules it contains; but, as a special
|
||||
exception, it need not include source code for modules which are standard
|
||||
libraries that accompany the operating system on which the executable
|
||||
file runs, or for standard header files or definitions files that
|
||||
accompany that operating system.
|
||||
|
||||
4. You may not copy, modify, sublicense, distribute or transfer the
|
||||
Program except as expressly provided under this General Public License.
|
||||
Any attempt otherwise to copy, modify, sublicense, distribute or transfer
|
||||
the Program is void, and will automatically terminate your rights to use
|
||||
the Program under this License. However, parties who have received
|
||||
copies, or rights to use copies, from you under this General Public
|
||||
License will not have their licenses terminated so long as such parties
|
||||
remain in full compliance.
|
||||
|
||||
5. By copying, distributing or modifying the Program (or any work based
|
||||
on the Program) you indicate your acceptance of this license to do so,
|
||||
and all its terms and conditions.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the original
|
||||
licensor to copy, distribute or modify the Program subject to these
|
||||
terms and conditions. You may not impose any further restrictions on the
|
||||
recipients' exercise of the rights granted herein.
|
||||
|
||||
7. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of the license which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
the license, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
8. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to humanity, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these
|
||||
terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest to
|
||||
attach them to the start of each source file to most effectively convey
|
||||
the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19xx name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the
|
||||
appropriate parts of the General Public License. Of course, the
|
||||
commands you use may be called something other than `show w' and `show
|
||||
c'; they could even be mouse-clicks or menu items--whatever suits your
|
||||
program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
program `Gnomovision' (a program to direct compilers to make passes
|
||||
at assemblers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
100
dmd2/hdrgen.c
Normal file
100
dmd2/hdrgen.c
Normal file
@@ -0,0 +1,100 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// Initial header generation implementation by Dave Fladebo
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
// Routines to emit header files
|
||||
|
||||
#define PRETTY_PRINT
|
||||
#define TEST_EMIT_ALL 0 // For Testing
|
||||
|
||||
#define LOG 0
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#if __DMC__
|
||||
#include <complex.h>
|
||||
#endif
|
||||
|
||||
#include "rmem.h"
|
||||
|
||||
#include "id.h"
|
||||
#include "init.h"
|
||||
|
||||
#include "attrib.h"
|
||||
#include "cond.h"
|
||||
#include "enum.h"
|
||||
#include "import.h"
|
||||
#include "module.h"
|
||||
#include "mtype.h"
|
||||
#include "scope.h"
|
||||
#include "staticassert.h"
|
||||
#include "template.h"
|
||||
#include "utf.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "declaration.h"
|
||||
#include "aggregate.h"
|
||||
#include "expression.h"
|
||||
#include "statement.h"
|
||||
#include "mtype.h"
|
||||
#include "hdrgen.h"
|
||||
|
||||
void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs);
|
||||
|
||||
void Module::genhdrfile()
|
||||
{
|
||||
OutBuffer hdrbufr;
|
||||
|
||||
hdrbufr.printf("// D import file generated from '%s'", srcfile->toChars());
|
||||
hdrbufr.writenl();
|
||||
|
||||
HdrGenState hgs;
|
||||
memset(&hgs, 0, sizeof(hgs));
|
||||
hgs.hdrgen = 1;
|
||||
|
||||
toCBuffer(&hdrbufr, &hgs);
|
||||
|
||||
// Transfer image to file
|
||||
hdrfile->setbuffer(hdrbufr.data, hdrbufr.offset);
|
||||
hdrbufr.data = NULL;
|
||||
|
||||
char *pt = FileName::path(hdrfile->toChars());
|
||||
if (*pt)
|
||||
FileName::ensurePathExists(pt);
|
||||
mem.free(pt);
|
||||
hdrfile->writev();
|
||||
}
|
||||
|
||||
|
||||
void Module::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
if (md)
|
||||
{
|
||||
buf->writestring("module ");
|
||||
buf->writestring(md->toChars());
|
||||
buf->writebyte(';');
|
||||
buf->writenl();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < members->dim; i++)
|
||||
{ Dsymbol *s = members->tdata()[i];
|
||||
|
||||
s->toHBuffer(buf, hgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Dsymbol::toHBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
toCBuffer(buf, hgs);
|
||||
}
|
||||
|
||||
|
||||
/*************************************/
|
||||
34
dmd2/hdrgen.h
Normal file
34
dmd2/hdrgen.h
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2006 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// initial header generation implementation by Dave Fladebo
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
|
||||
struct HdrGenState
|
||||
{
|
||||
int hdrgen; // 1 if generating header file
|
||||
int ddoc; // 1 if generating Ddoc file
|
||||
int console; // 1 if writing to console
|
||||
int tpltMember;
|
||||
int inCallExp;
|
||||
int inPtrExp;
|
||||
int inSlcExp;
|
||||
int inDotExp;
|
||||
int inBinExp;
|
||||
int inArrExp;
|
||||
int emitInst;
|
||||
struct
|
||||
{
|
||||
int init;
|
||||
int decl;
|
||||
} FLinit;
|
||||
|
||||
HdrGenState() { memset(this, 0, sizeof(HdrGenState)); }
|
||||
};
|
||||
|
||||
|
||||
772
dmd2/html.c
Normal file
772
dmd2/html.c
Normal file
@@ -0,0 +1,772 @@
|
||||
|
||||
// Copyright (c) 1999-2009 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gpl.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
|
||||
/* HTML parser
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#define MARS 1
|
||||
#include "html.h"
|
||||
|
||||
#if MARS
|
||||
#include <assert.h>
|
||||
#include "root.h"
|
||||
//#include "../mars/mars.h"
|
||||
#else
|
||||
#include "outbuf.h"
|
||||
#include "msgs2.h"
|
||||
|
||||
extern void html_err(const char *, unsigned, unsigned, ...);
|
||||
|
||||
static char __file__[] = __FILE__; /* for tassert.h */
|
||||
#include "tassert.h"
|
||||
#endif
|
||||
|
||||
#if __GNUC__
|
||||
int memicmp(const char *s1, const char *s2, int n);
|
||||
#if 0
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{ char c1 = s1[i];
|
||||
char c2 = s2[i];
|
||||
|
||||
result = c1 - c2;
|
||||
if (result)
|
||||
{
|
||||
if ('A' <= c1 && c1 <= 'Z')
|
||||
c1 += 'a' - 'A';
|
||||
if ('A' <= c2 && c2 <= 'Z')
|
||||
c2 += 'a' - 'A';
|
||||
result = c1 - c2;
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern int HtmlNamedEntity(unsigned char *p, int length);
|
||||
|
||||
static int isLineSeparator(const unsigned char* p);
|
||||
|
||||
/**********************************
|
||||
* Determine if beginning of tag identifier
|
||||
* or a continuation of a tag identifier.
|
||||
*/
|
||||
|
||||
inline int istagstart(int c)
|
||||
{
|
||||
return (isalpha(c) || c == '_');
|
||||
}
|
||||
|
||||
inline int istag(int c)
|
||||
{
|
||||
return (isalnum(c) || c == '_');
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
*/
|
||||
|
||||
Html::Html(const char *sourcename, unsigned char *base, unsigned length)
|
||||
{
|
||||
//printf("Html::Html()\n");
|
||||
this->sourcename = sourcename;
|
||||
this->base = base;
|
||||
p = base;
|
||||
end = base + length;
|
||||
linnum = 1;
|
||||
dbuf = NULL;
|
||||
inCode = 0;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
* Print error & quit.
|
||||
*/
|
||||
|
||||
void Html::error(const char *format, ...)
|
||||
{
|
||||
printf("%s(%d) : HTML Error: ", sourcename, linnum);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vprintf(format, ap);
|
||||
va_end(ap);
|
||||
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
|
||||
//#if MARS
|
||||
// global.errors++;
|
||||
//#else
|
||||
exit(EXIT_FAILURE);
|
||||
//#endif
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
* Extract all the code from an HTML file,
|
||||
* concatenate it all together, and store in buf.
|
||||
*/
|
||||
|
||||
#if MARS
|
||||
void Html::extractCode(OutBuffer *buf)
|
||||
#else
|
||||
void Html::extractCode(Outbuffer *buf)
|
||||
#endif
|
||||
{
|
||||
//printf("Html::extractCode()\n");
|
||||
dbuf = buf; // save for other routines
|
||||
buf->reserve(end - p);
|
||||
inCode = 0;
|
||||
while (1)
|
||||
{
|
||||
//printf("p = %p, *p = x%x\n", p, *p);
|
||||
switch (*p)
|
||||
{
|
||||
#if 0 // strings are not recognized outside of tags
|
||||
case '"':
|
||||
case '\'':
|
||||
skipString();
|
||||
continue;
|
||||
#endif
|
||||
case '<':
|
||||
if (p[1] == '!' && isCommentStart())
|
||||
{ // Comments start with <!--
|
||||
scanComment();
|
||||
}
|
||||
else if(p[1] == '!' && isCDATAStart())
|
||||
{
|
||||
scanCDATA();
|
||||
}
|
||||
else if (p[1] == '/' && istagstart(*skipWhite(p + 2)))
|
||||
skipTag();
|
||||
else if (istagstart(*skipWhite(p + 1)))
|
||||
skipTag();
|
||||
else
|
||||
goto Ldefault;
|
||||
continue;
|
||||
|
||||
case 0:
|
||||
case 0x1a:
|
||||
break; // end of file
|
||||
|
||||
case '&':
|
||||
if (inCode)
|
||||
{ // Translate character entity into ascii for D parser
|
||||
int c;
|
||||
|
||||
c = charEntity();
|
||||
#if MARS
|
||||
buf->writeUTF8(c);
|
||||
#else
|
||||
buf->writeByte(c);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
p++;
|
||||
continue;
|
||||
|
||||
case '\r':
|
||||
if (p[1] == '\n')
|
||||
goto Ldefault;
|
||||
case '\n':
|
||||
linnum++;
|
||||
// Always extract new lines, so that D lexer counts the
|
||||
// lines right.
|
||||
buf->writeByte(*p);
|
||||
p++;
|
||||
continue;
|
||||
|
||||
default:
|
||||
Ldefault:
|
||||
if (inCode)
|
||||
buf->writeByte(*p);
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
buf->writeByte(0); // ending sentinel
|
||||
#if SCPP
|
||||
//printf("Code is: '%s'\n", buf->toString() + 3);
|
||||
#endif
|
||||
#if MARS
|
||||
//printf("D code is: '%s'\n", (char *)buf->data);
|
||||
#endif
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Scan to end of <> tag.
|
||||
* Look for <code> and </code> tags to start/stop D processing.
|
||||
* Input:
|
||||
* p is on opening '<' of tag; it's already verified that
|
||||
* it's a tag by lookahead
|
||||
* Output:
|
||||
* p is past closing '>' of tag
|
||||
*/
|
||||
|
||||
void Html::skipTag()
|
||||
{
|
||||
enum TagState // what parsing state we're in
|
||||
{
|
||||
TStagstart, // start of tag name
|
||||
TStag, // in a tag name
|
||||
TSrest, // following tag name
|
||||
};
|
||||
enum TagState state = TStagstart;
|
||||
int inot;
|
||||
unsigned char *tagstart = NULL;
|
||||
int taglen = 0;
|
||||
|
||||
p++;
|
||||
inot = 0;
|
||||
if (*p == '/')
|
||||
{ inot = 1;
|
||||
p++;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case '>': // found end of tag
|
||||
p++;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
state = TSrest;
|
||||
skipString();
|
||||
continue;
|
||||
|
||||
case '<':
|
||||
if (p[1] == '!' && isCommentStart())
|
||||
{ // Comments start with <!--
|
||||
scanComment();
|
||||
}
|
||||
else if (p[1] == '/' && istagstart(*skipWhite(p + 2)))
|
||||
{ error("nested tag");
|
||||
skipTag();
|
||||
}
|
||||
else if (istagstart(*skipWhite(p + 1)))
|
||||
{ error("nested tag");
|
||||
skipTag();
|
||||
}
|
||||
// Treat comments as if they were whitespace
|
||||
state = TSrest;
|
||||
continue;
|
||||
|
||||
case 0:
|
||||
case 0x1a:
|
||||
error("end of file before end of tag");
|
||||
break; // end of file
|
||||
|
||||
case '\r':
|
||||
if (p[1] == '\n')
|
||||
goto Ldefault;
|
||||
case '\n':
|
||||
linnum++;
|
||||
// Always extract new lines, so that code lexer counts the
|
||||
// lines right.
|
||||
dbuf->writeByte(*p);
|
||||
state = TSrest; // end of tag
|
||||
p++;
|
||||
continue;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\f':
|
||||
case '\v':
|
||||
if (state == TStagstart)
|
||||
{ p++;
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
Ldefault:
|
||||
switch (state)
|
||||
{
|
||||
case TStagstart: // start of tag name
|
||||
assert(istagstart(*p));
|
||||
state = TStag;
|
||||
tagstart = p;
|
||||
taglen = 0;
|
||||
break;
|
||||
|
||||
case TStag:
|
||||
if (istag(*p))
|
||||
{ // Continuing tag name
|
||||
taglen++;
|
||||
}
|
||||
else
|
||||
{ // End of tag name
|
||||
state = TSrest;
|
||||
}
|
||||
break;
|
||||
|
||||
case TSrest:
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// See if we parsed a <code> or </code> tag
|
||||
if (taglen && memicmp((char *) tagstart, (char *) "CODE", taglen) == 0
|
||||
&& *(p - 2) != '/') // ignore "<code />" (XHTML)
|
||||
{
|
||||
if (inot)
|
||||
{ inCode--;
|
||||
if (inCode < 0)
|
||||
inCode = 0; // ignore extra </code>'s
|
||||
}
|
||||
else
|
||||
inCode++;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Scan to end of attribute string.
|
||||
*/
|
||||
|
||||
void Html::skipString()
|
||||
{
|
||||
int tc = *p;
|
||||
|
||||
while (1)
|
||||
{
|
||||
p++;
|
||||
switch (*p)
|
||||
{
|
||||
case '"':
|
||||
case '\'':
|
||||
if (*p == tc)
|
||||
{ p++;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
case '\r':
|
||||
if (p[1] == '\n')
|
||||
goto Ldefault;
|
||||
case '\n':
|
||||
linnum++;
|
||||
// Always extract new lines, so that D lexer counts the
|
||||
// lines right.
|
||||
dbuf->writeByte(*p);
|
||||
continue;
|
||||
|
||||
case 0:
|
||||
case 0x1a:
|
||||
Leof:
|
||||
error("end of file before closing %c of string", tc);
|
||||
break;
|
||||
|
||||
default:
|
||||
Ldefault:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* If p points to any white space, skip it
|
||||
* and return pointer just past it.
|
||||
*/
|
||||
|
||||
unsigned char *Html::skipWhite(unsigned char *q)
|
||||
{
|
||||
for (; 1; q++)
|
||||
{
|
||||
switch (*q)
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\f':
|
||||
case '\v':
|
||||
case '\r':
|
||||
case '\n':
|
||||
continue;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
/***************************************************
|
||||
* Scan to end of comment.
|
||||
* Comments are defined any of a number of ways.
|
||||
* IE 5.0: <!-- followed by >
|
||||
* "HTML The Definitive Guide": <!-- text with at least one space in it -->
|
||||
* Netscape: <!-- --> comments nest
|
||||
* w3c: whitespace can appear between -- and > of comment close
|
||||
*/
|
||||
|
||||
void Html::scanComment()
|
||||
{
|
||||
// Most of the complexity is dealing with the case that
|
||||
// an arbitrary amount of whitespace can appear between
|
||||
// the -- and the > of a comment close.
|
||||
int scangt = 0;
|
||||
|
||||
//printf("scanComment()\n");
|
||||
if (*p == '\n')
|
||||
{ linnum++;
|
||||
// Always extract new lines, so that D lexer counts the
|
||||
// lines right.
|
||||
dbuf->writeByte(*p);
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
//scangt = 1; // IE 5.0 compatibility
|
||||
p++;
|
||||
switch (*p)
|
||||
{
|
||||
case '-':
|
||||
if (p[1] == '-')
|
||||
{
|
||||
if (p[2] == '>') // optimize for most common case
|
||||
{
|
||||
p += 3;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
scangt = 1;
|
||||
}
|
||||
else
|
||||
scangt = 0;
|
||||
continue;
|
||||
|
||||
case '>':
|
||||
if (scangt)
|
||||
{ // found -->
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\f':
|
||||
case '\v':
|
||||
// skip white space
|
||||
continue;
|
||||
|
||||
case '\r':
|
||||
if (p[1] == '\n')
|
||||
goto Ldefault;
|
||||
case '\n':
|
||||
linnum++; // remember to count lines
|
||||
// Always extract new lines, so that D lexer counts the
|
||||
// lines right.
|
||||
dbuf->writeByte(*p);
|
||||
continue;
|
||||
|
||||
case 0:
|
||||
case 0x1a:
|
||||
error("end of file before closing --> of comment");
|
||||
break;
|
||||
|
||||
default:
|
||||
Ldefault:
|
||||
scangt = 0; // it's not -->
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//printf("*p = '%c'\n", *p);
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Determine if we are at the start of a comment.
|
||||
* Input:
|
||||
* p is on the opening '<'
|
||||
* Returns:
|
||||
* 0 if not start of a comment
|
||||
* 1 if start of a comment, p is adjusted to point past --
|
||||
*/
|
||||
|
||||
int Html::isCommentStart()
|
||||
#ifdef __DMC__
|
||||
__out(result)
|
||||
{
|
||||
if (result == 0)
|
||||
;
|
||||
else if (result == 1)
|
||||
{
|
||||
assert(p[-2] == '-' && p[-1] == '-');
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
__body
|
||||
#endif /* __DMC__ */
|
||||
{ unsigned char *s;
|
||||
|
||||
if (p[0] == '<' && p[1] == '!')
|
||||
{
|
||||
for (s = p + 2; 1; s++)
|
||||
{
|
||||
switch (*s)
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\f':
|
||||
case '\v':
|
||||
// skip white space, even though spec says no
|
||||
// white space is allowed
|
||||
continue;
|
||||
|
||||
case '-':
|
||||
if (s[1] == '-')
|
||||
{
|
||||
p = s + 2;
|
||||
return 1;
|
||||
}
|
||||
goto No;
|
||||
|
||||
default:
|
||||
goto No;
|
||||
}
|
||||
}
|
||||
}
|
||||
No:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Html::isCDATAStart()
|
||||
{
|
||||
const char * CDATA_START_MARKER = "<![CDATA[";
|
||||
size_t len = strlen(CDATA_START_MARKER);
|
||||
|
||||
if (strncmp((char*)p, CDATA_START_MARKER, len) == 0)
|
||||
{
|
||||
p += len;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Html::scanCDATA()
|
||||
{
|
||||
while(*p && *p != 0x1A)
|
||||
{
|
||||
int lineSepLength = isLineSeparator(p);
|
||||
if (lineSepLength>0)
|
||||
{
|
||||
/* Always extract new lines, so that D lexer counts the lines
|
||||
* right.
|
||||
*/
|
||||
linnum++;
|
||||
dbuf->writeByte('\n');
|
||||
p += lineSepLength;
|
||||
continue;
|
||||
}
|
||||
else if (p[0] == ']' && p[1] == ']' && p[2] == '>')
|
||||
{
|
||||
/* end of CDATA section */
|
||||
p += 3;
|
||||
return;
|
||||
}
|
||||
else if (inCode)
|
||||
{
|
||||
/* this CDATA section contains D code */
|
||||
dbuf->writeByte(*p);
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
* Convert an HTML character entity into a character.
|
||||
* Forms are:
|
||||
* &name; named entity
|
||||
* &#ddd; decimal
|
||||
* &#xhhhh; hex
|
||||
* Input:
|
||||
* p is on the &
|
||||
*/
|
||||
|
||||
int Html::charEntity()
|
||||
{ int c = 0;
|
||||
int v;
|
||||
int hex;
|
||||
unsigned char *pstart = p;
|
||||
|
||||
//printf("Html::charEntity('%c')\n", *p);
|
||||
if (p[1] == '#')
|
||||
{
|
||||
p++;
|
||||
if (p[1] == 'x' || p[1] == 'X')
|
||||
{ p++;
|
||||
hex = 1;
|
||||
}
|
||||
else
|
||||
hex = 0;
|
||||
if (p[1] == ';')
|
||||
goto Linvalid;
|
||||
while (1)
|
||||
{
|
||||
p++;
|
||||
switch (*p)
|
||||
{
|
||||
case 0:
|
||||
case 0x1a:
|
||||
error("end of file before end of character entity");
|
||||
goto Lignore;
|
||||
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '<': // tag start
|
||||
// Termination is assumed
|
||||
break;
|
||||
|
||||
case ';':
|
||||
// Termination is explicit
|
||||
p++;
|
||||
break;
|
||||
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
v = *p - '0';
|
||||
goto Lvalue;
|
||||
|
||||
case 'a': case 'b': case 'c':
|
||||
case 'd': case 'e': case 'f':
|
||||
if (!hex)
|
||||
goto Linvalid;
|
||||
v = (*p - 'a') + 10;
|
||||
goto Lvalue;
|
||||
|
||||
case 'A': case 'B': case 'C':
|
||||
case 'D': case 'E': case 'F':
|
||||
if (!hex)
|
||||
goto Linvalid;
|
||||
v = (*p - 'A') + 10;
|
||||
goto Lvalue;
|
||||
|
||||
Lvalue:
|
||||
if (hex)
|
||||
c = (c << 4) + v;
|
||||
else
|
||||
c = (c * 10) + v;
|
||||
if (c > 0x10FFFF)
|
||||
{
|
||||
error("character entity out of range");
|
||||
goto Lignore;
|
||||
}
|
||||
continue;
|
||||
|
||||
default:
|
||||
Linvalid:
|
||||
error("invalid numeric character reference");
|
||||
goto Lignore;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's a named entity; gather all characters until ;
|
||||
unsigned char *idstart = p + 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
p++;
|
||||
switch (*p)
|
||||
{
|
||||
case 0:
|
||||
case 0x1a:
|
||||
error("end of file before end of character entity");
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '<': // tag start
|
||||
// Termination is assumed
|
||||
c = HtmlNamedEntity(idstart, p - idstart);
|
||||
if (c == -1)
|
||||
goto Lignore;
|
||||
break;
|
||||
|
||||
case ';':
|
||||
// Termination is explicit
|
||||
c = HtmlNamedEntity(idstart, p - idstart);
|
||||
if (c == -1)
|
||||
goto Lignore;
|
||||
p++;
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Kludge to convert non-breaking space to ascii space
|
||||
if (c == 160)
|
||||
c = ' ';
|
||||
|
||||
return c;
|
||||
|
||||
Lignore:
|
||||
//printf("Lignore\n");
|
||||
p = pstart + 1;
|
||||
return '&';
|
||||
}
|
||||
|
||||
/**
|
||||
* identify DOS, Linux, Mac, Next and Unicode line endings
|
||||
* 0 if this is no line separator
|
||||
* >0 the length of the separator
|
||||
* Note: input has to be UTF-8
|
||||
*/
|
||||
static int isLineSeparator(const unsigned char* p)
|
||||
{
|
||||
// Linux
|
||||
if( p[0]=='\n')
|
||||
return 1;
|
||||
|
||||
// Mac & Dos
|
||||
if( p[0]=='\r')
|
||||
return (p[1]=='\n') ? 2 : 1;
|
||||
|
||||
// Unicode (line || paragraph sep.)
|
||||
if( p[0]==0xE2 && p[1]==0x80 && (p[2]==0xA8 || p[2]==0xA9))
|
||||
return 3;
|
||||
|
||||
// Next
|
||||
if( p[0]==0xC2 && p[1]==0x85)
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
50
dmd2/html.h
Normal file
50
dmd2/html.h
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
// Copyright (c) 1999-2009 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gpl.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
|
||||
#if MARS
|
||||
struct OutBuffer;
|
||||
#else
|
||||
struct Outbuffer;
|
||||
#endif
|
||||
|
||||
struct Html
|
||||
{
|
||||
const char *sourcename;
|
||||
|
||||
unsigned char *base; // pointer to start of buffer
|
||||
unsigned char *end; // past end of buffer
|
||||
unsigned char *p; // current character
|
||||
unsigned linnum; // current line number
|
||||
#if MARS
|
||||
OutBuffer *dbuf; // code source buffer
|
||||
#else
|
||||
Outbuffer *dbuf; // code source buffer
|
||||
#endif
|
||||
int inCode; // !=0 if in code
|
||||
|
||||
|
||||
Html(const char *sourcename, unsigned char *base, unsigned length);
|
||||
|
||||
void error(const char *format, ...);
|
||||
#if MARS
|
||||
void extractCode(OutBuffer *buf);
|
||||
#else
|
||||
void extractCode(Outbuffer *buf);
|
||||
#endif
|
||||
void skipTag();
|
||||
void skipString();
|
||||
unsigned char *skipWhite(unsigned char *q);
|
||||
void scanComment();
|
||||
int isCommentStart();
|
||||
void scanCDATA();
|
||||
int isCDATAStart();
|
||||
int charEntity();
|
||||
static int namedEntity(unsigned char *p, int length);
|
||||
};
|
||||
102
dmd2/identifier.c
Normal file
102
dmd2/identifier.c
Normal file
@@ -0,0 +1,102 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2006 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "root.h"
|
||||
#include "identifier.h"
|
||||
#include "mars.h"
|
||||
#include "lexer.h"
|
||||
#include "id.h"
|
||||
|
||||
Identifier::Identifier(const char *string, int value)
|
||||
{
|
||||
//printf("Identifier('%s', %d)\n", string, value);
|
||||
this->string = string;
|
||||
this->value = value;
|
||||
this->len = strlen(string);
|
||||
}
|
||||
|
||||
hash_t Identifier::hashCode()
|
||||
{
|
||||
return String::calcHash(string);
|
||||
}
|
||||
|
||||
int Identifier::equals(Object *o)
|
||||
{
|
||||
return this == o || memcmp(string,o->toChars(),len+1) == 0;
|
||||
}
|
||||
|
||||
int Identifier::compare(Object *o)
|
||||
{
|
||||
return memcmp(string, o->toChars(), len + 1);
|
||||
}
|
||||
|
||||
char *Identifier::toChars()
|
||||
{
|
||||
return (char *)string;
|
||||
}
|
||||
|
||||
const char *Identifier::toHChars2()
|
||||
{
|
||||
const char *p = NULL;
|
||||
|
||||
if (this == Id::ctor) p = "this";
|
||||
else if (this == Id::dtor) p = "~this";
|
||||
else if (this == Id::classInvariant) p = "invariant";
|
||||
else if (this == Id::unitTest) p = "unittest";
|
||||
else if (this == Id::dollar) p = "$";
|
||||
else if (this == Id::withSym) p = "with";
|
||||
else if (this == Id::result) p = "result";
|
||||
else if (this == Id::returnLabel) p = "return";
|
||||
else
|
||||
{ p = toChars();
|
||||
if (*p == '_')
|
||||
{
|
||||
if (memcmp(p, "_staticCtor", 11) == 0)
|
||||
p = "static this";
|
||||
else if (memcmp(p, "_staticDtor", 11) == 0)
|
||||
p = "static ~this";
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void Identifier::print()
|
||||
{
|
||||
fprintf(stdmsg, "%s",string);
|
||||
}
|
||||
|
||||
int Identifier::dyncast()
|
||||
{
|
||||
return DYNCAST_IDENTIFIER;
|
||||
}
|
||||
|
||||
// BUG: these are redundant with Lexer::uniqueId()
|
||||
|
||||
Identifier *Identifier::generateId(const char *prefix)
|
||||
{
|
||||
static size_t i;
|
||||
|
||||
return generateId(prefix, ++i);
|
||||
}
|
||||
|
||||
Identifier *Identifier::generateId(const char *prefix, size_t i)
|
||||
{ OutBuffer buf;
|
||||
|
||||
buf.writestring(prefix);
|
||||
buf.printf("%zu", i);
|
||||
|
||||
char *id = buf.toChars();
|
||||
buf.data = NULL;
|
||||
return Lexer::idPool(id);
|
||||
}
|
||||
47
dmd2/identifier.h
Normal file
47
dmd2/identifier.h
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2006 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_IDENTIFIER_H
|
||||
#define DMD_IDENTIFIER_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
#include "root.h"
|
||||
|
||||
#if IN_LLVM
|
||||
namespace llvm
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Identifier : Object
|
||||
{
|
||||
int value;
|
||||
const char *string;
|
||||
unsigned len;
|
||||
|
||||
Identifier(const char *string, int value);
|
||||
int equals(Object *o);
|
||||
hash_t hashCode();
|
||||
int compare(Object *o);
|
||||
void print();
|
||||
char *toChars();
|
||||
char *toHChars();
|
||||
const char *toHChars2();
|
||||
int dyncast();
|
||||
|
||||
static Identifier *generateId(const char *prefix);
|
||||
static Identifier *generateId(const char *prefix, size_t i);
|
||||
};
|
||||
|
||||
#endif /* DMD_IDENTIFIER_H */
|
||||
435
dmd2/idgen.c
Normal file
435
dmd2/idgen.c
Normal file
@@ -0,0 +1,435 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// http://www.dsource.org/projects/dmd/browser/trunk/src/idgen.c
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
// Program to generate string files in d data structures.
|
||||
// Saves much tedious typing, and eliminates typo problems.
|
||||
// Generates:
|
||||
// id.h
|
||||
// id.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct Msgtable
|
||||
{
|
||||
const char *ident; // name to use in DMD source
|
||||
const char *name; // name in D executable
|
||||
};
|
||||
|
||||
Msgtable msgtable[] =
|
||||
{
|
||||
{ "IUnknown" },
|
||||
{ "Object" },
|
||||
{ "object" },
|
||||
{ "max" },
|
||||
{ "min" },
|
||||
{ "This", "this" },
|
||||
{ "super" },
|
||||
{ "ctor", "__ctor" },
|
||||
{ "dtor", "__dtor" },
|
||||
{ "cpctor", "__cpctor" },
|
||||
{ "_postblit", "__postblit" },
|
||||
{ "classInvariant", "__invariant" },
|
||||
{ "unitTest", "__unitTest" },
|
||||
{ "require", "__require" },
|
||||
{ "ensure", "__ensure" },
|
||||
{ "init" },
|
||||
{ "size" },
|
||||
{ "__sizeof", "sizeof" },
|
||||
{ "__xalignof", "alignof" },
|
||||
{ "mangleof" },
|
||||
{ "stringof" },
|
||||
{ "tupleof" },
|
||||
{ "length" },
|
||||
{ "remove" },
|
||||
{ "ptr" },
|
||||
{ "array" },
|
||||
{ "funcptr" },
|
||||
{ "dollar", "__dollar" },
|
||||
{ "ctfe", "__ctfe" },
|
||||
{ "offset" },
|
||||
{ "offsetof" },
|
||||
{ "ModuleInfo" },
|
||||
{ "ClassInfo" },
|
||||
{ "classinfo" },
|
||||
{ "typeinfo" },
|
||||
{ "outer" },
|
||||
{ "Exception" },
|
||||
{ "AssociativeArray" },
|
||||
{ "Throwable" },
|
||||
{ "Error" },
|
||||
{ "withSym", "__withSym" },
|
||||
{ "result", "__result" },
|
||||
{ "returnLabel", "__returnLabel" },
|
||||
{ "delegate" },
|
||||
{ "line" },
|
||||
{ "empty", "" },
|
||||
{ "p" },
|
||||
{ "q" },
|
||||
{ "coverage", "__coverage" },
|
||||
{ "__vptr" },
|
||||
{ "__monitor" },
|
||||
|
||||
{ "TypeInfo" },
|
||||
{ "TypeInfo_Class" },
|
||||
{ "TypeInfo_Interface" },
|
||||
{ "TypeInfo_Struct" },
|
||||
{ "TypeInfo_Enum" },
|
||||
{ "TypeInfo_Typedef" },
|
||||
{ "TypeInfo_Pointer" },
|
||||
{ "TypeInfo_Vector" },
|
||||
{ "TypeInfo_Array" },
|
||||
{ "TypeInfo_StaticArray" },
|
||||
{ "TypeInfo_AssociativeArray" },
|
||||
{ "TypeInfo_Function" },
|
||||
{ "TypeInfo_Delegate" },
|
||||
{ "TypeInfo_Tuple" },
|
||||
{ "TypeInfo_Const" },
|
||||
{ "TypeInfo_Invariant" },
|
||||
{ "TypeInfo_Shared" },
|
||||
{ "TypeInfo_Wild", "TypeInfo_Inout" },
|
||||
{ "elements" },
|
||||
{ "_arguments_typeinfo" },
|
||||
{ "_arguments" },
|
||||
{ "_argptr" },
|
||||
{ "_match" },
|
||||
{ "destroy" },
|
||||
{ "postblit" },
|
||||
|
||||
{ "LINE", "__LINE__" },
|
||||
{ "FILE", "__FILE__" },
|
||||
{ "DATE", "__DATE__" },
|
||||
{ "TIME", "__TIME__" },
|
||||
{ "TIMESTAMP", "__TIMESTAMP__" },
|
||||
{ "VENDOR", "__VENDOR__" },
|
||||
{ "VERSIONX", "__VERSION__" },
|
||||
{ "EOFX", "__EOF__" },
|
||||
|
||||
{ "nan" },
|
||||
{ "infinity" },
|
||||
{ "dig" },
|
||||
{ "epsilon" },
|
||||
{ "mant_dig" },
|
||||
{ "max_10_exp" },
|
||||
{ "max_exp" },
|
||||
{ "min_10_exp" },
|
||||
{ "min_exp" },
|
||||
{ "min_normal" },
|
||||
{ "re" },
|
||||
{ "im" },
|
||||
|
||||
{ "C" },
|
||||
{ "D" },
|
||||
{ "Windows" },
|
||||
{ "Pascal" },
|
||||
{ "System" },
|
||||
|
||||
{ "exit" },
|
||||
{ "success" },
|
||||
{ "failure" },
|
||||
|
||||
{ "keys" },
|
||||
{ "values" },
|
||||
{ "rehash" },
|
||||
|
||||
{ "sort" },
|
||||
{ "reverse" },
|
||||
{ "dup" },
|
||||
{ "idup" },
|
||||
|
||||
{ "property" },
|
||||
{ "safe" },
|
||||
{ "trusted" },
|
||||
{ "system" },
|
||||
{ "disable" },
|
||||
|
||||
// For inline assembler
|
||||
{ "___out", "out" },
|
||||
{ "___in", "in" },
|
||||
{ "__int", "int" },
|
||||
{ "__dollar", "$" },
|
||||
{ "__LOCAL_SIZE" },
|
||||
|
||||
// For operator overloads
|
||||
{ "uadd", "opPos" },
|
||||
{ "neg", "opNeg" },
|
||||
{ "com", "opCom" },
|
||||
{ "add", "opAdd" },
|
||||
{ "add_r", "opAdd_r" },
|
||||
{ "sub", "opSub" },
|
||||
{ "sub_r", "opSub_r" },
|
||||
{ "mul", "opMul" },
|
||||
{ "mul_r", "opMul_r" },
|
||||
{ "div", "opDiv" },
|
||||
{ "div_r", "opDiv_r" },
|
||||
{ "mod", "opMod" },
|
||||
{ "mod_r", "opMod_r" },
|
||||
{ "eq", "opEquals" },
|
||||
{ "cmp", "opCmp" },
|
||||
{ "iand", "opAnd" },
|
||||
{ "iand_r", "opAnd_r" },
|
||||
{ "ior", "opOr" },
|
||||
{ "ior_r", "opOr_r" },
|
||||
{ "ixor", "opXor" },
|
||||
{ "ixor_r", "opXor_r" },
|
||||
{ "shl", "opShl" },
|
||||
{ "shl_r", "opShl_r" },
|
||||
{ "shr", "opShr" },
|
||||
{ "shr_r", "opShr_r" },
|
||||
{ "ushr", "opUShr" },
|
||||
{ "ushr_r", "opUShr_r" },
|
||||
{ "cat", "opCat" },
|
||||
{ "cat_r", "opCat_r" },
|
||||
{ "assign", "opAssign" },
|
||||
{ "addass", "opAddAssign" },
|
||||
{ "subass", "opSubAssign" },
|
||||
{ "mulass", "opMulAssign" },
|
||||
{ "divass", "opDivAssign" },
|
||||
{ "modass", "opModAssign" },
|
||||
{ "andass", "opAndAssign" },
|
||||
{ "orass", "opOrAssign" },
|
||||
{ "xorass", "opXorAssign" },
|
||||
{ "shlass", "opShlAssign" },
|
||||
{ "shrass", "opShrAssign" },
|
||||
{ "ushrass", "opUShrAssign" },
|
||||
{ "catass", "opCatAssign" },
|
||||
{ "postinc", "opPostInc" },
|
||||
{ "postdec", "opPostDec" },
|
||||
{ "index", "opIndex" },
|
||||
{ "indexass", "opIndexAssign" },
|
||||
{ "slice", "opSlice" },
|
||||
{ "sliceass", "opSliceAssign" },
|
||||
{ "call", "opCall" },
|
||||
{ "cast", "opCast" },
|
||||
{ "match", "opMatch" },
|
||||
{ "next", "opNext" },
|
||||
{ "opIn" },
|
||||
{ "opIn_r" },
|
||||
{ "opStar" },
|
||||
{ "opDot" },
|
||||
{ "opDispatch" },
|
||||
{ "opDollar" },
|
||||
{ "opUnary" },
|
||||
{ "opIndexUnary" },
|
||||
{ "opSliceUnary" },
|
||||
{ "opBinary" },
|
||||
{ "opBinaryRight" },
|
||||
{ "opOpAssign" },
|
||||
{ "opIndexOpAssign" },
|
||||
{ "opSliceOpAssign" },
|
||||
{ "pow", "opPow" },
|
||||
{ "pow_r", "opPow_r" },
|
||||
{ "powass", "opPowAssign" },
|
||||
|
||||
{ "classNew", "new" },
|
||||
{ "classDelete", "delete" },
|
||||
|
||||
// For foreach
|
||||
{ "apply", "opApply" },
|
||||
{ "applyReverse", "opApplyReverse" },
|
||||
|
||||
// Ranges
|
||||
{ "Fempty", "empty" },
|
||||
{ "Ffront", "front" },
|
||||
{ "Fback", "back" },
|
||||
{ "FpopFront", "popFront" },
|
||||
{ "FpopBack", "popBack" },
|
||||
|
||||
{ "adDup", "_adDupT" },
|
||||
{ "adReverse", "_adReverse" },
|
||||
|
||||
// For internal functions
|
||||
{ "aaLen", "_aaLen" },
|
||||
{ "aaKeys", "_aaKeys" },
|
||||
{ "aaValues", "_aaValues" },
|
||||
{ "aaRehash", "_aaRehash" },
|
||||
{ "monitorenter", "_d_monitorenter" },
|
||||
{ "monitorexit", "_d_monitorexit" },
|
||||
{ "criticalenter", "_d_criticalenter" },
|
||||
{ "criticalexit", "_d_criticalexit" },
|
||||
{ "_ArrayEq" },
|
||||
|
||||
// For pragma's
|
||||
{ "GNU_asm" },
|
||||
{ "lib" },
|
||||
{ "msg" },
|
||||
{ "startaddress" },
|
||||
|
||||
#if IN_LLVM
|
||||
// LDC pragma's
|
||||
{ "intrinsic" },
|
||||
{ "va_intrinsic" },
|
||||
{ "no_typeinfo" },
|
||||
{ "no_moduleinfo" },
|
||||
{ "Alloca", "alloca" },
|
||||
{ "vastart", "va_start" },
|
||||
{ "vacopy", "va_copy" },
|
||||
{ "vaend", "va_end" },
|
||||
{ "vaarg", "va_arg" },
|
||||
{ "ldc" },
|
||||
{ "allow_inline" },
|
||||
{ "llvm_inline_asm" },
|
||||
{ "fence" },
|
||||
{ "atomic_load" },
|
||||
{ "atomic_store" },
|
||||
{ "atomic_cmp_xchg" },
|
||||
{ "atomic_rmw" },
|
||||
#endif
|
||||
|
||||
// For special functions
|
||||
{ "tohash", "toHash" },
|
||||
{ "tostring", "toString" },
|
||||
{ "getmembers", "getMembers" },
|
||||
|
||||
// Special functions
|
||||
#if IN_DMD
|
||||
{ "alloca" },
|
||||
#endif
|
||||
{ "main" },
|
||||
{ "WinMain" },
|
||||
{ "DllMain" },
|
||||
{ "tls_get_addr", "___tls_get_addr" },
|
||||
|
||||
// varargs implementation
|
||||
{ "va_argsave_t", "__va_argsave_t" },
|
||||
{ "va_argsave", "__va_argsave" },
|
||||
|
||||
// Builtin functions
|
||||
{ "std" },
|
||||
{ "core" },
|
||||
{ "math" },
|
||||
{ "sin" },
|
||||
{ "cos" },
|
||||
{ "tan" },
|
||||
{ "_sqrt", "sqrt" },
|
||||
{ "_pow", "pow" },
|
||||
{ "atan2" },
|
||||
{ "rndtol" },
|
||||
{ "expm1" },
|
||||
{ "exp2" },
|
||||
{ "yl2x" },
|
||||
{ "yl2xp1" },
|
||||
{ "fabs" },
|
||||
{ "bitop" },
|
||||
{ "bsf" },
|
||||
{ "bsr" },
|
||||
{ "bswap" },
|
||||
|
||||
// Traits
|
||||
{ "isAbstractClass" },
|
||||
{ "isArithmetic" },
|
||||
{ "isAssociativeArray" },
|
||||
{ "isFinalClass" },
|
||||
{ "isFloating" },
|
||||
{ "isIntegral" },
|
||||
{ "isScalar" },
|
||||
{ "isStaticArray" },
|
||||
{ "isUnsigned" },
|
||||
{ "isVirtualFunction" },
|
||||
{ "isVirtualMethod" },
|
||||
{ "isAbstractFunction" },
|
||||
{ "isFinalFunction" },
|
||||
{ "isStaticFunction" },
|
||||
{ "isRef" },
|
||||
{ "isOut" },
|
||||
{ "isLazy" },
|
||||
{ "hasMember" },
|
||||
{ "identifier" },
|
||||
{ "parent" },
|
||||
{ "getMember" },
|
||||
{ "getOverloads" },
|
||||
{ "getVirtualFunctions" },
|
||||
{ "getVirtualMethods" },
|
||||
{ "classInstanceSize" },
|
||||
{ "allMembers" },
|
||||
{ "derivedMembers" },
|
||||
{ "isSame" },
|
||||
{ "compiles" },
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
FILE *fp;
|
||||
unsigned i;
|
||||
|
||||
{
|
||||
fp = fopen("id.h","w");
|
||||
if (!fp)
|
||||
{ printf("can't open id.h\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fprintf(fp, "// File generated by idgen.c\n");
|
||||
#if __DMC__
|
||||
fprintf(fp, "#pragma once\n");
|
||||
#endif
|
||||
fprintf(fp, "#ifndef DMD_ID_H\n");
|
||||
fprintf(fp, "#define DMD_ID_H 1\n");
|
||||
fprintf(fp, "struct Identifier;\n");
|
||||
fprintf(fp, "struct Id\n");
|
||||
fprintf(fp, "{\n");
|
||||
|
||||
for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
|
||||
{ const char *id = msgtable[i].ident;
|
||||
|
||||
fprintf(fp," static Identifier *%s;\n", id);
|
||||
}
|
||||
|
||||
fprintf(fp, " static void initialize();\n");
|
||||
fprintf(fp, "};\n");
|
||||
fprintf(fp, "#endif\n");
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
{
|
||||
fp = fopen("id.c","w");
|
||||
if (!fp)
|
||||
{ printf("can't open id.c\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fprintf(fp, "// File generated by idgen.c\n");
|
||||
fprintf(fp, "#include \"id.h\"\n");
|
||||
fprintf(fp, "#include \"identifier.h\"\n");
|
||||
fprintf(fp, "#include \"lexer.h\"\n");
|
||||
|
||||
for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
|
||||
{ const char *id = msgtable[i].ident;
|
||||
const char *p = msgtable[i].name;
|
||||
|
||||
if (!p)
|
||||
p = id;
|
||||
fprintf(fp,"Identifier *Id::%s;\n", id);
|
||||
}
|
||||
|
||||
fprintf(fp, "void Id::initialize()\n");
|
||||
fprintf(fp, "{\n");
|
||||
|
||||
for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
|
||||
{ const char *id = msgtable[i].ident;
|
||||
const char *p = msgtable[i].name;
|
||||
|
||||
if (!p)
|
||||
p = id;
|
||||
fprintf(fp," %s = Lexer::idPool(\"%s\");\n", id, p);
|
||||
}
|
||||
|
||||
fprintf(fp, "}\n");
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
427
dmd2/impcnvgen.c
Normal file
427
dmd2/impcnvgen.c
Normal file
@@ -0,0 +1,427 @@
|
||||
|
||||
// Copyright (c) 1999-2006 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mtype.h"
|
||||
|
||||
TY impcnvResult[TMAX][TMAX];
|
||||
TY impcnvType1[TMAX][TMAX];
|
||||
TY impcnvType2[TMAX][TMAX];
|
||||
int impcnvWarn[TMAX][TMAX];
|
||||
|
||||
int integral_promotion(int t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case Tchar:
|
||||
case Twchar:
|
||||
case Tbool:
|
||||
case Tint8:
|
||||
case Tuns8:
|
||||
case Tint16:
|
||||
case Tuns16: return Tint32;
|
||||
case Tdchar: return Tuns32;
|
||||
default: return t;
|
||||
}
|
||||
}
|
||||
|
||||
void init()
|
||||
{ int i, j;
|
||||
|
||||
// Set conversion tables
|
||||
for (i = 0; i < TMAX; i++)
|
||||
for (j = 0; j < TMAX; j++)
|
||||
{ impcnvResult[i][j] = Terror;
|
||||
impcnvType1[i][j] = Terror;
|
||||
impcnvType2[i][j] = Terror;
|
||||
impcnvWarn[i][j] = 0;
|
||||
}
|
||||
|
||||
#define X(t1,t2, nt1,nt2, rt) \
|
||||
impcnvResult[t1][t2] = rt; \
|
||||
impcnvType1[t1][t2] = nt1; \
|
||||
impcnvType2[t1][t2] = nt2;
|
||||
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tbool,Tbool, Tbool,Tbool, Tbool)
|
||||
X(Tbool,Tint8, Tint32,Tint32, Tint32)
|
||||
X(Tbool,Tuns8, Tint32,Tint32, Tint32)
|
||||
X(Tbool,Tint16, Tint32,Tint32, Tint32)
|
||||
X(Tbool,Tuns16, Tint32,Tint32, Tint32)
|
||||
X(Tbool,Tint32, Tint32,Tint32, Tint32)
|
||||
X(Tbool,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||
X(Tbool,Tint64, Tint64,Tint64, Tint64)
|
||||
X(Tbool,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||
|
||||
X(Tbool,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||
X(Tbool,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||
X(Tbool,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||
X(Tbool,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||
X(Tbool,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||
X(Tbool,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||
X(Tbool,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||
X(Tbool,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||
X(Tbool,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tint8,Tint8, Tint32,Tint32, Tint32)
|
||||
X(Tint8,Tuns8, Tint32,Tint32, Tint32)
|
||||
X(Tint8,Tint16, Tint32,Tint32, Tint32)
|
||||
X(Tint8,Tuns16, Tint32,Tint32, Tint32)
|
||||
X(Tint8,Tint32, Tint32,Tint32, Tint32)
|
||||
X(Tint8,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||
X(Tint8,Tint64, Tint64,Tint64, Tint64)
|
||||
X(Tint8,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||
|
||||
X(Tint8,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||
X(Tint8,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||
X(Tint8,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||
X(Tint8,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||
X(Tint8,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||
X(Tint8,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||
X(Tint8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||
X(Tint8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||
X(Tint8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tuns8,Tuns8, Tint32,Tint32, Tint32)
|
||||
X(Tuns8,Tint16, Tint32,Tint32, Tint32)
|
||||
X(Tuns8,Tuns16, Tint32,Tint32, Tint32)
|
||||
X(Tuns8,Tint32, Tint32,Tint32, Tint32)
|
||||
X(Tuns8,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||
X(Tuns8,Tint64, Tint64,Tint64, Tint64)
|
||||
X(Tuns8,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||
|
||||
X(Tuns8,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||
X(Tuns8,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||
X(Tuns8,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||
X(Tuns8,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||
X(Tuns8,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||
X(Tuns8,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||
X(Tuns8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||
X(Tuns8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||
X(Tuns8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tint16,Tint16, Tint32,Tint32, Tint32)
|
||||
X(Tint16,Tuns16, Tint32,Tint32, Tint32)
|
||||
X(Tint16,Tint32, Tint32,Tint32, Tint32)
|
||||
X(Tint16,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||
X(Tint16,Tint64, Tint64,Tint64, Tint64)
|
||||
X(Tint16,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||
|
||||
X(Tint16,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||
X(Tint16,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||
X(Tint16,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||
X(Tint16,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||
X(Tint16,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||
X(Tint16,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||
X(Tint16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||
X(Tint16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||
X(Tint16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tuns16,Tuns16, Tint32,Tint32, Tint32)
|
||||
X(Tuns16,Tint32, Tint32,Tint32, Tint32)
|
||||
X(Tuns16,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||
X(Tuns16,Tint64, Tint64,Tint64, Tint64)
|
||||
X(Tuns16,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||
|
||||
X(Tuns16,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||
X(Tuns16,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||
X(Tuns16,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||
X(Tuns16,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||
X(Tuns16,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||
X(Tuns16,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||
X(Tuns16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||
X(Tuns16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||
X(Tuns16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tint32,Tint32, Tint32,Tint32, Tint32)
|
||||
X(Tint32,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||
X(Tint32,Tint64, Tint64,Tint64, Tint64)
|
||||
X(Tint32,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||
|
||||
X(Tint32,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||
X(Tint32,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||
X(Tint32,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||
X(Tint32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||
X(Tint32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||
X(Tint32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||
X(Tint32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||
X(Tint32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||
X(Tint32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tuns32,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||
X(Tuns32,Tint64, Tint64,Tint64, Tint64)
|
||||
X(Tuns32,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||
|
||||
X(Tuns32,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||
X(Tuns32,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||
X(Tuns32,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||
X(Tuns32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||
X(Tuns32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||
X(Tuns32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||
X(Tuns32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||
X(Tuns32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||
X(Tuns32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tint64,Tint64, Tint64,Tint64, Tint64)
|
||||
X(Tint64,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||
|
||||
X(Tint64,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||
X(Tint64,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||
X(Tint64,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||
X(Tint64,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||
X(Tint64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||
X(Tint64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||
X(Tint64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||
X(Tint64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||
X(Tint64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tuns64,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||
|
||||
X(Tuns64,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||
X(Tuns64,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||
X(Tuns64,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||
X(Tuns64,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||
X(Tuns64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||
X(Tuns64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||
X(Tuns64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||
X(Tuns64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||
X(Tuns64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tfloat32,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||
X(Tfloat32,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||
X(Tfloat32,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||
|
||||
X(Tfloat32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||
X(Tfloat32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||
X(Tfloat32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||
|
||||
X(Tfloat32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||
X(Tfloat32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||
X(Tfloat32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tfloat64,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||
X(Tfloat64,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||
|
||||
X(Tfloat64,Timaginary32, Tfloat64,Timaginary64, Tfloat64)
|
||||
X(Tfloat64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||
X(Tfloat64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||
|
||||
X(Tfloat64,Tcomplex32, Tfloat64,Tcomplex64, Tcomplex64)
|
||||
X(Tfloat64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||
X(Tfloat64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tfloat80,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||
|
||||
X(Tfloat80,Timaginary32, Tfloat80,Timaginary80, Tfloat80)
|
||||
X(Tfloat80,Timaginary64, Tfloat80,Timaginary80, Tfloat80)
|
||||
X(Tfloat80,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||
|
||||
X(Tfloat80,Tcomplex32, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
X(Tfloat80,Tcomplex64, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
X(Tfloat80,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Timaginary32,Timaginary32, Timaginary32,Timaginary32, Timaginary32)
|
||||
X(Timaginary32,Timaginary64, Timaginary64,Timaginary64, Timaginary64)
|
||||
X(Timaginary32,Timaginary80, Timaginary80,Timaginary80, Timaginary80)
|
||||
|
||||
X(Timaginary32,Tcomplex32, Timaginary32,Tcomplex32, Tcomplex32)
|
||||
X(Timaginary32,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64)
|
||||
X(Timaginary32,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Timaginary64,Timaginary64, Timaginary64,Timaginary64, Timaginary64)
|
||||
X(Timaginary64,Timaginary80, Timaginary80,Timaginary80, Timaginary80)
|
||||
|
||||
X(Timaginary64,Tcomplex32, Timaginary64,Tcomplex64, Tcomplex64)
|
||||
X(Timaginary64,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64)
|
||||
X(Timaginary64,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Timaginary80,Timaginary80, Timaginary80,Timaginary80, Timaginary80)
|
||||
|
||||
X(Timaginary80,Tcomplex32, Timaginary80,Tcomplex80, Tcomplex80)
|
||||
X(Timaginary80,Tcomplex64, Timaginary80,Tcomplex80, Tcomplex80)
|
||||
X(Timaginary80,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tcomplex32,Tcomplex32, Tcomplex32,Tcomplex32, Tcomplex32)
|
||||
X(Tcomplex32,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64)
|
||||
X(Tcomplex32,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tcomplex64,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64)
|
||||
X(Tcomplex64,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80)
|
||||
|
||||
/* ======================= */
|
||||
|
||||
X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80)
|
||||
|
||||
#undef X
|
||||
|
||||
#define Y(t1,t2) impcnvWarn[t1][t2] = 1;
|
||||
|
||||
Y(Tuns8, Tint8)
|
||||
Y(Tint16, Tint8)
|
||||
Y(Tuns16, Tint8)
|
||||
Y(Tint32, Tint8)
|
||||
Y(Tuns32, Tint8)
|
||||
Y(Tint64, Tint8)
|
||||
Y(Tuns64, Tint8)
|
||||
|
||||
Y(Tint8, Tuns8)
|
||||
Y(Tint16, Tuns8)
|
||||
Y(Tuns16, Tuns8)
|
||||
Y(Tint32, Tuns8)
|
||||
Y(Tuns32, Tuns8)
|
||||
Y(Tint64, Tuns8)
|
||||
Y(Tuns64, Tuns8)
|
||||
|
||||
Y(Tint8, Tchar)
|
||||
Y(Tint16, Tchar)
|
||||
Y(Tuns16, Tchar)
|
||||
Y(Tint32, Tchar)
|
||||
Y(Tuns32, Tchar)
|
||||
Y(Tint64, Tchar)
|
||||
Y(Tuns64, Tchar)
|
||||
|
||||
Y(Tuns16, Tint16)
|
||||
Y(Tint32, Tint16)
|
||||
Y(Tuns32, Tint16)
|
||||
Y(Tint64, Tint16)
|
||||
Y(Tuns64, Tint16)
|
||||
|
||||
Y(Tint16, Tuns16)
|
||||
Y(Tint32, Tuns16)
|
||||
Y(Tuns32, Tuns16)
|
||||
Y(Tint64, Tuns16)
|
||||
Y(Tuns64, Tuns16)
|
||||
|
||||
Y(Tint16, Twchar)
|
||||
Y(Tint32, Twchar)
|
||||
Y(Tuns32, Twchar)
|
||||
Y(Tint64, Twchar)
|
||||
Y(Tuns64, Twchar)
|
||||
|
||||
// Y(Tuns32, Tint32)
|
||||
Y(Tint64, Tint32)
|
||||
Y(Tuns64, Tint32)
|
||||
|
||||
// Y(Tint32, Tuns32)
|
||||
Y(Tint64, Tuns32)
|
||||
Y(Tuns64, Tuns32)
|
||||
|
||||
Y(Tint64, Tdchar)
|
||||
Y(Tuns64, Tdchar)
|
||||
|
||||
// Y(Tint64, Tuns64)
|
||||
// Y(Tuns64, Tint64)
|
||||
|
||||
for (i = 0; i < TMAX; i++)
|
||||
for (j = 0; j < TMAX; j++)
|
||||
{
|
||||
if (impcnvResult[i][j] == Terror)
|
||||
{
|
||||
impcnvResult[i][j] = impcnvResult[j][i];
|
||||
impcnvType1[i][j] = impcnvType2[j][i];
|
||||
impcnvType2[i][j] = impcnvType1[j][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{ FILE *fp;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
init();
|
||||
|
||||
fp = fopen("impcnvtab.c","w");
|
||||
|
||||
fprintf(fp,"// This file is generated by impcnvgen.c\n");
|
||||
fprintf(fp,"#include \"mtype.h\"\n");
|
||||
|
||||
fprintf(fp,"unsigned char Type::impcnvResult[TMAX][TMAX] =\n{\n");
|
||||
for (i = 0; i < TMAX; i++)
|
||||
{
|
||||
for (j = 0; j < TMAX; j++)
|
||||
{
|
||||
fprintf(fp, "%d,",impcnvResult[i][j]);
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
fprintf(fp,"};\n");
|
||||
|
||||
fprintf(fp,"unsigned char Type::impcnvType1[TMAX][TMAX] =\n{\n");
|
||||
for (i = 0; i < TMAX; i++)
|
||||
{
|
||||
for (j = 0; j < TMAX; j++)
|
||||
{
|
||||
fprintf(fp, "%d,",impcnvType1[i][j]);
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
fprintf(fp,"};\n");
|
||||
|
||||
fprintf(fp,"unsigned char Type::impcnvType2[TMAX][TMAX] =\n{\n");
|
||||
for (i = 0; i < TMAX; i++)
|
||||
{
|
||||
for (j = 0; j < TMAX; j++)
|
||||
{
|
||||
fprintf(fp, "%d,",impcnvType2[i][j]);
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
fprintf(fp,"};\n");
|
||||
|
||||
fprintf(fp,"unsigned char Type::impcnvWarn[TMAX][TMAX] =\n{\n");
|
||||
for (i = 0; i < TMAX; i++)
|
||||
{
|
||||
for (j = 0; j < TMAX; j++)
|
||||
{
|
||||
fprintf(fp, "%d,",impcnvWarn[i][j]);
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
fprintf(fp,"};\n");
|
||||
|
||||
fclose(fp);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
88
dmd2/imphint.c
Normal file
88
dmd2/imphint.c
Normal file
@@ -0,0 +1,88 @@
|
||||
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 2010 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mars.h"
|
||||
|
||||
/******************************************
|
||||
* Looks for undefined identifier s to see
|
||||
* if it might be undefined because an import
|
||||
* was not specified.
|
||||
* Not meant to be a comprehensive list of names in each module,
|
||||
* just the most common ones.
|
||||
*/
|
||||
|
||||
const char *importHint(const char *s)
|
||||
{
|
||||
#if DMDV1
|
||||
static const char *modules[] =
|
||||
{ "std.c.stdio",
|
||||
"std.stdio",
|
||||
"std.math",
|
||||
"std.c.stdarg",
|
||||
};
|
||||
static const char *names[] =
|
||||
{
|
||||
"printf", NULL,
|
||||
"writefln", NULL,
|
||||
"sin", "cos", "sqrt", "fabs", NULL,
|
||||
"__va_argsave_t", NULL,
|
||||
};
|
||||
#else
|
||||
static const char *modules[] =
|
||||
{ "core.stdc.stdio",
|
||||
"std.stdio",
|
||||
"std.math",
|
||||
"core.vararg",
|
||||
};
|
||||
static const char *names[] =
|
||||
{
|
||||
"printf", NULL,
|
||||
"writeln", NULL,
|
||||
"sin", "cos", "sqrt", "fabs", NULL,
|
||||
"__va_argsave_t", NULL,
|
||||
};
|
||||
#endif
|
||||
int m = 0;
|
||||
for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++)
|
||||
{
|
||||
const char *p = names[n];
|
||||
if (p == NULL)
|
||||
{ m++;
|
||||
continue;
|
||||
}
|
||||
assert(m < sizeof(modules)/sizeof(modules[0]));
|
||||
if (strcmp(s, p) == 0)
|
||||
return modules[m];
|
||||
}
|
||||
return NULL; // didn't find it
|
||||
}
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
void unittest_importHint()
|
||||
{
|
||||
const char *p;
|
||||
|
||||
p = importHint("printf");
|
||||
assert(p);
|
||||
p = importHint("fabs");
|
||||
assert(p);
|
||||
p = importHint("xxxxx");
|
||||
assert(!p);
|
||||
}
|
||||
|
||||
#endif
|
||||
397
dmd2/import.c
Normal file
397
dmd2/import.c
Normal file
@@ -0,0 +1,397 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2009 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "root.h"
|
||||
#include "dsymbol.h"
|
||||
#include "import.h"
|
||||
#include "identifier.h"
|
||||
#include "module.h"
|
||||
#include "scope.h"
|
||||
#include "hdrgen.h"
|
||||
#include "mtype.h"
|
||||
#include "declaration.h"
|
||||
#include "id.h"
|
||||
#include "attrib.h"
|
||||
|
||||
/********************************* Import ****************************/
|
||||
|
||||
Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId,
|
||||
int isstatic)
|
||||
: Dsymbol(NULL)
|
||||
{
|
||||
assert(id);
|
||||
this->loc = loc;
|
||||
this->packages = packages;
|
||||
this->id = id;
|
||||
this->aliasId = aliasId;
|
||||
this->isstatic = isstatic;
|
||||
this->protection = PROTprivate; // default to private
|
||||
this->pkg = NULL;
|
||||
this->mod = NULL;
|
||||
|
||||
// Set symbol name (bracketed)
|
||||
// import [cstdio] = std.stdio;
|
||||
if (aliasId)
|
||||
this->ident = aliasId;
|
||||
// import [std].stdio;
|
||||
else if (packages && packages->dim)
|
||||
this->ident = packages->tdata()[0];
|
||||
// import [foo];
|
||||
else
|
||||
this->ident = id;
|
||||
}
|
||||
|
||||
void Import::addAlias(Identifier *name, Identifier *alias)
|
||||
{
|
||||
if (isstatic)
|
||||
error("cannot have an import bind list");
|
||||
|
||||
if (!aliasId)
|
||||
this->ident = NULL; // make it an anonymous import
|
||||
|
||||
names.push(name);
|
||||
aliases.push(alias);
|
||||
}
|
||||
|
||||
const char *Import::kind()
|
||||
{
|
||||
return isstatic ? (char *)"static import" : (char *)"import";
|
||||
}
|
||||
|
||||
enum PROT Import::prot()
|
||||
{
|
||||
return protection;
|
||||
}
|
||||
|
||||
Dsymbol *Import::syntaxCopy(Dsymbol *s)
|
||||
{
|
||||
assert(!s);
|
||||
|
||||
Import *si;
|
||||
|
||||
si = new Import(loc, packages, id, aliasId, isstatic);
|
||||
|
||||
for (size_t i = 0; i < names.dim; i++)
|
||||
{
|
||||
si->addAlias(names.tdata()[i], aliases.tdata()[i]);
|
||||
}
|
||||
|
||||
return si;
|
||||
}
|
||||
|
||||
void Import::load(Scope *sc)
|
||||
{
|
||||
//printf("Import::load('%s')\n", toChars());
|
||||
|
||||
// See if existing module
|
||||
DsymbolTable *dst = Package::resolve(packages, NULL, &pkg);
|
||||
|
||||
Dsymbol *s = dst->lookup(id);
|
||||
if (s)
|
||||
{
|
||||
#if TARGET_NET
|
||||
mod = (Module *)s;
|
||||
#else
|
||||
if (s->isModule())
|
||||
mod = (Module *)s;
|
||||
else
|
||||
error("package and module have the same name");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!mod)
|
||||
{
|
||||
// Load module
|
||||
mod = Module::load(loc, packages, id);
|
||||
dst->insert(id, mod); // id may be different from mod->ident,
|
||||
// if so then insert alias
|
||||
if (!mod->importedFrom)
|
||||
mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule;
|
||||
}
|
||||
if (!pkg)
|
||||
pkg = mod;
|
||||
|
||||
//printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
|
||||
}
|
||||
|
||||
void escapePath(OutBuffer *buf, const char *fname)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
switch (*fname)
|
||||
{
|
||||
case 0:
|
||||
return;
|
||||
case '(':
|
||||
case ')':
|
||||
case '\\':
|
||||
buf->writebyte('\\');
|
||||
default:
|
||||
buf->writebyte(*fname);
|
||||
break;
|
||||
}
|
||||
fname++;
|
||||
}
|
||||
}
|
||||
|
||||
void Import::importAll(Scope *sc)
|
||||
{
|
||||
if (!mod)
|
||||
{
|
||||
load(sc);
|
||||
mod->importAll(0);
|
||||
|
||||
if (!isstatic && !aliasId && !names.dim)
|
||||
{
|
||||
if (sc->explicitProtection)
|
||||
protection = sc->protection;
|
||||
sc->scopesym->importScope(mod, protection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Import::semantic(Scope *sc)
|
||||
{
|
||||
//printf("Import::semantic('%s')\n", toChars());
|
||||
|
||||
// Load if not already done so
|
||||
if (!mod)
|
||||
{ load(sc);
|
||||
mod->importAll(0);
|
||||
}
|
||||
|
||||
if (mod)
|
||||
{
|
||||
#if 0
|
||||
if (mod->loc.linnum != 0)
|
||||
{ /* If the line number is not 0, then this is not
|
||||
* a 'root' module, i.e. it was not specified on the command line.
|
||||
*/
|
||||
mod->importedFrom = sc->module->importedFrom;
|
||||
assert(mod->importedFrom);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Modules need a list of each imported module
|
||||
//printf("%s imports %s\n", sc->module->toChars(), mod->toChars());
|
||||
sc->module->aimports.push(mod);
|
||||
|
||||
if (!isstatic && !aliasId && !names.dim)
|
||||
{
|
||||
if (sc->explicitProtection)
|
||||
protection = sc->protection;
|
||||
for (Scope *scd = sc; scd; scd = scd->enclosing)
|
||||
{
|
||||
if (scd->scopesym)
|
||||
{
|
||||
scd->scopesym->importScope(mod, protection);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod->semantic();
|
||||
|
||||
if (mod->needmoduleinfo)
|
||||
{ //printf("module4 %s because of %s\n", sc->module->toChars(), mod->toChars());
|
||||
sc->module->needmoduleinfo = 1;
|
||||
}
|
||||
|
||||
sc = sc->push(mod);
|
||||
/* BUG: Protection checks can't be enabled yet. The issue is
|
||||
* that Dsymbol::search errors before overload resolution.
|
||||
*/
|
||||
#if 0
|
||||
sc->protection = protection;
|
||||
#else
|
||||
sc->protection = PROTpublic;
|
||||
#endif
|
||||
for (size_t i = 0; i < aliasdecls.dim; i++)
|
||||
{ Dsymbol *s = aliasdecls.tdata()[i];
|
||||
|
||||
//printf("\tImport alias semantic('%s')\n", s->toChars());
|
||||
if (!mod->search(loc, names.tdata()[i], 0))
|
||||
error("%s not found", (names.tdata()[i])->toChars());
|
||||
|
||||
s->semantic(sc);
|
||||
}
|
||||
sc = sc->pop();
|
||||
}
|
||||
|
||||
if (global.params.moduleDeps != NULL)
|
||||
{
|
||||
/* The grammar of the file is:
|
||||
* ImportDeclaration
|
||||
* ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
|
||||
* ModuleAliasIdentifier ] "\n"
|
||||
*
|
||||
* BasicImportDeclaration
|
||||
* ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection
|
||||
* " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
|
||||
*
|
||||
* FilePath
|
||||
* - any string with '(', ')' and '\' escaped with the '\' character
|
||||
*/
|
||||
|
||||
OutBuffer *ob = global.params.moduleDeps;
|
||||
|
||||
ob->writestring(sc->module->toPrettyChars());
|
||||
ob->writestring(" (");
|
||||
escapePath(ob, sc->module->srcfile->toChars());
|
||||
ob->writestring(") : ");
|
||||
|
||||
ProtDeclaration::protectionToCBuffer(ob, sc->protection);
|
||||
if (isstatic)
|
||||
StorageClassDeclaration::stcToCBuffer(ob, STCstatic);
|
||||
ob->writestring(": ");
|
||||
|
||||
if (packages)
|
||||
{
|
||||
for (size_t i = 0; i < packages->dim; i++)
|
||||
{
|
||||
Identifier *pid = packages->tdata()[i];
|
||||
ob->printf("%s.", pid->toChars());
|
||||
}
|
||||
}
|
||||
|
||||
ob->writestring(id->toChars());
|
||||
ob->writestring(" (");
|
||||
if (mod)
|
||||
escapePath(ob, mod->srcfile->toChars());
|
||||
else
|
||||
ob->writestring("???");
|
||||
ob->writebyte(')');
|
||||
|
||||
for (size_t i = 0; i < names.dim; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
ob->writebyte(':');
|
||||
else
|
||||
ob->writebyte(',');
|
||||
|
||||
Identifier *name = names.tdata()[i];
|
||||
Identifier *alias = aliases.tdata()[i];
|
||||
|
||||
if (!alias)
|
||||
{
|
||||
ob->printf("%s", name->toChars());
|
||||
alias = name;
|
||||
}
|
||||
else
|
||||
ob->printf("%s=%s", alias->toChars(), name->toChars());
|
||||
}
|
||||
|
||||
if (aliasId)
|
||||
ob->printf(" -> %s", aliasId->toChars());
|
||||
|
||||
ob->writenl();
|
||||
}
|
||||
|
||||
//printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg);
|
||||
}
|
||||
|
||||
void Import::semantic2(Scope *sc)
|
||||
{
|
||||
//printf("Import::semantic2('%s')\n", toChars());
|
||||
mod->semantic2();
|
||||
if (mod->needmoduleinfo)
|
||||
{ //printf("module5 %s because of %s\n", sc->module->toChars(), mod->toChars());
|
||||
sc->module->needmoduleinfo = 1;
|
||||
}
|
||||
}
|
||||
|
||||
Dsymbol *Import::toAlias()
|
||||
{
|
||||
if (aliasId)
|
||||
return mod;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*****************************
|
||||
* Add import to sd's symbol table.
|
||||
*/
|
||||
|
||||
int Import::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (names.dim == 0)
|
||||
return Dsymbol::addMember(sc, sd, memnum);
|
||||
|
||||
if (aliasId)
|
||||
result = Dsymbol::addMember(sc, sd, memnum);
|
||||
|
||||
/* Instead of adding the import to sd's symbol table,
|
||||
* add each of the alias=name pairs
|
||||
*/
|
||||
for (size_t i = 0; i < names.dim; i++)
|
||||
{
|
||||
Identifier *name = names.tdata()[i];
|
||||
Identifier *alias = aliases.tdata()[i];
|
||||
|
||||
if (!alias)
|
||||
alias = name;
|
||||
|
||||
TypeIdentifier *tname = new TypeIdentifier(loc, name);
|
||||
AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname);
|
||||
result |= ad->addMember(sc, sd, memnum);
|
||||
|
||||
aliasdecls.push(ad);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Dsymbol *Import::search(Loc loc, Identifier *ident, int flags)
|
||||
{
|
||||
//printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
|
||||
|
||||
if (!pkg)
|
||||
{ load(NULL);
|
||||
mod->semantic();
|
||||
}
|
||||
|
||||
// Forward it to the package/module
|
||||
return pkg->search(loc, ident, flags);
|
||||
}
|
||||
|
||||
int Import::overloadInsert(Dsymbol *s)
|
||||
{
|
||||
// Allow multiple imports of the same name
|
||||
return s->isImport() != NULL;
|
||||
}
|
||||
|
||||
void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
if (hgs->hdrgen && id == Id::object)
|
||||
return; // object is imported by default
|
||||
|
||||
if (isstatic)
|
||||
buf->writestring("static ");
|
||||
buf->writestring("import ");
|
||||
if (aliasId)
|
||||
{
|
||||
buf->printf("%s = ", aliasId->toChars());
|
||||
}
|
||||
if (packages && packages->dim)
|
||||
{
|
||||
for (size_t i = 0; i < packages->dim; i++)
|
||||
{ Identifier *pid = packages->tdata()[i];
|
||||
|
||||
buf->printf("%s.", pid->toChars());
|
||||
}
|
||||
}
|
||||
buf->printf("%s;", id->toChars());
|
||||
buf->writenl();
|
||||
}
|
||||
|
||||
66
dmd2/import.h
Normal file
66
dmd2/import.h
Normal file
@@ -0,0 +1,66 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2007 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_IMPORT_H
|
||||
#define DMD_IMPORT_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
#include "dsymbol.h"
|
||||
|
||||
|
||||
struct Identifier;
|
||||
struct Scope;
|
||||
struct OutBuffer;
|
||||
struct Module;
|
||||
struct Package;
|
||||
struct AliasDeclaration;
|
||||
struct HdrGenState;
|
||||
|
||||
struct Import : Dsymbol
|
||||
{
|
||||
Identifiers *packages; // array of Identifier's representing packages
|
||||
Identifier *id; // module Identifier
|
||||
Identifier *aliasId;
|
||||
int isstatic; // !=0 if static import
|
||||
enum PROT protection;
|
||||
|
||||
// Pairs of alias=name to bind into current namespace
|
||||
Identifiers names;
|
||||
Identifiers aliases;
|
||||
|
||||
AliasDeclarations aliasdecls; // AliasDeclarations for names/aliases
|
||||
|
||||
Module *mod;
|
||||
Package *pkg; // leftmost package/module
|
||||
|
||||
Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId,
|
||||
int isstatic);
|
||||
void addAlias(Identifier *name, Identifier *alias);
|
||||
|
||||
const char *kind();
|
||||
enum PROT prot();
|
||||
Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
|
||||
void load(Scope *sc);
|
||||
void importAll(Scope *sc);
|
||||
void semantic(Scope *sc);
|
||||
void semantic2(Scope *sc);
|
||||
Dsymbol *toAlias();
|
||||
int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
|
||||
Dsymbol *search(Loc loc, Identifier *ident, int flags);
|
||||
int overloadInsert(Dsymbol *s);
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
|
||||
Import *isImport() { return this; }
|
||||
};
|
||||
|
||||
#endif /* DMD_IMPORT_H */
|
||||
328
dmd2/inifile.c
Normal file
328
dmd2/inifile.c
Normal file
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Some portions copyright (c) 1994-1995 by Symantec
|
||||
* Copyright (c) 1999-2011 by Digital Mars
|
||||
* All Rights Reserved
|
||||
* http://www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This source file is made available for personal use
|
||||
* only. The license is in /dmd/src/dmd/backendlicense.txt
|
||||
* For any other uses, please contact Digital Mars.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
#include <sys/syslimits.h>
|
||||
#endif
|
||||
#if __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
|
||||
// for PATH_MAX
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#if __sun&&__SVR4
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
#include "root.h"
|
||||
#include "rmem.h"
|
||||
|
||||
#define LOG 0
|
||||
|
||||
char *skipspace(const char *p);
|
||||
|
||||
#if __GNUC__
|
||||
char *strupr(char *s)
|
||||
{
|
||||
char *t = s;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
*s = toupper(*s);
|
||||
s++;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
#endif /* unix */
|
||||
|
||||
/*****************************
|
||||
* Read and analyze .ini file.
|
||||
* Input:
|
||||
* argv0 program name (argv[0])
|
||||
* inifile .ini file name
|
||||
* Returns:
|
||||
* file name of ini file
|
||||
* Note: this is a memory leak
|
||||
*/
|
||||
|
||||
const char *inifile(const char *argv0x, const char *inifilex)
|
||||
{
|
||||
char *argv0 = (char *)argv0x;
|
||||
char *inifile = (char *)inifilex; // do const-correct later
|
||||
char *path; // need path for @P macro
|
||||
char *filename;
|
||||
OutBuffer buf;
|
||||
int envsection = 0;
|
||||
|
||||
#if LOG
|
||||
printf("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile);
|
||||
#endif
|
||||
if (FileName::absolute(inifile))
|
||||
{
|
||||
filename = inifile;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Look for inifile in the following sequence of places:
|
||||
* o current directory
|
||||
* o home directory
|
||||
* o directory off of argv0
|
||||
* o /etc/
|
||||
*/
|
||||
if (FileName::exists(inifile))
|
||||
{
|
||||
filename = inifile;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = FileName::combine(getenv("HOME"), inifile);
|
||||
if (!FileName::exists(filename))
|
||||
{
|
||||
#if _WIN32 // This fix by Tim Matthews
|
||||
char resolved_name[MAX_PATH + 1];
|
||||
if(GetModuleFileName(NULL, resolved_name, MAX_PATH + 1) && FileName::exists(resolved_name))
|
||||
{
|
||||
filename = (char *)FileName::replaceName(resolved_name, inifile);
|
||||
if(FileName::exists(filename))
|
||||
goto Ldone;
|
||||
}
|
||||
#endif
|
||||
filename = (char *)FileName::replaceName(argv0, inifile);
|
||||
if (!FileName::exists(filename))
|
||||
{
|
||||
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
|
||||
#if __GLIBC__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 // This fix by Thomas Kuehne
|
||||
/* argv0 might be a symbolic link,
|
||||
* so try again looking past it to the real path
|
||||
*/
|
||||
#if __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
|
||||
char resolved_name[PATH_MAX + 1];
|
||||
char* real_argv0 = realpath(argv0, resolved_name);
|
||||
#else
|
||||
char* real_argv0 = realpath(argv0, NULL);
|
||||
#endif
|
||||
//printf("argv0 = %s, real_argv0 = %p\n", argv0, real_argv0);
|
||||
if (real_argv0)
|
||||
{
|
||||
filename = (char *)FileName::replaceName(real_argv0, inifile);
|
||||
#if !(__APPLE__ || __FreeBSD__ || __sun&&__SVR4)
|
||||
free(real_argv0);
|
||||
#endif
|
||||
if (FileName::exists(filename))
|
||||
goto Ldone;
|
||||
}
|
||||
#else
|
||||
#error use of glibc non-standard extension realpath(char*, NULL)
|
||||
#endif
|
||||
if (1){
|
||||
// Search PATH for argv0
|
||||
const char *p = getenv("PATH");
|
||||
Strings *paths = FileName::splitPath(p);
|
||||
filename = FileName::searchPath(paths, argv0, 0);
|
||||
if (!filename)
|
||||
goto Letc; // argv0 not found on path
|
||||
filename = (char *)FileName::replaceName(filename, inifile);
|
||||
if (FileName::exists(filename))
|
||||
goto Ldone;
|
||||
}
|
||||
// Search /etc/ for inifile
|
||||
Letc:
|
||||
#endif
|
||||
filename = FileName::combine((char *)"/etc/", inifile);
|
||||
|
||||
Ldone:
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
path = FileName::path(filename);
|
||||
#if LOG
|
||||
printf("\tpath = '%s', filename = '%s'\n", path, filename);
|
||||
#endif
|
||||
|
||||
File file(filename);
|
||||
|
||||
if (file.read())
|
||||
return filename; // error reading file
|
||||
|
||||
// Parse into lines
|
||||
int eof = 0;
|
||||
for (size_t i = 0; i < file.len && !eof; i++)
|
||||
{
|
||||
size_t linestart = i;
|
||||
|
||||
for (; i < file.len; i++)
|
||||
{
|
||||
switch (file.buffer[i])
|
||||
{
|
||||
case '\r':
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
// Skip if it was preceded by '\r'
|
||||
if (i && file.buffer[i - 1] == '\r')
|
||||
goto Lskip;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
case 0x1A:
|
||||
eof = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// The line is file.buffer[linestart..i]
|
||||
char *line;
|
||||
size_t len;
|
||||
char *p;
|
||||
char *pn;
|
||||
|
||||
line = (char *)&file.buffer[linestart];
|
||||
len = i - linestart;
|
||||
|
||||
buf.reset();
|
||||
|
||||
// First, expand the macros.
|
||||
// Macros are bracketed by % characters.
|
||||
|
||||
for (size_t k = 0; k < len; k++)
|
||||
{
|
||||
if (line[k] == '%')
|
||||
{
|
||||
for (size_t j = k + 1; j < len; j++)
|
||||
{
|
||||
if (line[j] == '%')
|
||||
{
|
||||
if (j - k == 3 && memicmp(&line[k + 1], "@P", 2) == 0)
|
||||
{
|
||||
// %@P% is special meaning the path to the .ini file
|
||||
p = path;
|
||||
if (!*p)
|
||||
p = (char *)".";
|
||||
}
|
||||
else
|
||||
{ size_t len2 = j - k;
|
||||
char tmp[10]; // big enough most of the time
|
||||
|
||||
if (len2 <= sizeof(tmp))
|
||||
p = tmp;
|
||||
else
|
||||
p = (char *)alloca(len2);
|
||||
len2--;
|
||||
memcpy(p, &line[k + 1], len2);
|
||||
p[len2] = 0;
|
||||
strupr(p);
|
||||
p = getenv(p);
|
||||
if (!p)
|
||||
p = (char *)"";
|
||||
}
|
||||
buf.writestring(p);
|
||||
k = j;
|
||||
goto L1;
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.writeByte(line[k]);
|
||||
L1:
|
||||
;
|
||||
}
|
||||
|
||||
// Remove trailing spaces
|
||||
while (buf.offset && isspace(buf.data[buf.offset - 1]))
|
||||
buf.offset--;
|
||||
|
||||
p = buf.toChars();
|
||||
|
||||
// The expanded line is in p.
|
||||
// Now parse it for meaning.
|
||||
|
||||
p = skipspace(p);
|
||||
switch (*p)
|
||||
{
|
||||
case ';': // comment
|
||||
case 0: // blank
|
||||
break;
|
||||
|
||||
case '[': // look for [Environment]
|
||||
p = skipspace(p + 1);
|
||||
for (pn = p; isalnum((unsigned char)*pn); pn++)
|
||||
;
|
||||
if (pn - p == 11 &&
|
||||
memicmp(p, "Environment", 11) == 0 &&
|
||||
*skipspace(pn) == ']'
|
||||
)
|
||||
envsection = 1;
|
||||
else
|
||||
envsection = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (envsection)
|
||||
{
|
||||
pn = p;
|
||||
|
||||
// Convert name to upper case;
|
||||
// remove spaces bracketing =
|
||||
for (p = pn; *p; p++)
|
||||
{ if (islower((unsigned char)*p))
|
||||
*p &= ~0x20;
|
||||
else if (isspace((unsigned char)*p))
|
||||
memmove(p, p + 1, strlen(p));
|
||||
else if (*p == '=')
|
||||
{
|
||||
p++;
|
||||
while (isspace((unsigned char)*p))
|
||||
memmove(p, p + 1, strlen(p));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
putenv(strdup(pn));
|
||||
#if LOG
|
||||
printf("\tputenv('%s')\n", pn);
|
||||
//printf("getenv(\"TEST\") = '%s'\n",getenv("TEST"));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Lskip:
|
||||
;
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
/********************
|
||||
* Skip spaces.
|
||||
*/
|
||||
|
||||
char *skipspace(const char *p)
|
||||
{
|
||||
while (isspace((unsigned char)*p))
|
||||
p++;
|
||||
return (char *)p;
|
||||
}
|
||||
|
||||
911
dmd2/init.c
Normal file
911
dmd2/init.c
Normal file
@@ -0,0 +1,911 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mars.h"
|
||||
#include "init.h"
|
||||
#include "expression.h"
|
||||
#include "statement.h"
|
||||
#include "identifier.h"
|
||||
#include "declaration.h"
|
||||
#include "aggregate.h"
|
||||
#include "scope.h"
|
||||
#include "mtype.h"
|
||||
#include "hdrgen.h"
|
||||
|
||||
/********************************** Initializer *******************************/
|
||||
|
||||
Initializer::Initializer(Loc loc)
|
||||
{
|
||||
this->loc = loc;
|
||||
}
|
||||
|
||||
Initializer *Initializer::syntaxCopy()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
Initializer *Initializer::semantic(Scope *sc, Type *t, int needInterpret)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
Type *Initializer::inferType(Scope *sc)
|
||||
{
|
||||
error(loc, "cannot infer type from initializer");
|
||||
return Type::terror;
|
||||
}
|
||||
|
||||
Initializers *Initializer::arraySyntaxCopy(Initializers *ai)
|
||||
{ Initializers *a = NULL;
|
||||
|
||||
if (ai)
|
||||
{
|
||||
a = new Initializers();
|
||||
a->setDim(ai->dim);
|
||||
for (size_t i = 0; i < a->dim; i++)
|
||||
{ Initializer *e = ai->tdata()[i];
|
||||
|
||||
e = e->syntaxCopy();
|
||||
a->tdata()[i] = e;
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
char *Initializer::toChars()
|
||||
{ OutBuffer *buf;
|
||||
HdrGenState hgs;
|
||||
|
||||
memset(&hgs, 0, sizeof(hgs));
|
||||
buf = new OutBuffer();
|
||||
toCBuffer(buf, &hgs);
|
||||
return buf->toChars();
|
||||
}
|
||||
|
||||
/********************************** VoidInitializer ***************************/
|
||||
|
||||
VoidInitializer::VoidInitializer(Loc loc)
|
||||
: Initializer(loc)
|
||||
{
|
||||
type = NULL;
|
||||
}
|
||||
|
||||
|
||||
Initializer *VoidInitializer::syntaxCopy()
|
||||
{
|
||||
return new VoidInitializer(loc);
|
||||
}
|
||||
|
||||
|
||||
Initializer *VoidInitializer::semantic(Scope *sc, Type *t, int needInterpret)
|
||||
{
|
||||
//printf("VoidInitializer::semantic(t = %p)\n", t);
|
||||
type = t;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
Expression *VoidInitializer::toExpression()
|
||||
{
|
||||
error(loc, "void initializer has no value");
|
||||
return new IntegerExp(0);
|
||||
}
|
||||
|
||||
|
||||
void VoidInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
buf->writestring("void");
|
||||
}
|
||||
|
||||
|
||||
/********************************** StructInitializer *************************/
|
||||
|
||||
StructInitializer::StructInitializer(Loc loc)
|
||||
: Initializer(loc)
|
||||
{
|
||||
ad = NULL;
|
||||
#if IN_LLVM
|
||||
ltype = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
Initializer *StructInitializer::syntaxCopy()
|
||||
{
|
||||
StructInitializer *ai = new StructInitializer(loc);
|
||||
|
||||
assert(field.dim == value.dim);
|
||||
ai->field.setDim(field.dim);
|
||||
ai->value.setDim(value.dim);
|
||||
for (size_t i = 0; i < field.dim; i++)
|
||||
{
|
||||
ai->field.tdata()[i] = field.tdata()[i];
|
||||
|
||||
Initializer *init = value.tdata()[i];
|
||||
init = init->syntaxCopy();
|
||||
ai->value.tdata()[i] = init;
|
||||
}
|
||||
return ai;
|
||||
}
|
||||
|
||||
void StructInitializer::addInit(Identifier *field, Initializer *value)
|
||||
{
|
||||
//printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
|
||||
this->field.push(field);
|
||||
this->value.push(value);
|
||||
}
|
||||
|
||||
Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret)
|
||||
{
|
||||
int errors = 0;
|
||||
|
||||
//printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars());
|
||||
vars.setDim(field.dim);
|
||||
t = t->toBasetype();
|
||||
if (t->ty == Tstruct)
|
||||
{
|
||||
unsigned fieldi = 0;
|
||||
|
||||
TypeStruct *ts = (TypeStruct *)t;
|
||||
ad = ts->sym;
|
||||
if (ad->ctor)
|
||||
error(loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead",
|
||||
ad->kind(), ad->toChars(), ad->toChars());
|
||||
size_t nfields = ad->fields.dim;
|
||||
if (((StructDeclaration *)ad)->isnested) nfields--;
|
||||
for (size_t i = 0; i < field.dim; i++)
|
||||
{
|
||||
Identifier *id = field.tdata()[i];
|
||||
Initializer *val = value.tdata()[i];
|
||||
Dsymbol *s;
|
||||
VarDeclaration *v;
|
||||
|
||||
if (id == NULL)
|
||||
{
|
||||
if (fieldi >= nfields)
|
||||
{ error(loc, "too many initializers for %s", ad->toChars());
|
||||
errors = 1;
|
||||
field.remove(i);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
s = ad->fields.tdata()[fieldi];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//s = ad->symtab->lookup(id);
|
||||
s = ad->search(loc, id, 0);
|
||||
if (!s)
|
||||
{
|
||||
error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars());
|
||||
errors = 1;
|
||||
continue;
|
||||
}
|
||||
s = s->toAlias();
|
||||
|
||||
// Find out which field index it is
|
||||
for (fieldi = 0; 1; fieldi++)
|
||||
{
|
||||
if (fieldi >= nfields)
|
||||
{
|
||||
error(loc, "%s.%s is not a per-instance initializable field",
|
||||
t->toChars(), s->toChars());
|
||||
errors = 1;
|
||||
break;
|
||||
}
|
||||
if (s == ad->fields.tdata()[fieldi])
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s && (v = s->isVarDeclaration()) != NULL)
|
||||
{
|
||||
val = val->semantic(sc, v->type, needInterpret);
|
||||
value.tdata()[i] = val;
|
||||
vars.tdata()[i] = v;
|
||||
}
|
||||
else
|
||||
{ error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars());
|
||||
errors = 1;
|
||||
}
|
||||
fieldi++;
|
||||
}
|
||||
}
|
||||
else if (t->ty == Tdelegate && value.dim == 0)
|
||||
{ /* Rewrite as empty delegate literal { }
|
||||
*/
|
||||
Parameters *arguments = new Parameters;
|
||||
Type *tf = new TypeFunction(arguments, NULL, 0, LINKd);
|
||||
FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL);
|
||||
fd->fbody = new CompoundStatement(loc, new Statements());
|
||||
fd->endloc = loc;
|
||||
Expression *e = new FuncExp(loc, fd);
|
||||
ExpInitializer *ie = new ExpInitializer(loc, e);
|
||||
return ie->semantic(sc, t, needInterpret);
|
||||
}
|
||||
else
|
||||
{
|
||||
error(loc, "a struct is not a valid initializer for a %s", t->toChars());
|
||||
errors = 1;
|
||||
}
|
||||
if (errors)
|
||||
{
|
||||
field.setDim(0);
|
||||
value.setDim(0);
|
||||
vars.setDim(0);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* This works by transforming a struct initializer into
|
||||
* a struct literal. In the future, the two should be the
|
||||
* same thing.
|
||||
*/
|
||||
Expression *StructInitializer::toExpression()
|
||||
{ Expression *e;
|
||||
size_t offset;
|
||||
|
||||
//printf("StructInitializer::toExpression() %s\n", toChars());
|
||||
if (!ad) // if fwd referenced
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
StructDeclaration *sd = ad->isStructDeclaration();
|
||||
if (!sd)
|
||||
return NULL;
|
||||
Expressions *elements = new Expressions();
|
||||
size_t nfields = ad->fields.dim;
|
||||
#if DMDV2
|
||||
if (sd->isnested)
|
||||
nfields--;
|
||||
#endif
|
||||
elements->setDim(nfields);
|
||||
for (size_t i = 0; i < elements->dim; i++)
|
||||
{
|
||||
elements->tdata()[i] = NULL;
|
||||
}
|
||||
unsigned fieldi = 0;
|
||||
for (size_t i = 0; i < value.dim; i++)
|
||||
{
|
||||
Identifier *id = field.tdata()[i];
|
||||
if (id)
|
||||
{
|
||||
Dsymbol * s = ad->search(loc, id, 0);
|
||||
if (!s)
|
||||
{
|
||||
error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars());
|
||||
goto Lno;
|
||||
}
|
||||
s = s->toAlias();
|
||||
|
||||
// Find out which field index it is
|
||||
for (fieldi = 0; 1; fieldi++)
|
||||
{
|
||||
if (fieldi >= nfields)
|
||||
{
|
||||
s->error("is not a per-instance initializable field");
|
||||
goto Lno;
|
||||
}
|
||||
if (s == ad->fields.tdata()[fieldi])
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (fieldi >= nfields)
|
||||
{ error(loc, "too many initializers for '%s'", ad->toChars());
|
||||
goto Lno;
|
||||
}
|
||||
Initializer *iz = value.tdata()[i];
|
||||
if (!iz)
|
||||
goto Lno;
|
||||
Expression *ex = iz->toExpression();
|
||||
if (!ex)
|
||||
goto Lno;
|
||||
if (elements->tdata()[fieldi])
|
||||
{ error(loc, "duplicate initializer for field '%s'",
|
||||
ad->fields.tdata()[fieldi]->toChars());
|
||||
goto Lno;
|
||||
}
|
||||
elements->tdata()[fieldi] = ex;
|
||||
++fieldi;
|
||||
}
|
||||
// Now, fill in any missing elements with default initializers.
|
||||
// We also need to validate any anonymous unions
|
||||
offset = 0;
|
||||
for (size_t i = 0; i < elements->dim; )
|
||||
{
|
||||
VarDeclaration * vd = ad->fields.tdata()[i]->isVarDeclaration();
|
||||
|
||||
//printf("test2 [%d] : %s %d %d\n", i, vd->toChars(), (int)offset, (int)vd->offset);
|
||||
if (vd->offset < offset)
|
||||
{
|
||||
// Only the first field of a union can have an initializer
|
||||
if (elements->tdata()[i])
|
||||
goto Lno;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!elements->tdata()[i])
|
||||
// Default initialize
|
||||
elements->tdata()[i] = vd->type->defaultInit();
|
||||
}
|
||||
offset = vd->offset + vd->type->size();
|
||||
i++;
|
||||
#if 0
|
||||
int unionSize = ad->numFieldsInUnion(i);
|
||||
if (unionSize == 1)
|
||||
{ // Not a union -- default initialize if missing
|
||||
if (!elements->tdata()[i])
|
||||
elements->tdata()[i] = vd->type->defaultInit();
|
||||
}
|
||||
else
|
||||
{ // anonymous union -- check for errors
|
||||
int found = -1; // index of the first field with an initializer
|
||||
for (int j = i; j < i + unionSize; ++j)
|
||||
{
|
||||
if (!elements->tdata()[j])
|
||||
continue;
|
||||
if (found >= 0)
|
||||
{
|
||||
VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration();
|
||||
VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration();
|
||||
error(loc, "%s cannot have initializers for fields %s and %s in same union",
|
||||
ad->toChars(),
|
||||
v1->toChars(), v->toChars());
|
||||
goto Lno;
|
||||
}
|
||||
found = j;
|
||||
}
|
||||
if (found == -1)
|
||||
{
|
||||
error(loc, "no initializer for union that contains field %s",
|
||||
vd->toChars());
|
||||
goto Lno;
|
||||
}
|
||||
}
|
||||
i += unionSize;
|
||||
#endif
|
||||
}
|
||||
e = new StructLiteralExp(loc, sd, elements);
|
||||
e->type = sd->type;
|
||||
return e;
|
||||
|
||||
Lno:
|
||||
delete elements;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
//printf("StructInitializer::toCBuffer()\n");
|
||||
buf->writebyte('{');
|
||||
for (size_t i = 0; i < field.dim; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
buf->writebyte(',');
|
||||
Identifier *id = field.tdata()[i];
|
||||
if (id)
|
||||
{
|
||||
buf->writestring(id->toChars());
|
||||
buf->writebyte(':');
|
||||
}
|
||||
Initializer *iz = value.tdata()[i];
|
||||
if (iz)
|
||||
iz->toCBuffer(buf, hgs);
|
||||
}
|
||||
buf->writebyte('}');
|
||||
}
|
||||
|
||||
/********************************** ArrayInitializer ************************************/
|
||||
|
||||
ArrayInitializer::ArrayInitializer(Loc loc)
|
||||
: Initializer(loc)
|
||||
{
|
||||
dim = 0;
|
||||
type = NULL;
|
||||
sem = 0;
|
||||
}
|
||||
|
||||
Initializer *ArrayInitializer::syntaxCopy()
|
||||
{
|
||||
//printf("ArrayInitializer::syntaxCopy()\n");
|
||||
|
||||
ArrayInitializer *ai = new ArrayInitializer(loc);
|
||||
|
||||
assert(index.dim == value.dim);
|
||||
ai->index.setDim(index.dim);
|
||||
ai->value.setDim(value.dim);
|
||||
for (size_t i = 0; i < ai->value.dim; i++)
|
||||
{ Expression *e = index.tdata()[i];
|
||||
if (e)
|
||||
e = e->syntaxCopy();
|
||||
ai->index.tdata()[i] = e;
|
||||
|
||||
Initializer *init = value.tdata()[i];
|
||||
init = init->syntaxCopy();
|
||||
ai->value.tdata()[i] = init;
|
||||
}
|
||||
return ai;
|
||||
}
|
||||
|
||||
void ArrayInitializer::addInit(Expression *index, Initializer *value)
|
||||
{
|
||||
this->index.push(index);
|
||||
this->value.push(value);
|
||||
dim = 0;
|
||||
type = NULL;
|
||||
}
|
||||
|
||||
Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, int needInterpret)
|
||||
{ unsigned i;
|
||||
unsigned length;
|
||||
const unsigned amax = 0x80000000;
|
||||
|
||||
//printf("ArrayInitializer::semantic(%s)\n", t->toChars());
|
||||
if (sem) // if semantic() already run
|
||||
return this;
|
||||
sem = 1;
|
||||
type = t;
|
||||
t = t->toBasetype();
|
||||
switch (t->ty)
|
||||
{
|
||||
case Tpointer:
|
||||
case Tsarray:
|
||||
case Tarray:
|
||||
break;
|
||||
|
||||
default:
|
||||
error(loc, "cannot use array to initialize %s", type->toChars());
|
||||
goto Lerr;
|
||||
}
|
||||
|
||||
length = 0;
|
||||
for (i = 0; i < index.dim; i++)
|
||||
{
|
||||
Expression *idx = index.tdata()[i];
|
||||
if (idx)
|
||||
{ idx = idx->semantic(sc);
|
||||
idx = idx->optimize(WANTvalue | WANTinterpret);
|
||||
index.tdata()[i] = idx;
|
||||
length = idx->toInteger();
|
||||
}
|
||||
|
||||
Initializer *val = value.tdata()[i];
|
||||
val = val->semantic(sc, t->nextOf(), needInterpret);
|
||||
value.tdata()[i] = val;
|
||||
length++;
|
||||
if (length == 0)
|
||||
{ error(loc, "array dimension overflow");
|
||||
goto Lerr;
|
||||
}
|
||||
if (length > dim)
|
||||
dim = length;
|
||||
}
|
||||
if (t->ty == Tsarray)
|
||||
{
|
||||
dinteger_t edim = ((TypeSArray *)t)->dim->toInteger();
|
||||
if (dim > edim)
|
||||
{
|
||||
error(loc, "array initializer has %u elements, but array length is %jd", dim, edim);
|
||||
goto Lerr;
|
||||
}
|
||||
}
|
||||
|
||||
if ((unsigned long) dim * t->nextOf()->size() >= amax)
|
||||
{ error(loc, "array dimension %u exceeds max of %u", dim, amax / t->nextOf()->size());
|
||||
goto Lerr;
|
||||
}
|
||||
return this;
|
||||
|
||||
Lerr:
|
||||
return new ExpInitializer(loc, new ErrorExp());
|
||||
}
|
||||
|
||||
/********************************
|
||||
* If possible, convert array initializer to array literal.
|
||||
* Otherwise return NULL.
|
||||
*/
|
||||
|
||||
Expression *ArrayInitializer::toExpression()
|
||||
{ Expressions *elements;
|
||||
|
||||
//printf("ArrayInitializer::toExpression(), dim = %d\n", dim);
|
||||
//static int i; if (++i == 2) halt();
|
||||
|
||||
size_t edim;
|
||||
Type *t = NULL;
|
||||
if (type)
|
||||
{
|
||||
if (type == Type::terror)
|
||||
return new ErrorExp();
|
||||
|
||||
t = type->toBasetype();
|
||||
switch (t->ty)
|
||||
{
|
||||
case Tsarray:
|
||||
edim = ((TypeSArray *)t)->dim->toInteger();
|
||||
break;
|
||||
|
||||
case Tpointer:
|
||||
case Tarray:
|
||||
edim = dim;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
edim = value.dim;
|
||||
for (size_t i = 0, j = 0; i < value.dim; i++, j++)
|
||||
{
|
||||
if (index.tdata()[i])
|
||||
j = index.tdata()[i]->toInteger();
|
||||
if (j >= edim)
|
||||
edim = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
elements = new Expressions();
|
||||
elements->setDim(edim);
|
||||
elements->zero();
|
||||
for (size_t i = 0, j = 0; i < value.dim; i++, j++)
|
||||
{
|
||||
if (index.tdata()[i])
|
||||
j = (index.tdata()[i])->toInteger();
|
||||
assert(j < edim);
|
||||
Initializer *iz = value.tdata()[i];
|
||||
if (!iz)
|
||||
goto Lno;
|
||||
Expression *ex = iz->toExpression();
|
||||
if (!ex)
|
||||
{
|
||||
goto Lno;
|
||||
}
|
||||
elements->tdata()[j] = ex;
|
||||
}
|
||||
|
||||
/* Fill in any missing elements with the default initializer
|
||||
*/
|
||||
{
|
||||
Expression *init = NULL;
|
||||
for (size_t i = 0; i < edim; i++)
|
||||
{
|
||||
if (!elements->tdata()[i])
|
||||
{
|
||||
if (!type)
|
||||
goto Lno;
|
||||
if (!init)
|
||||
init = ((TypeNext *)t)->next->defaultInit();
|
||||
elements->tdata()[i] = init;
|
||||
}
|
||||
}
|
||||
|
||||
Expression *e = new ArrayLiteralExp(loc, elements);
|
||||
e->type = type;
|
||||
return e;
|
||||
}
|
||||
|
||||
Lno:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/********************************
|
||||
* If possible, convert array initializer to associative array initializer.
|
||||
*/
|
||||
|
||||
Expression *ArrayInitializer::toAssocArrayLiteral()
|
||||
{
|
||||
Expression *e;
|
||||
|
||||
//printf("ArrayInitializer::toAssocArrayInitializer()\n");
|
||||
//static int i; if (++i == 2) halt();
|
||||
Expressions *keys = new Expressions();
|
||||
keys->setDim(value.dim);
|
||||
Expressions *values = new Expressions();
|
||||
values->setDim(value.dim);
|
||||
|
||||
for (size_t i = 0; i < value.dim; i++)
|
||||
{
|
||||
e = index.tdata()[i];
|
||||
if (!e)
|
||||
goto Lno;
|
||||
keys->tdata()[i] = e;
|
||||
|
||||
Initializer *iz = value.tdata()[i];
|
||||
if (!iz)
|
||||
goto Lno;
|
||||
e = iz->toExpression();
|
||||
if (!e)
|
||||
goto Lno;
|
||||
values->tdata()[i] = e;
|
||||
}
|
||||
e = new AssocArrayLiteralExp(loc, keys, values);
|
||||
return e;
|
||||
|
||||
Lno:
|
||||
delete keys;
|
||||
delete values;
|
||||
error(loc, "not an associative array initializer");
|
||||
return new ErrorExp();
|
||||
}
|
||||
|
||||
int ArrayInitializer::isAssociativeArray()
|
||||
{
|
||||
for (size_t i = 0; i < value.dim; i++)
|
||||
{
|
||||
if (index.tdata()[i])
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Type *ArrayInitializer::inferType(Scope *sc)
|
||||
{
|
||||
//printf("ArrayInitializer::inferType() %s\n", toChars());
|
||||
assert(0);
|
||||
return NULL;
|
||||
#if 0
|
||||
type = Type::terror;
|
||||
for (size_t i = 0; i < value.dim; i++)
|
||||
{
|
||||
if (index.data[i])
|
||||
goto Laa;
|
||||
}
|
||||
for (size_t i = 0; i < value.dim; i++)
|
||||
{
|
||||
Initializer *iz = (Initializer *)value.data[i];
|
||||
if (iz)
|
||||
{ Type *t = iz->inferType(sc);
|
||||
if (i == 0)
|
||||
{ /* BUG: This gets the type from the first element.
|
||||
* Fix to use all the elements to figure out the type.
|
||||
*/
|
||||
t = new TypeSArray(t, new IntegerExp(value.dim));
|
||||
t = t->semantic(loc, sc);
|
||||
type = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
return type;
|
||||
|
||||
Laa:
|
||||
/* It's possibly an associative array initializer.
|
||||
* BUG: inferring type from first member.
|
||||
*/
|
||||
Initializer *iz = (Initializer *)value.data[0];
|
||||
Expression *indexinit = (Expression *)index.data[0];
|
||||
if (iz && indexinit)
|
||||
{ Type *t = iz->inferType(sc);
|
||||
indexinit = indexinit->semantic(sc);
|
||||
Type *indext = indexinit->type;
|
||||
t = new TypeAArray(t, indext);
|
||||
type = t->semantic(loc, sc);
|
||||
}
|
||||
else
|
||||
error(loc, "cannot infer type from this array initializer");
|
||||
return type;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void ArrayInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
buf->writebyte('[');
|
||||
for (size_t i = 0; i < index.dim; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
buf->writebyte(',');
|
||||
Expression *ex = index.tdata()[i];
|
||||
if (ex)
|
||||
{
|
||||
ex->toCBuffer(buf, hgs);
|
||||
buf->writebyte(':');
|
||||
}
|
||||
Initializer *iz = value.tdata()[i];
|
||||
if (iz)
|
||||
iz->toCBuffer(buf, hgs);
|
||||
}
|
||||
buf->writebyte(']');
|
||||
}
|
||||
|
||||
|
||||
/********************************** ExpInitializer ************************************/
|
||||
|
||||
ExpInitializer::ExpInitializer(Loc loc, Expression *exp)
|
||||
: Initializer(loc)
|
||||
{
|
||||
this->exp = exp;
|
||||
}
|
||||
|
||||
Initializer *ExpInitializer::syntaxCopy()
|
||||
{
|
||||
return new ExpInitializer(loc, exp->syntaxCopy());
|
||||
}
|
||||
|
||||
bool arrayHasNonConstPointers(Expressions *elems);
|
||||
|
||||
bool hasNonConstPointers(Expression *e)
|
||||
{
|
||||
if (e->op == TOKnull)
|
||||
return false;
|
||||
if (e->op == TOKstructliteral)
|
||||
{
|
||||
StructLiteralExp *se = (StructLiteralExp *)e;
|
||||
return arrayHasNonConstPointers(se->elements);
|
||||
}
|
||||
if (e->op == TOKarrayliteral)
|
||||
{
|
||||
if (!e->type->nextOf()->hasPointers())
|
||||
return false;
|
||||
ArrayLiteralExp *ae = (ArrayLiteralExp *)e;
|
||||
return arrayHasNonConstPointers(ae->elements);
|
||||
}
|
||||
if (e->op == TOKassocarrayliteral)
|
||||
{
|
||||
AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
|
||||
if (ae->type->nextOf()->hasPointers() &&
|
||||
arrayHasNonConstPointers(ae->values))
|
||||
return true;
|
||||
if (((TypeAArray *)ae->type)->index->hasPointers())
|
||||
return arrayHasNonConstPointers(ae->keys);
|
||||
return false;
|
||||
}
|
||||
if (e->type->ty== Tpointer && e->type->nextOf()->ty != Tfunction)
|
||||
{
|
||||
#if IN_LLVM
|
||||
// address of a global is OK
|
||||
if (e->op == TOKaddress || e->op == TOKcast)
|
||||
return false;
|
||||
if (e->op == TOKadd || e->op == TOKmin) {
|
||||
BinExp *be = (BinExp*)e;
|
||||
if (be->e1->type->ty == Tpointer || be->e2->type->ty == Tpointer)
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (e->op == TOKsymoff) // address of a global is OK
|
||||
return false;
|
||||
#endif
|
||||
if (e->op == TOKint64) // cast(void *)int is OK
|
||||
return false;
|
||||
if (e->op == TOKstring) // "abc".ptr is OK
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool arrayHasNonConstPointers(Expressions *elems)
|
||||
{
|
||||
for (size_t i = 0; i < elems->dim; i++)
|
||||
{
|
||||
if (!elems->tdata()[i])
|
||||
continue;
|
||||
if (hasNonConstPointers(elems->tdata()[i]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret)
|
||||
{
|
||||
//printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars());
|
||||
exp = exp->semantic(sc);
|
||||
exp = resolveProperties(sc, exp);
|
||||
int wantOptimize = needInterpret ? WANTinterpret|WANTvalue : WANTvalue;
|
||||
|
||||
int olderrors = global.errors;
|
||||
exp = exp->optimize(wantOptimize);
|
||||
if (!global.gag && olderrors != global.errors)
|
||||
return this; // Failed, suppress duplicate error messages
|
||||
|
||||
if (exp->op == TOKtype)
|
||||
error("initializer must be an expression, not '%s'", exp->toChars());
|
||||
|
||||
// Make sure all pointers are constants
|
||||
if (needInterpret && hasNonConstPointers(exp))
|
||||
{
|
||||
exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars());
|
||||
return this;
|
||||
}
|
||||
|
||||
Type *tb = t->toBasetype();
|
||||
|
||||
/* Look for case of initializing a static array with a too-short
|
||||
* string literal, such as:
|
||||
* char[5] foo = "abc";
|
||||
* Allow this by doing an explicit cast, which will lengthen the string
|
||||
* literal.
|
||||
*/
|
||||
if (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray)
|
||||
{ StringExp *se = (StringExp *)exp;
|
||||
|
||||
if (!se->committed && se->type->ty == Tsarray &&
|
||||
((TypeSArray *)se->type)->dim->toInteger() <
|
||||
((TypeSArray *)t)->dim->toInteger())
|
||||
{
|
||||
exp = se->castTo(sc, t);
|
||||
goto L1;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the case of statically initializing an array
|
||||
// with a single member.
|
||||
if (tb->ty == Tsarray &&
|
||||
!tb->nextOf()->equals(exp->type->toBasetype()->nextOf()) &&
|
||||
exp->implicitConvTo(tb->nextOf())
|
||||
)
|
||||
{
|
||||
t = tb->nextOf();
|
||||
}
|
||||
|
||||
exp = exp->implicitCastTo(sc, t);
|
||||
L1:
|
||||
exp = exp->optimize(wantOptimize);
|
||||
//printf("-ExpInitializer::semantic(): "); exp->print();
|
||||
return this;
|
||||
}
|
||||
|
||||
Type *ExpInitializer::inferType(Scope *sc)
|
||||
{
|
||||
//printf("ExpInitializer::inferType() %s\n", toChars());
|
||||
if (exp->op == TOKfunction && ((FuncExp *)exp)->td)
|
||||
{
|
||||
exp->error("cannot infer type from ambiguous function literal %s", exp->toChars());
|
||||
return Type::terror;
|
||||
}
|
||||
|
||||
exp = exp->semantic(sc);
|
||||
exp = resolveProperties(sc, exp);
|
||||
|
||||
// Give error for overloaded function addresses
|
||||
if (exp->op == TOKsymoff)
|
||||
{ SymOffExp *se = (SymOffExp *)exp;
|
||||
if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique())
|
||||
exp->error("cannot infer type from overloaded function symbol %s", exp->toChars());
|
||||
}
|
||||
|
||||
// Give error for overloaded function addresses
|
||||
if (exp->op == TOKdelegate)
|
||||
{ DelegateExp *se = (DelegateExp *)exp;
|
||||
if (
|
||||
se->func->isFuncDeclaration() &&
|
||||
!se->func->isFuncDeclaration()->isUnique())
|
||||
exp->error("cannot infer type from overloaded function symbol %s", exp->toChars());
|
||||
}
|
||||
|
||||
Type *t = exp->type;
|
||||
if (!t)
|
||||
t = Initializer::inferType(sc);
|
||||
return t;
|
||||
}
|
||||
|
||||
Expression *ExpInitializer::toExpression()
|
||||
{
|
||||
return exp;
|
||||
}
|
||||
|
||||
|
||||
void ExpInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||
{
|
||||
exp->toCBuffer(buf, hgs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
149
dmd2/init.h
Normal file
149
dmd2/init.h
Normal file
@@ -0,0 +1,149 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2007 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef INIT_H
|
||||
#define INIT_H
|
||||
|
||||
#include "root.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "arraytypes.h"
|
||||
|
||||
struct Identifier;
|
||||
struct Expression;
|
||||
struct Scope;
|
||||
struct Type;
|
||||
struct dt_t;
|
||||
struct AggregateDeclaration;
|
||||
struct VoidInitializer;
|
||||
struct StructInitializer;
|
||||
struct ArrayInitializer;
|
||||
struct ExpInitializer;
|
||||
struct HdrGenState;
|
||||
|
||||
#if IN_LLVM
|
||||
namespace llvm {
|
||||
class StructType;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
struct Initializer : Object
|
||||
{
|
||||
Loc loc;
|
||||
|
||||
Initializer(Loc loc);
|
||||
virtual Initializer *syntaxCopy();
|
||||
// needInterpret is WANTinterpret if must be a manifest constant, 0 if not.
|
||||
virtual Initializer *semantic(Scope *sc, Type *t, int needInterpret);
|
||||
virtual Type *inferType(Scope *sc);
|
||||
virtual Expression *toExpression() = 0;
|
||||
virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0;
|
||||
char *toChars();
|
||||
|
||||
static Initializers *arraySyntaxCopy(Initializers *ai);
|
||||
|
||||
#if IN_DMD
|
||||
virtual dt_t *toDt();
|
||||
#endif
|
||||
|
||||
virtual VoidInitializer *isVoidInitializer() { return NULL; }
|
||||
virtual StructInitializer *isStructInitializer() { return NULL; }
|
||||
virtual ArrayInitializer *isArrayInitializer() { return NULL; }
|
||||
virtual ExpInitializer *isExpInitializer() { return NULL; }
|
||||
};
|
||||
|
||||
struct VoidInitializer : Initializer
|
||||
{
|
||||
Type *type; // type that this will initialize to
|
||||
|
||||
VoidInitializer(Loc loc);
|
||||
Initializer *syntaxCopy();
|
||||
Initializer *semantic(Scope *sc, Type *t, int needInterpret);
|
||||
Expression *toExpression();
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
|
||||
#if IN_DMD
|
||||
dt_t *toDt();
|
||||
#endif
|
||||
|
||||
virtual VoidInitializer *isVoidInitializer() { return this; }
|
||||
};
|
||||
|
||||
struct StructInitializer : Initializer
|
||||
{
|
||||
Identifiers field; // of Identifier *'s
|
||||
Initializers value; // parallel array of Initializer *'s
|
||||
|
||||
VarDeclarations vars; // parallel array of VarDeclaration *'s
|
||||
AggregateDeclaration *ad; // which aggregate this is for
|
||||
|
||||
StructInitializer(Loc loc);
|
||||
Initializer *syntaxCopy();
|
||||
void addInit(Identifier *field, Initializer *value);
|
||||
Initializer *semantic(Scope *sc, Type *t, int needInterpret);
|
||||
Expression *toExpression();
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
|
||||
#if IN_DMD
|
||||
dt_t *toDt();
|
||||
#endif
|
||||
|
||||
StructInitializer *isStructInitializer() { return this; }
|
||||
#if IN_LLVM
|
||||
llvm::StructType *ltype;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ArrayInitializer : Initializer
|
||||
{
|
||||
Expressions index; // indices
|
||||
Initializers value; // of Initializer *'s
|
||||
unsigned dim; // length of array being initialized
|
||||
Type *type; // type that array will be used to initialize
|
||||
int sem; // !=0 if semantic() is run
|
||||
|
||||
ArrayInitializer(Loc loc);
|
||||
Initializer *syntaxCopy();
|
||||
void addInit(Expression *index, Initializer *value);
|
||||
Initializer *semantic(Scope *sc, Type *t, int needInterpret);
|
||||
int isAssociativeArray();
|
||||
Type *inferType(Scope *sc);
|
||||
Expression *toExpression();
|
||||
Expression *toAssocArrayLiteral();
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
|
||||
#if IN_DMD
|
||||
dt_t *toDt();
|
||||
dt_t *toDtBit(); // for bit arrays
|
||||
#endif
|
||||
|
||||
ArrayInitializer *isArrayInitializer() { return this; }
|
||||
};
|
||||
|
||||
struct ExpInitializer : Initializer
|
||||
{
|
||||
Expression *exp;
|
||||
|
||||
ExpInitializer(Loc loc, Expression *exp);
|
||||
Initializer *syntaxCopy();
|
||||
Initializer *semantic(Scope *sc, Type *t, int needInterpret);
|
||||
Type *inferType(Scope *sc);
|
||||
Expression *toExpression();
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
|
||||
#if IN_DMD
|
||||
dt_t *toDt();
|
||||
#endif
|
||||
|
||||
virtual ExpInitializer *isExpInitializer() { return this; }
|
||||
};
|
||||
|
||||
#endif
|
||||
1831
dmd2/inline.c
Normal file
1831
dmd2/inline.c
Normal file
File diff suppressed because it is too large
Load Diff
6586
dmd2/interpret.c
Normal file
6586
dmd2/interpret.c
Normal file
File diff suppressed because it is too large
Load Diff
1105
dmd2/intrange.c
Normal file
1105
dmd2/intrange.c
Normal file
File diff suppressed because it is too large
Load Diff
149
dmd2/intrange.h
Normal file
149
dmd2/intrange.h
Normal file
@@ -0,0 +1,149 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by KennyTM
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
|
||||
#ifndef DMD_SXNUM_H
|
||||
#define DMD_SXNUM_H
|
||||
|
||||
#include "mars.h" // for uinteger_t
|
||||
struct Type;
|
||||
struct Expression;
|
||||
|
||||
/**
|
||||
This class represents a "sign-extended number", i.e. a 65-bit number, which can
|
||||
represent all built-in integer types in D. This class is mainly used for
|
||||
performing value-range propagation only, therefore all arithmetic are done with
|
||||
saturation, not wrapping as usual.
|
||||
*/
|
||||
struct SignExtendedNumber
|
||||
{
|
||||
/// The lower 64-bit of the number.
|
||||
uinteger_t value;
|
||||
/// The sign (i.e. the most significant bit) of the number.
|
||||
bool negative;
|
||||
|
||||
/// Create an uninitialized sign-extended number.
|
||||
SignExtendedNumber() {}
|
||||
|
||||
/// Create a sign-extended number from an unsigned 64-bit number.
|
||||
SignExtendedNumber(uinteger_t value_)
|
||||
: value(value_), negative(false) {}
|
||||
/// Create a sign-extended number from the lower 64-bit and the sign bit.
|
||||
SignExtendedNumber(uinteger_t value_, bool negative_)
|
||||
: value(value_), negative(negative_) {}
|
||||
|
||||
/// Create a sign-extended number from a signed 64-bit number.
|
||||
static SignExtendedNumber fromInteger(uinteger_t value_);
|
||||
|
||||
/// Get the minimum or maximum value of a sign-extended number.
|
||||
static SignExtendedNumber extreme(bool minimum);
|
||||
static SignExtendedNumber max();
|
||||
static SignExtendedNumber min() { return SignExtendedNumber(0, true); }
|
||||
|
||||
/// Check if the sign-extended number is minimum or zero.
|
||||
bool isMinimum() const { return negative && value == 0; }
|
||||
|
||||
/// Compare two sign-extended number.
|
||||
bool operator==(const SignExtendedNumber&) const;
|
||||
bool operator!=(const SignExtendedNumber& a) const { return !(*this == a); }
|
||||
bool operator<(const SignExtendedNumber&) const;
|
||||
bool operator>(const SignExtendedNumber& a) const { return a < *this; }
|
||||
bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); }
|
||||
bool operator>=(const SignExtendedNumber& a) const { return !(*this < a); }
|
||||
|
||||
/// Compute the saturated negation of a sign-extended number.
|
||||
SignExtendedNumber operator-() const;
|
||||
|
||||
/// Compute the saturated sum of two sign-extended number.
|
||||
SignExtendedNumber operator+(const SignExtendedNumber&) const;
|
||||
/// Compute the saturated difference of two sign-extended number.
|
||||
SignExtendedNumber operator-(const SignExtendedNumber& a) const;
|
||||
/// Compute the saturated product of two sign-extended number.
|
||||
SignExtendedNumber operator*(const SignExtendedNumber&) const;
|
||||
/// Compute the saturated quotient of two sign-extended number.
|
||||
SignExtendedNumber operator/(const SignExtendedNumber&) const;
|
||||
/// Compute the saturated modulus of two sign-extended number.
|
||||
SignExtendedNumber operator%(const SignExtendedNumber&) const;
|
||||
|
||||
/// Increase the sign-extended number by 1 (saturated).
|
||||
SignExtendedNumber& operator++();
|
||||
|
||||
/// Compute the saturated shifts of two sign-extended number.
|
||||
SignExtendedNumber operator<<(const SignExtendedNumber&) const;
|
||||
SignExtendedNumber operator>>(const SignExtendedNumber&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
This class represents a range of integers, denoted by its lower and upper bounds
|
||||
(inclusive).
|
||||
*/
|
||||
struct IntRange
|
||||
{
|
||||
SignExtendedNumber imin, imax;
|
||||
|
||||
/// Create an uninitialized range.
|
||||
IntRange() {}
|
||||
|
||||
/// Create a range consisting of a single number.
|
||||
IntRange(const SignExtendedNumber& a)
|
||||
: imin(a), imax(a) {}
|
||||
/// Create a range with the lower and upper bounds.
|
||||
IntRange(const SignExtendedNumber& lower, const SignExtendedNumber& upper)
|
||||
: imin(lower), imax(upper) {}
|
||||
|
||||
/// Create the tightest range containing all valid integers in the specified
|
||||
/// type.
|
||||
static IntRange fromType(Type *type);
|
||||
/// Create the tightest range containing all valid integers in the type with
|
||||
/// a forced signedness.
|
||||
static IntRange fromType(Type *type, bool isUnsigned);
|
||||
|
||||
|
||||
/// Create the tightest range containing all specified numbers.
|
||||
static IntRange fromNumbers2(const SignExtendedNumber numbers[2]);
|
||||
static IntRange fromNumbers4(const SignExtendedNumber numbers[4]);
|
||||
|
||||
/// Create the widest range possible.
|
||||
static IntRange widest();
|
||||
|
||||
/// Cast the integer range to a signed type with the given size mask.
|
||||
IntRange& castSigned(uinteger_t mask);
|
||||
/// Cast the integer range to an unsigned type with the given size mask.
|
||||
IntRange& castUnsigned(uinteger_t mask);
|
||||
/// Cast the integer range to the dchar type.
|
||||
IntRange& castDchar();
|
||||
|
||||
/// Cast the integer range to a specific type.
|
||||
IntRange& cast(Type *type);
|
||||
/// Cast the integer range to a specific type, forcing it to be unsigned.
|
||||
IntRange& castUnsigned(Type *type);
|
||||
|
||||
/// Check if this range contains another range.
|
||||
bool contains(const IntRange& a) const;
|
||||
|
||||
/// Check if this range contains 0.
|
||||
bool containsZero() const;
|
||||
|
||||
/// Compute the range of the negated absolute values of the original range.
|
||||
IntRange absNeg() const;
|
||||
|
||||
/// Compute the union of two ranges.
|
||||
IntRange unionWith(const IntRange& other) const;
|
||||
void unionOrAssign(const IntRange& other, bool& union_);
|
||||
|
||||
/// Dump the content of the integer range to the console.
|
||||
const IntRange& dump(const char* funcName, Expression *e) const;
|
||||
|
||||
/// Split the range into two nonnegative- and negative-only subintervals.
|
||||
void splitBySign(IntRange& negRange, bool& hasNegRange,
|
||||
IntRange& nonNegRange, bool& hasNonNegRange) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
195
dmd2/irstate.c
Normal file
195
dmd2/irstate.c
Normal file
@@ -0,0 +1,195 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mars.h"
|
||||
#include "mtype.h"
|
||||
#include "declaration.h"
|
||||
#include "irstate.h"
|
||||
|
||||
IRState::IRState(IRState *irs, Statement *s)
|
||||
{
|
||||
prev = irs;
|
||||
statement = s;
|
||||
symbol = NULL;
|
||||
breakBlock = NULL;
|
||||
contBlock = NULL;
|
||||
switchBlock = NULL;
|
||||
defaultBlock = NULL;
|
||||
ident = NULL;
|
||||
ehidden = NULL;
|
||||
startaddress = NULL;
|
||||
if (irs)
|
||||
{
|
||||
m = irs->m;
|
||||
shidden = irs->shidden;
|
||||
sclosure = irs->sclosure;
|
||||
sthis = irs->sthis;
|
||||
blx = irs->blx;
|
||||
deferToObj = irs->deferToObj;
|
||||
#if DMDV2
|
||||
varsInScope = irs->varsInScope;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
m = NULL;
|
||||
shidden = NULL;
|
||||
sclosure = NULL;
|
||||
sthis = NULL;
|
||||
blx = NULL;
|
||||
deferToObj = NULL;
|
||||
#if DMDV2
|
||||
varsInScope = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
IRState::IRState(IRState *irs, Dsymbol *s)
|
||||
{
|
||||
prev = irs;
|
||||
statement = NULL;
|
||||
symbol = s;
|
||||
breakBlock = NULL;
|
||||
contBlock = NULL;
|
||||
switchBlock = NULL;
|
||||
defaultBlock = NULL;
|
||||
ident = NULL;
|
||||
ehidden = NULL;
|
||||
startaddress = NULL;
|
||||
if (irs)
|
||||
{
|
||||
m = irs->m;
|
||||
shidden = irs->shidden;
|
||||
sclosure = irs->sclosure;
|
||||
sthis = irs->sthis;
|
||||
blx = irs->blx;
|
||||
deferToObj = irs->deferToObj;
|
||||
varsInScope = irs->varsInScope;
|
||||
}
|
||||
else
|
||||
{
|
||||
m = NULL;
|
||||
shidden = NULL;
|
||||
sclosure = NULL;
|
||||
sthis = NULL;
|
||||
blx = NULL;
|
||||
deferToObj = NULL;
|
||||
varsInScope = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
IRState::IRState(Module *m, Dsymbol *s)
|
||||
{
|
||||
prev = NULL;
|
||||
statement = NULL;
|
||||
this->m = m;
|
||||
symbol = s;
|
||||
breakBlock = NULL;
|
||||
contBlock = NULL;
|
||||
switchBlock = NULL;
|
||||
defaultBlock = NULL;
|
||||
ident = NULL;
|
||||
ehidden = NULL;
|
||||
shidden = NULL;
|
||||
sclosure = NULL;
|
||||
sthis = NULL;
|
||||
blx = NULL;
|
||||
deferToObj = NULL;
|
||||
startaddress = NULL;
|
||||
varsInScope = NULL;
|
||||
}
|
||||
|
||||
block *IRState::getBreakBlock(Identifier *ident)
|
||||
{
|
||||
IRState *bc;
|
||||
|
||||
for (bc = this; bc; bc = bc->prev)
|
||||
{
|
||||
if (ident)
|
||||
{
|
||||
if (bc->prev && bc->prev->ident == ident)
|
||||
return bc->breakBlock;
|
||||
}
|
||||
else if (bc->breakBlock)
|
||||
return bc->breakBlock;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block *IRState::getContBlock(Identifier *ident)
|
||||
{
|
||||
IRState *bc;
|
||||
|
||||
for (bc = this; bc; bc = bc->prev)
|
||||
{
|
||||
if (ident)
|
||||
{
|
||||
if (bc->prev && bc->prev->ident == ident)
|
||||
return bc->contBlock;
|
||||
}
|
||||
else if (bc->contBlock)
|
||||
return bc->contBlock;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block *IRState::getSwitchBlock()
|
||||
{
|
||||
IRState *bc;
|
||||
|
||||
for (bc = this; bc; bc = bc->prev)
|
||||
{
|
||||
if (bc->switchBlock)
|
||||
return bc->switchBlock;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block *IRState::getDefaultBlock()
|
||||
{
|
||||
IRState *bc;
|
||||
|
||||
for (bc = this; bc; bc = bc->prev)
|
||||
{
|
||||
if (bc->defaultBlock)
|
||||
return bc->defaultBlock;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FuncDeclaration *IRState::getFunc()
|
||||
{
|
||||
IRState *bc;
|
||||
|
||||
for (bc = this; bc->prev; bc = bc->prev)
|
||||
{
|
||||
}
|
||||
return (FuncDeclaration *)(bc->symbol);
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* Return !=0 if do array bounds checking
|
||||
*/
|
||||
int IRState::arrayBoundsCheck()
|
||||
{
|
||||
int result = global.params.useArrayBounds;
|
||||
|
||||
if (result == 1)
|
||||
{ // For safe functions only
|
||||
result = 0;
|
||||
FuncDeclaration *fd = getFunc();
|
||||
if (fd)
|
||||
{ Type *t = fd->type;
|
||||
if (t->ty == Tfunction && ((TypeFunction *)t)->trust == TRUSTsafe)
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
59
dmd2/irstate.h
Normal file
59
dmd2/irstate.h
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
|
||||
#ifndef DMD_CONTEXT_H
|
||||
#define DMD_CONTEXT_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
struct Module;
|
||||
struct Statement;
|
||||
struct block;
|
||||
struct Dsymbol;
|
||||
struct Identifier;
|
||||
struct Symbol;
|
||||
struct FuncDeclaration;
|
||||
struct Blockx;
|
||||
struct elem;
|
||||
#include "arraytypes.h"
|
||||
|
||||
struct IRState
|
||||
{
|
||||
IRState *prev;
|
||||
Statement *statement;
|
||||
Module *m; // module
|
||||
Dsymbol *symbol;
|
||||
Identifier *ident;
|
||||
Symbol *shidden; // hidden parameter to function
|
||||
Symbol *sthis; // 'this' parameter to function (member and nested)
|
||||
Symbol *sclosure; // pointer to closure instance
|
||||
Blockx *blx;
|
||||
Dsymbols *deferToObj; // array of Dsymbol's to run toObjFile(int multiobj) on later
|
||||
elem *ehidden; // transmit hidden pointer to CallExp::toElem()
|
||||
Symbol *startaddress;
|
||||
VarDeclarations *varsInScope; // variables that are in scope that will need destruction later
|
||||
|
||||
block *breakBlock;
|
||||
block *contBlock;
|
||||
block *switchBlock;
|
||||
block *defaultBlock;
|
||||
|
||||
IRState(IRState *irs, Statement *s);
|
||||
IRState(IRState *irs, Dsymbol *s);
|
||||
IRState(Module *m, Dsymbol *s);
|
||||
|
||||
block *getBreakBlock(Identifier *ident);
|
||||
block *getContBlock(Identifier *ident);
|
||||
block *getSwitchBlock();
|
||||
block *getDefaultBlock();
|
||||
FuncDeclaration *getFunc();
|
||||
int arrayBoundsCheck();
|
||||
};
|
||||
|
||||
#endif /* DMD_CONTEXT_H */
|
||||
462
dmd2/json.c
Normal file
462
dmd2/json.c
Normal file
@@ -0,0 +1,462 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
// This implements the JSON capability.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "rmem.h"
|
||||
#include "root.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "dsymbol.h"
|
||||
#include "macro.h"
|
||||
#include "template.h"
|
||||
#include "lexer.h"
|
||||
#include "aggregate.h"
|
||||
#include "declaration.h"
|
||||
#include "enum.h"
|
||||
#include "id.h"
|
||||
#include "module.h"
|
||||
#include "scope.h"
|
||||
#include "hdrgen.h"
|
||||
#include "json.h"
|
||||
#include "mtype.h"
|
||||
#include "attrib.h"
|
||||
#include "cond.h"
|
||||
|
||||
const char Pname[] = "name";
|
||||
const char Pkind[] = "kind";
|
||||
const char Pfile[] = "file";
|
||||
const char Pline[] = "line";
|
||||
const char Ptype[] = "type";
|
||||
const char Pcomment[] = "comment";
|
||||
const char Pmembers[] = "members";
|
||||
const char Pprotection[] = "protection";
|
||||
const char* Pprotectionnames[] = {NULL, "none", "private", "package", "protected", "public", "export"};
|
||||
|
||||
void JsonRemoveComma(OutBuffer *buf);
|
||||
|
||||
void json_generate(Modules *modules)
|
||||
{ OutBuffer buf;
|
||||
|
||||
buf.writestring("[\n");
|
||||
for (size_t i = 0; i < modules->dim; i++)
|
||||
{ Module *m = modules->tdata()[i];
|
||||
if (global.params.verbose)
|
||||
printf("json gen %s\n", m->toChars());
|
||||
m->toJsonBuffer(&buf);
|
||||
buf.writestring(",\n");
|
||||
}
|
||||
JsonRemoveComma(&buf);
|
||||
buf.writestring("]\n");
|
||||
|
||||
// Write buf to file
|
||||
char *arg = global.params.xfilename;
|
||||
if (!arg || !*arg)
|
||||
{ // Generate lib file name from first obj name
|
||||
char *n = global.params.objfiles->tdata()[0];
|
||||
|
||||
n = FileName::name(n);
|
||||
FileName *fn = FileName::forceExt(n, global.json_ext);
|
||||
arg = fn->toChars();
|
||||
}
|
||||
else if (arg[0] == '-' && arg[1] == 0)
|
||||
{ // Write to stdout; assume it succeeds
|
||||
int n = fwrite(buf.data, 1, buf.offset, stdout);
|
||||
assert(n == buf.offset); // keep gcc happy about return values
|
||||
return;
|
||||
}
|
||||
// if (!FileName::absolute(arg))
|
||||
// arg = FileName::combine(dir, arg);
|
||||
FileName *jsonfilename = FileName::defaultExt(arg, global.json_ext);
|
||||
File *jsonfile = new File(jsonfilename);
|
||||
assert(jsonfile);
|
||||
jsonfile->setbuffer(buf.data, buf.offset);
|
||||
jsonfile->ref = 1;
|
||||
char *pt = FileName::path(jsonfile->toChars());
|
||||
if (*pt)
|
||||
FileName::ensurePathExists(pt);
|
||||
mem.free(pt);
|
||||
jsonfile->writev();
|
||||
}
|
||||
|
||||
|
||||
/*********************************
|
||||
* Encode string into buf, and wrap it in double quotes.
|
||||
*/
|
||||
void JsonString(OutBuffer *buf, const char *s)
|
||||
{
|
||||
buf->writeByte('\"');
|
||||
for (; *s; s++)
|
||||
{
|
||||
unsigned char c = (unsigned char) *s;
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
buf->writestring("\\n");
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
buf->writestring("\\r");
|
||||
break;
|
||||
|
||||
case '\t':
|
||||
buf->writestring("\\t");
|
||||
break;
|
||||
|
||||
case '\"':
|
||||
buf->writestring("\\\"");
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
buf->writestring("\\\\");
|
||||
break;
|
||||
|
||||
case '/':
|
||||
buf->writestring("\\/");
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
buf->writestring("\\b");
|
||||
break;
|
||||
|
||||
case '\f':
|
||||
buf->writestring("\\f");
|
||||
break;
|
||||
|
||||
default:
|
||||
if (c < 0x20)
|
||||
buf->printf("\\u%04x", c);
|
||||
else
|
||||
// Note that UTF-8 chars pass through here just fine
|
||||
buf->writeByte(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf->writeByte('\"');
|
||||
}
|
||||
|
||||
void JsonProperty(OutBuffer *buf, const char *name, const char *value)
|
||||
{
|
||||
JsonString(buf, name);
|
||||
buf->writestring(" : ");
|
||||
JsonString(buf, value);
|
||||
buf->writestring(",\n");
|
||||
}
|
||||
|
||||
void JsonProperty(OutBuffer *buf, const char *name, int value)
|
||||
{
|
||||
JsonString(buf, name);
|
||||
buf->writestring(" : ");
|
||||
buf->printf("%d", value);
|
||||
buf->writestring(",\n");
|
||||
}
|
||||
|
||||
void JsonRemoveComma(OutBuffer *buf)
|
||||
{
|
||||
if (buf->offset >= 2 &&
|
||||
buf->data[buf->offset - 2] == ',' &&
|
||||
buf->data[buf->offset - 1] == '\n')
|
||||
buf->offset -= 2;
|
||||
}
|
||||
|
||||
void Dsymbol::toJsonBuffer(OutBuffer *buf)
|
||||
{
|
||||
}
|
||||
|
||||
void Module::toJsonBuffer(OutBuffer *buf)
|
||||
{
|
||||
buf->writestring("{\n");
|
||||
|
||||
if (md)
|
||||
JsonProperty(buf, Pname, md->toChars());
|
||||
|
||||
JsonProperty(buf, Pkind, kind());
|
||||
|
||||
JsonProperty(buf, Pfile, srcfile->toChars());
|
||||
|
||||
if (comment)
|
||||
JsonProperty(buf, Pcomment, (const char *)comment);
|
||||
|
||||
JsonString(buf, Pmembers);
|
||||
buf->writestring(" : [\n");
|
||||
|
||||
size_t offset = buf->offset;
|
||||
for (size_t i = 0; i < members->dim; i++)
|
||||
{ Dsymbol *s = members->tdata()[i];
|
||||
if (offset != buf->offset)
|
||||
{ buf->writestring(",\n");
|
||||
offset = buf->offset;
|
||||
}
|
||||
s->toJsonBuffer(buf);
|
||||
}
|
||||
|
||||
JsonRemoveComma(buf);
|
||||
buf->writestring("]\n");
|
||||
|
||||
buf->writestring("}\n");
|
||||
}
|
||||
|
||||
void AttribDeclaration::toJsonBuffer(OutBuffer *buf)
|
||||
{
|
||||
//printf("AttribDeclaration::toJsonBuffer()\n");
|
||||
|
||||
Dsymbols *d = include(NULL, NULL);
|
||||
|
||||
if (d)
|
||||
{
|
||||
size_t offset = buf->offset;
|
||||
for (unsigned i = 0; i < d->dim; i++)
|
||||
{ Dsymbol *s = d->tdata()[i];
|
||||
//printf("AttribDeclaration::toJsonBuffer %s\n", s->toChars());
|
||||
if (offset != buf->offset)
|
||||
{ buf->writestring(",\n");
|
||||
offset = buf->offset;
|
||||
}
|
||||
s->toJsonBuffer(buf);
|
||||
}
|
||||
JsonRemoveComma(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ConditionalDeclaration::toJsonBuffer(OutBuffer *buf)
|
||||
{
|
||||
//printf("ConditionalDeclaration::toJsonBuffer()\n");
|
||||
if (condition->inc)
|
||||
{
|
||||
AttribDeclaration::toJsonBuffer(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InvariantDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||
void DtorDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||
void StaticCtorDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||
void StaticDtorDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||
void ClassInfoDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||
void ModuleInfoDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||
void TypeInfoDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||
void UnitTestDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||
#if DMDV2
|
||||
void PostBlitDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||
#endif
|
||||
|
||||
void Declaration::toJsonBuffer(OutBuffer *buf)
|
||||
{
|
||||
//printf("Declaration::toJsonBuffer()\n");
|
||||
buf->writestring("{\n");
|
||||
|
||||
JsonProperty(buf, Pname, toChars());
|
||||
JsonProperty(buf, Pkind, kind());
|
||||
|
||||
if (prot())
|
||||
JsonProperty(buf, Pprotection, Pprotectionnames[prot()]);
|
||||
|
||||
if (type)
|
||||
JsonProperty(buf, Ptype, type->toChars());
|
||||
|
||||
if (comment)
|
||||
JsonProperty(buf, Pcomment, (const char *)comment);
|
||||
|
||||
if (loc.linnum)
|
||||
JsonProperty(buf, Pline, loc.linnum);
|
||||
|
||||
TypedefDeclaration *td = isTypedefDeclaration();
|
||||
if (td)
|
||||
{
|
||||
JsonProperty(buf, "base", td->basetype->toChars());
|
||||
}
|
||||
|
||||
JsonRemoveComma(buf);
|
||||
buf->writestring("}\n");
|
||||
}
|
||||
|
||||
void AggregateDeclaration::toJsonBuffer(OutBuffer *buf)
|
||||
{
|
||||
//printf("AggregateDeclaration::toJsonBuffer()\n");
|
||||
buf->writestring("{\n");
|
||||
|
||||
JsonProperty(buf, Pname, toChars());
|
||||
JsonProperty(buf, Pkind, kind());
|
||||
|
||||
if (prot())
|
||||
JsonProperty(buf, Pprotection, Pprotectionnames[prot()]);
|
||||
|
||||
if (comment)
|
||||
JsonProperty(buf, Pcomment, (const char *)comment);
|
||||
|
||||
if (loc.linnum)
|
||||
JsonProperty(buf, Pline, loc.linnum);
|
||||
|
||||
ClassDeclaration *cd = isClassDeclaration();
|
||||
if (cd)
|
||||
{
|
||||
if (cd->baseClass)
|
||||
{
|
||||
JsonProperty(buf, "base", cd->baseClass->toChars());
|
||||
}
|
||||
if (cd->interfaces_dim)
|
||||
{
|
||||
JsonString(buf, "interfaces");
|
||||
buf->writestring(" : [\n");
|
||||
size_t offset = buf->offset;
|
||||
for (size_t i = 0; i < cd->interfaces_dim; i++)
|
||||
{ BaseClass *b = cd->interfaces[i];
|
||||
if (offset != buf->offset)
|
||||
{ buf->writestring(",\n");
|
||||
offset = buf->offset;
|
||||
}
|
||||
JsonString(buf, b->base->toChars());
|
||||
}
|
||||
JsonRemoveComma(buf);
|
||||
buf->writestring("],\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (members)
|
||||
{
|
||||
JsonString(buf, Pmembers);
|
||||
buf->writestring(" : [\n");
|
||||
size_t offset = buf->offset;
|
||||
for (size_t i = 0; i < members->dim; i++)
|
||||
{ Dsymbol *s = members->tdata()[i];
|
||||
if (offset != buf->offset)
|
||||
{ buf->writestring(",\n");
|
||||
offset = buf->offset;
|
||||
}
|
||||
s->toJsonBuffer(buf);
|
||||
}
|
||||
JsonRemoveComma(buf);
|
||||
buf->writestring("]\n");
|
||||
}
|
||||
JsonRemoveComma(buf);
|
||||
|
||||
buf->writestring("}\n");
|
||||
}
|
||||
|
||||
void TemplateDeclaration::toJsonBuffer(OutBuffer *buf)
|
||||
{
|
||||
//printf("TemplateDeclaration::toJsonBuffer()\n");
|
||||
|
||||
buf->writestring("{\n");
|
||||
|
||||
JsonProperty(buf, Pname, toChars());
|
||||
JsonProperty(buf, Pkind, kind());
|
||||
|
||||
if (prot())
|
||||
JsonProperty(buf, Pprotection, Pprotectionnames[prot()]);
|
||||
|
||||
if (comment)
|
||||
JsonProperty(buf, Pcomment, (const char *)comment);
|
||||
|
||||
if (loc.linnum)
|
||||
JsonProperty(buf, Pline, loc.linnum);
|
||||
|
||||
JsonString(buf, Pmembers);
|
||||
buf->writestring(" : [\n");
|
||||
size_t offset = buf->offset;
|
||||
for (size_t i = 0; i < members->dim; i++)
|
||||
{ Dsymbol *s = members->tdata()[i];
|
||||
if (offset != buf->offset)
|
||||
{ buf->writestring(",\n");
|
||||
offset = buf->offset;
|
||||
}
|
||||
s->toJsonBuffer(buf);
|
||||
}
|
||||
JsonRemoveComma(buf);
|
||||
buf->writestring("]\n");
|
||||
|
||||
buf->writestring("}\n");
|
||||
}
|
||||
|
||||
void EnumDeclaration::toJsonBuffer(OutBuffer *buf)
|
||||
{
|
||||
//printf("EnumDeclaration::toJsonBuffer()\n");
|
||||
if (isAnonymous())
|
||||
{
|
||||
if (members)
|
||||
{
|
||||
for (size_t i = 0; i < members->dim; i++)
|
||||
{
|
||||
Dsymbol *s = members->tdata()[i];
|
||||
s->toJsonBuffer(buf);
|
||||
buf->writestring(",\n");
|
||||
}
|
||||
JsonRemoveComma(buf);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
buf->writestring("{\n");
|
||||
|
||||
JsonProperty(buf, Pname, toChars());
|
||||
JsonProperty(buf, Pkind, kind());
|
||||
|
||||
if (prot())
|
||||
JsonProperty(buf, Pprotection, Pprotectionnames[prot()]);
|
||||
|
||||
if (comment)
|
||||
JsonProperty(buf, Pcomment, (const char *)comment);
|
||||
|
||||
if (loc.linnum)
|
||||
JsonProperty(buf, Pline, loc.linnum);
|
||||
|
||||
if (memtype)
|
||||
JsonProperty(buf, "base", memtype->toChars());
|
||||
|
||||
if (members)
|
||||
{
|
||||
JsonString(buf, Pmembers);
|
||||
buf->writestring(" : [\n");
|
||||
size_t offset = buf->offset;
|
||||
for (size_t i = 0; i < members->dim; i++)
|
||||
{ Dsymbol *s = members->tdata()[i];
|
||||
if (offset != buf->offset)
|
||||
{ buf->writestring(",\n");
|
||||
offset = buf->offset;
|
||||
}
|
||||
s->toJsonBuffer(buf);
|
||||
}
|
||||
JsonRemoveComma(buf);
|
||||
buf->writestring("]\n");
|
||||
}
|
||||
JsonRemoveComma(buf);
|
||||
|
||||
buf->writestring("}\n");
|
||||
}
|
||||
|
||||
void EnumMember::toJsonBuffer(OutBuffer *buf)
|
||||
{
|
||||
//printf("EnumMember::toJsonBuffer()\n");
|
||||
buf->writestring("{\n");
|
||||
|
||||
JsonProperty(buf, Pname, toChars());
|
||||
JsonProperty(buf, Pkind, kind());
|
||||
|
||||
if (prot())
|
||||
JsonProperty(buf, Pprotection, Pprotectionnames[prot()]);
|
||||
|
||||
if (comment)
|
||||
JsonProperty(buf, Pcomment, (const char *)comment);
|
||||
|
||||
if (loc.linnum)
|
||||
JsonProperty(buf, Pline, loc.linnum);
|
||||
|
||||
JsonRemoveComma(buf);
|
||||
buf->writestring("}\n");
|
||||
}
|
||||
|
||||
|
||||
24
dmd2/json.h
Normal file
24
dmd2/json.h
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2008 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_JSON_H
|
||||
#define DMD_JSON_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
#include "arraytypes.h"
|
||||
|
||||
void json_generate(Modules *);
|
||||
|
||||
#endif /* DMD_JSON_H */
|
||||
|
||||
3216
dmd2/lexer.c
Normal file
3216
dmd2/lexer.c
Normal file
File diff suppressed because it is too large
Load Diff
321
dmd2/lexer.h
Normal file
321
dmd2/lexer.h
Normal file
@@ -0,0 +1,321 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2010 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_LEXER_H
|
||||
#define DMD_LEXER_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
#include "root.h"
|
||||
#include "mars.h"
|
||||
|
||||
struct StringTable;
|
||||
struct Identifier;
|
||||
struct Module;
|
||||
|
||||
/* Tokens:
|
||||
( )
|
||||
[ ]
|
||||
{ }
|
||||
< > <= >= == != === !==
|
||||
<< >> <<= >>= >>> >>>=
|
||||
+ - += -=
|
||||
* / % *= /= %=
|
||||
& | ^ &= |= ^=
|
||||
= ! ~ @
|
||||
^^ ^^=
|
||||
++ --
|
||||
. -> : , =>
|
||||
? && ||
|
||||
*/
|
||||
|
||||
enum TOK
|
||||
{
|
||||
TOKreserved,
|
||||
|
||||
// Other
|
||||
TOKlparen, TOKrparen,
|
||||
TOKlbracket, TOKrbracket,
|
||||
TOKlcurly, TOKrcurly,
|
||||
TOKcolon, TOKneg,
|
||||
TOKsemicolon, TOKdotdotdot,
|
||||
TOKeof, TOKcast,
|
||||
TOKnull, TOKassert,
|
||||
TOKtrue, TOKfalse,
|
||||
TOKarray, TOKcall,
|
||||
TOKaddress,
|
||||
TOKtype, TOKthrow,
|
||||
TOKnew, TOKdelete,
|
||||
TOKstar, TOKsymoff,
|
||||
TOKvar, TOKdotvar,
|
||||
TOKdotti, TOKdotexp,
|
||||
TOKdottype, TOKslice,
|
||||
TOKarraylength, TOKversion,
|
||||
TOKmodule, TOKdollar,
|
||||
TOKtemplate, TOKdottd,
|
||||
TOKdeclaration, TOKtypeof,
|
||||
TOKpragma, TOKdsymbol,
|
||||
TOKtypeid, TOKuadd,
|
||||
TOKremove,
|
||||
TOKnewanonclass, TOKcomment,
|
||||
TOKarrayliteral, TOKassocarrayliteral,
|
||||
TOKstructliteral,
|
||||
|
||||
// Operators
|
||||
TOKlt, TOKgt,
|
||||
TOKle, TOKge,
|
||||
TOKequal, TOKnotequal,
|
||||
TOKidentity, TOKnotidentity,
|
||||
TOKindex, TOKis,
|
||||
TOKtobool,
|
||||
|
||||
// 60
|
||||
// NCEG floating point compares
|
||||
// !<>= <> <>= !> !>= !< !<= !<>
|
||||
TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue,
|
||||
|
||||
TOKshl, TOKshr,
|
||||
TOKshlass, TOKshrass,
|
||||
TOKushr, TOKushrass,
|
||||
TOKcat, TOKcatass, // ~ ~=
|
||||
TOKadd, TOKmin, TOKaddass, TOKminass,
|
||||
TOKmul, TOKdiv, TOKmod,
|
||||
TOKmulass, TOKdivass, TOKmodass,
|
||||
TOKand, TOKor, TOKxor,
|
||||
TOKandass, TOKorass, TOKxorass,
|
||||
TOKassign, TOKnot, TOKtilde,
|
||||
TOKplusplus, TOKminusminus, TOKconstruct, TOKblit,
|
||||
TOKdot, TOKarrow, TOKcomma,
|
||||
TOKquestion, TOKandand, TOKoror,
|
||||
TOKpreplusplus, TOKpreminusminus,
|
||||
|
||||
// 106
|
||||
// Numeric literals
|
||||
TOKint32v, TOKuns32v,
|
||||
TOKint64v, TOKuns64v,
|
||||
TOKfloat32v, TOKfloat64v, TOKfloat80v,
|
||||
TOKimaginary32v, TOKimaginary64v, TOKimaginary80v,
|
||||
|
||||
// Char constants
|
||||
TOKcharv, TOKwcharv, TOKdcharv,
|
||||
|
||||
// Leaf operators
|
||||
TOKidentifier, TOKstring,
|
||||
TOKthis, TOKsuper,
|
||||
TOKhalt, TOKtuple,
|
||||
TOKerror,
|
||||
|
||||
// Basic types
|
||||
TOKvoid,
|
||||
TOKint8, TOKuns8,
|
||||
TOKint16, TOKuns16,
|
||||
TOKint32, TOKuns32,
|
||||
TOKint64, TOKuns64,
|
||||
TOKfloat32, TOKfloat64, TOKfloat80,
|
||||
TOKimaginary32, TOKimaginary64, TOKimaginary80,
|
||||
TOKcomplex32, TOKcomplex64, TOKcomplex80,
|
||||
TOKchar, TOKwchar, TOKdchar, TOKbit, TOKbool,
|
||||
TOKcent, TOKucent,
|
||||
|
||||
// 152
|
||||
// Aggregates
|
||||
TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport,
|
||||
TOKtypedef, TOKalias, TOKoverride, TOKdelegate, TOKfunction,
|
||||
TOKmixin,
|
||||
|
||||
TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport,
|
||||
TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile,
|
||||
TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy,
|
||||
TOKauto, TOKpackage, TOKmanifest, TOKimmutable,
|
||||
|
||||
// Statements
|
||||
TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch,
|
||||
TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith,
|
||||
TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally,
|
||||
TOKasm, TOKforeach, TOKforeach_reverse,
|
||||
TOKscope,
|
||||
TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success,
|
||||
|
||||
// Contracts
|
||||
TOKbody, TOKinvariant,
|
||||
|
||||
// Testing
|
||||
TOKunittest,
|
||||
|
||||
// Added after 1.0
|
||||
TOKargTypes,
|
||||
TOKref,
|
||||
TOKmacro,
|
||||
#if DMDV2
|
||||
TOKtraits,
|
||||
TOKoverloadset,
|
||||
TOKpure,
|
||||
TOKnothrow,
|
||||
TOKtls,
|
||||
TOKgshared,
|
||||
TOKline,
|
||||
TOKfile,
|
||||
TOKshared,
|
||||
TOKat,
|
||||
TOKpow,
|
||||
TOKpowass,
|
||||
TOKgoesto,
|
||||
TOKvector,
|
||||
#endif
|
||||
|
||||
// LDC specific
|
||||
#if IN_LLVM
|
||||
TOKgep,
|
||||
#endif
|
||||
|
||||
TOKMAX
|
||||
};
|
||||
|
||||
#define TOKwild TOKinout
|
||||
|
||||
#define BASIC_TYPES \
|
||||
TOKwchar: case TOKdchar: \
|
||||
case TOKbit: case TOKbool: case TOKchar: \
|
||||
case TOKint8: case TOKuns8: \
|
||||
case TOKint16: case TOKuns16: \
|
||||
case TOKint32: case TOKuns32: \
|
||||
case TOKint64: case TOKuns64: \
|
||||
case TOKfloat32: case TOKfloat64: case TOKfloat80: \
|
||||
case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: \
|
||||
case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: \
|
||||
case TOKvoid
|
||||
|
||||
#define BASIC_TYPES_X(t) \
|
||||
TOKvoid: t = Type::tvoid; goto LabelX; \
|
||||
case TOKint8: t = Type::tint8; goto LabelX; \
|
||||
case TOKuns8: t = Type::tuns8; goto LabelX; \
|
||||
case TOKint16: t = Type::tint16; goto LabelX; \
|
||||
case TOKuns16: t = Type::tuns16; goto LabelX; \
|
||||
case TOKint32: t = Type::tint32; goto LabelX; \
|
||||
case TOKuns32: t = Type::tuns32; goto LabelX; \
|
||||
case TOKint64: t = Type::tint64; goto LabelX; \
|
||||
case TOKuns64: t = Type::tuns64; goto LabelX; \
|
||||
case TOKfloat32: t = Type::tfloat32; goto LabelX; \
|
||||
case TOKfloat64: t = Type::tfloat64; goto LabelX; \
|
||||
case TOKfloat80: t = Type::tfloat80; goto LabelX; \
|
||||
case TOKimaginary32: t = Type::timaginary32; goto LabelX; \
|
||||
case TOKimaginary64: t = Type::timaginary64; goto LabelX; \
|
||||
case TOKimaginary80: t = Type::timaginary80; goto LabelX; \
|
||||
case TOKcomplex32: t = Type::tcomplex32; goto LabelX; \
|
||||
case TOKcomplex64: t = Type::tcomplex64; goto LabelX; \
|
||||
case TOKcomplex80: t = Type::tcomplex80; goto LabelX; \
|
||||
case TOKbool: t = Type::tbool; goto LabelX; \
|
||||
case TOKchar: t = Type::tchar; goto LabelX; \
|
||||
case TOKwchar: t = Type::twchar; goto LabelX; \
|
||||
case TOKdchar: t = Type::tdchar; goto LabelX; \
|
||||
LabelX
|
||||
|
||||
struct Token
|
||||
{
|
||||
Token *next;
|
||||
unsigned char *ptr; // pointer to first character of this token within buffer
|
||||
enum TOK value;
|
||||
unsigned char *blockComment; // doc comment string prior to this token
|
||||
unsigned char *lineComment; // doc comment for previous token
|
||||
union
|
||||
{
|
||||
// Integers
|
||||
d_int32 int32value;
|
||||
d_uns32 uns32value;
|
||||
d_int64 int64value;
|
||||
d_uns64 uns64value;
|
||||
|
||||
// Floats
|
||||
#ifdef IN_GCC
|
||||
// real_t float80value; // can't use this in a union!
|
||||
#else
|
||||
d_float80 float80value;
|
||||
#endif
|
||||
|
||||
struct
|
||||
{ unsigned char *ustring; // UTF8 string
|
||||
unsigned len;
|
||||
unsigned char postfix; // 'c', 'w', 'd'
|
||||
};
|
||||
|
||||
Identifier *ident;
|
||||
};
|
||||
#ifdef IN_GCC
|
||||
real_t float80value; // can't use this in a union!
|
||||
#endif
|
||||
|
||||
static const char *tochars[TOKMAX];
|
||||
static void *operator new(size_t sz);
|
||||
|
||||
int isKeyword();
|
||||
void print();
|
||||
const char *toChars();
|
||||
static const char *toChars(enum TOK);
|
||||
};
|
||||
|
||||
struct Lexer
|
||||
{
|
||||
static StringTable stringtable;
|
||||
static OutBuffer stringbuffer;
|
||||
static Token *freelist;
|
||||
|
||||
Loc loc; // for error messages
|
||||
|
||||
unsigned char *base; // pointer to start of buffer
|
||||
unsigned char *end; // past end of buffer
|
||||
unsigned char *p; // current character
|
||||
Token token;
|
||||
Module *mod;
|
||||
int doDocComment; // collect doc comment information
|
||||
int anyToken; // !=0 means seen at least one token
|
||||
int commentToken; // !=0 means comments are TOKcomment's
|
||||
|
||||
Lexer(Module *mod,
|
||||
unsigned char *base, unsigned begoffset, unsigned endoffset,
|
||||
int doDocComment, int commentToken);
|
||||
|
||||
static void initKeywords();
|
||||
static Identifier *idPool(const char *s);
|
||||
static Identifier *uniqueId(const char *s);
|
||||
static Identifier *uniqueId(const char *s, int num);
|
||||
|
||||
TOK nextToken();
|
||||
TOK peekNext();
|
||||
TOK peekNext2();
|
||||
void scan(Token *t);
|
||||
Token *peek(Token *t);
|
||||
Token *peekPastParen(Token *t);
|
||||
unsigned escapeSequence();
|
||||
TOK wysiwygStringConstant(Token *t, int tc);
|
||||
TOK hexStringConstant(Token *t);
|
||||
#if DMDV2
|
||||
TOK delimitedStringConstant(Token *t);
|
||||
TOK tokenStringConstant(Token *t);
|
||||
#endif
|
||||
TOK escapeStringConstant(Token *t, int wide);
|
||||
TOK charConstant(Token *t, int wide);
|
||||
void stringPostfix(Token *t);
|
||||
unsigned wchar(unsigned u);
|
||||
TOK number(Token *t);
|
||||
TOK inreal(Token *t);
|
||||
void error(const char *format, ...) IS_PRINTF(2);
|
||||
void error(Loc loc, const char *format, ...) IS_PRINTF(3);
|
||||
void verror(Loc loc, const char *format, va_list ap);
|
||||
void pragma();
|
||||
unsigned decodeUTF();
|
||||
void getDocComment(Token *t, unsigned lineComment);
|
||||
|
||||
static int isValidIdentifier(char *p);
|
||||
static unsigned char *combineComments(unsigned char *c1, unsigned char *c2);
|
||||
};
|
||||
|
||||
#endif /* DMD_LEXER_H */
|
||||
54
dmd2/lib.h
Normal file
54
dmd2/lib.h
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2008 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_LIB_H
|
||||
#define DMD_LIB_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
struct ObjModule;
|
||||
|
||||
struct ObjSymbol
|
||||
{
|
||||
char *name;
|
||||
ObjModule *om;
|
||||
};
|
||||
|
||||
#include "arraytypes.h"
|
||||
|
||||
typedef ArrayBase<ObjModule> ObjModules;
|
||||
typedef ArrayBase<ObjSymbol> ObjSymbols;
|
||||
|
||||
struct Library
|
||||
{
|
||||
File *libfile;
|
||||
ObjModules objmodules; // ObjModule[]
|
||||
ObjSymbols objsymbols; // ObjSymbol[]
|
||||
|
||||
StringTable tab;
|
||||
|
||||
Library();
|
||||
void setFilename(char *dir, char *filename);
|
||||
void addObject(const char *module_name, void *buf, size_t buflen);
|
||||
void addLibrary(void *buf, size_t buflen);
|
||||
void write();
|
||||
|
||||
private:
|
||||
void addSymbol(ObjModule *om, char *name, int pickAny = 0);
|
||||
void scanObjModule(ObjModule *om);
|
||||
unsigned short numDictPages(unsigned padding);
|
||||
int FillDict(unsigned char *bucketsP, unsigned short uNumPages);
|
||||
void WriteLibToBuffer(OutBuffer *libbuf);
|
||||
};
|
||||
|
||||
#endif /* DMD_LIB_H */
|
||||
|
||||
449
dmd2/macro.c
Normal file
449
dmd2/macro.c
Normal file
@@ -0,0 +1,449 @@
|
||||
|
||||
// Copyright (c) 1999-2006 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
/* Simple macro text processor.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "rmem.h"
|
||||
#include "root.h"
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
#define isidstart(c) (isalpha(c) || (c) == '_')
|
||||
#define isidchar(c) (isalnum(c) || (c) == '_')
|
||||
|
||||
unsigned char *memdup(unsigned char *p, size_t len)
|
||||
{
|
||||
return (unsigned char *)memcpy(mem.malloc(len), p, len);
|
||||
}
|
||||
|
||||
Macro::Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen)
|
||||
{
|
||||
next = NULL;
|
||||
|
||||
#if 1
|
||||
this->name = name;
|
||||
this->namelen = namelen;
|
||||
|
||||
this->text = text;
|
||||
this->textlen = textlen;
|
||||
#else
|
||||
this->name = name;
|
||||
this->namelen = namelen;
|
||||
|
||||
this->text = text;
|
||||
this->textlen = textlen;
|
||||
#endif
|
||||
inuse = 0;
|
||||
}
|
||||
|
||||
|
||||
Macro *Macro::search(unsigned char *name, size_t namelen)
|
||||
{ Macro *table;
|
||||
|
||||
//printf("Macro::search(%.*s)\n", namelen, name);
|
||||
for (table = this; table; table = table->next)
|
||||
{
|
||||
if (table->namelen == namelen &&
|
||||
memcmp(table->name, name, namelen) == 0)
|
||||
{
|
||||
//printf("\tfound %d\n", table->textlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
Macro *Macro::define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen)
|
||||
{
|
||||
//printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text);
|
||||
|
||||
Macro *table;
|
||||
|
||||
//assert(ptable);
|
||||
for (table = *ptable; table; table = table->next)
|
||||
{
|
||||
if (table->namelen == namelen &&
|
||||
memcmp(table->name, name, namelen) == 0)
|
||||
{
|
||||
table->text = text;
|
||||
table->textlen = textlen;
|
||||
return table;
|
||||
}
|
||||
}
|
||||
table = new Macro(name, namelen, text, textlen);
|
||||
table->next = *ptable;
|
||||
*ptable = table;
|
||||
return table;
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
* Given buffer p[0..end], extract argument marg[0..marglen].
|
||||
* Params:
|
||||
* n 0: get entire argument
|
||||
* 1..9: get nth argument
|
||||
* -1: get 2nd through end
|
||||
*/
|
||||
|
||||
unsigned extractArgN(unsigned char *p, unsigned end, unsigned char **pmarg, unsigned *pmarglen, int n)
|
||||
{
|
||||
/* Scan forward for matching right parenthesis.
|
||||
* Nest parentheses.
|
||||
* Skip over $( and $)
|
||||
* Skip over "..." and '...' strings inside HTML tags.
|
||||
* Skip over <!-- ... --> comments.
|
||||
* Skip over previous macro insertions
|
||||
* Set marglen.
|
||||
*/
|
||||
unsigned parens = 1;
|
||||
unsigned char instring = 0;
|
||||
unsigned incomment = 0;
|
||||
unsigned intag = 0;
|
||||
unsigned inexp = 0;
|
||||
unsigned argn = 0;
|
||||
|
||||
unsigned v = 0;
|
||||
|
||||
Largstart:
|
||||
#if 1
|
||||
// Skip first space, if any, to find the start of the macro argument
|
||||
if (v < end && isspace(p[v]))
|
||||
v++;
|
||||
#else
|
||||
// Skip past spaces to find the start of the macro argument
|
||||
for (; v < end && isspace(p[v]); v++)
|
||||
;
|
||||
#endif
|
||||
*pmarg = p + v;
|
||||
|
||||
for (; v < end; v++)
|
||||
{ unsigned char c = p[v];
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case ',':
|
||||
if (!inexp && !instring && !incomment && parens == 1)
|
||||
{
|
||||
argn++;
|
||||
if (argn == 1 && n == -1)
|
||||
{ v++;
|
||||
goto Largstart;
|
||||
}
|
||||
if (argn == n)
|
||||
break;
|
||||
if (argn + 1 == n)
|
||||
{ v++;
|
||||
goto Largstart;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
case '(':
|
||||
if (!inexp && !instring && !incomment)
|
||||
parens++;
|
||||
continue;
|
||||
|
||||
case ')':
|
||||
if (!inexp && !instring && !incomment && --parens == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
if (!inexp && !incomment && intag)
|
||||
{
|
||||
if (c == instring)
|
||||
instring = 0;
|
||||
else if (!instring)
|
||||
instring = c;
|
||||
}
|
||||
continue;
|
||||
|
||||
case '<':
|
||||
if (!inexp && !instring && !incomment)
|
||||
{
|
||||
if (v + 6 < end &&
|
||||
p[v + 1] == '!' &&
|
||||
p[v + 2] == '-' &&
|
||||
p[v + 3] == '-')
|
||||
{
|
||||
incomment = 1;
|
||||
v += 3;
|
||||
}
|
||||
else if (v + 2 < end &&
|
||||
isalpha(p[v + 1]))
|
||||
intag = 1;
|
||||
}
|
||||
continue;
|
||||
|
||||
case '>':
|
||||
if (!inexp)
|
||||
intag = 0;
|
||||
continue;
|
||||
|
||||
case '-':
|
||||
if (!inexp &&
|
||||
!instring &&
|
||||
incomment &&
|
||||
v + 2 < end &&
|
||||
p[v + 1] == '-' &&
|
||||
p[v + 2] == '>')
|
||||
{
|
||||
incomment = 0;
|
||||
v += 2;
|
||||
}
|
||||
continue;
|
||||
|
||||
case 0xFF:
|
||||
if (v + 1 < end)
|
||||
{
|
||||
if (p[v + 1] == '{')
|
||||
inexp++;
|
||||
else if (p[v + 1] == '}')
|
||||
inexp--;
|
||||
}
|
||||
continue;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (argn == 0 && n == -1)
|
||||
*pmarg = p + v;
|
||||
*pmarglen = p + v - *pmarg;
|
||||
//printf("extractArg%d('%.*s') = '%.*s'\n", n, end, p, *pmarglen, *pmarg);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* Expand macro in place in buf.
|
||||
* Only look at the text in buf from start to end.
|
||||
*/
|
||||
|
||||
void Macro::expand(OutBuffer *buf, unsigned start, unsigned *pend,
|
||||
unsigned char *arg, unsigned arglen)
|
||||
{
|
||||
#if 0
|
||||
printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, *pend, arglen, arg);
|
||||
printf("Buf is: '%.*s'\n", *pend - start, buf->data + start);
|
||||
#endif
|
||||
|
||||
static int nest;
|
||||
if (nest > 100) // limit recursive expansion
|
||||
return;
|
||||
nest++;
|
||||
|
||||
unsigned end = *pend;
|
||||
assert(start <= end);
|
||||
assert(end <= buf->offset);
|
||||
|
||||
/* First pass - replace $0
|
||||
*/
|
||||
arg = memdup(arg, arglen);
|
||||
for (unsigned u = start; u + 1 < end; )
|
||||
{
|
||||
unsigned char *p = buf->data; // buf->data is not loop invariant
|
||||
|
||||
/* Look for $0, but not $$0, and replace it with arg.
|
||||
*/
|
||||
if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+'))
|
||||
{
|
||||
if (u > start && p[u - 1] == '$')
|
||||
{ // Don't expand $$0, but replace it with $0
|
||||
buf->remove(u - 1, 1);
|
||||
end--;
|
||||
u += 1; // now u is one past the closing '1'
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned char c = p[u + 1];
|
||||
int n = (c == '+') ? -1 : c - '0';
|
||||
|
||||
unsigned char *marg;
|
||||
unsigned marglen;
|
||||
extractArgN(arg, arglen, &marg, &marglen, n);
|
||||
if (marglen == 0)
|
||||
{ // Just remove macro invocation
|
||||
//printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
|
||||
buf->remove(u, 2);
|
||||
end -= 2;
|
||||
}
|
||||
else if (c == '+')
|
||||
{
|
||||
// Replace '$+' with 'arg'
|
||||
//printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
|
||||
buf->remove(u, 2);
|
||||
buf->insert(u, marg, marglen);
|
||||
end += marglen - 2;
|
||||
|
||||
// Scan replaced text for further expansion
|
||||
unsigned mend = u + marglen;
|
||||
expand(buf, u, &mend, NULL, 0);
|
||||
end += mend - (u + marglen);
|
||||
u = mend;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replace '$1' with '\xFF{arg\xFF}'
|
||||
//printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], marglen, marg);
|
||||
buf->data[u] = 0xFF;
|
||||
buf->data[u + 1] = '{';
|
||||
buf->insert(u + 2, marg, marglen);
|
||||
buf->insert(u + 2 + marglen, "\xFF}", 2);
|
||||
end += -2 + 2 + marglen + 2;
|
||||
|
||||
// Scan replaced text for further expansion
|
||||
unsigned mend = u + 2 + marglen;
|
||||
expand(buf, u + 2, &mend, NULL, 0);
|
||||
end += mend - (u + 2 + marglen);
|
||||
u = mend;
|
||||
}
|
||||
//printf("u = %d, end = %d\n", u, end);
|
||||
//printf("#%.*s#\n", end, &buf->data[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
u++;
|
||||
}
|
||||
|
||||
/* Second pass - replace other macros
|
||||
*/
|
||||
for (unsigned u = start; u + 4 < end; )
|
||||
{
|
||||
unsigned char *p = buf->data; // buf->data is not loop invariant
|
||||
|
||||
/* A valid start of macro expansion is $(c, where c is
|
||||
* an id start character, and not $$(c.
|
||||
*/
|
||||
if (p[u] == '$' && p[u + 1] == '(' && isidstart(p[u + 2]))
|
||||
{
|
||||
//printf("\tfound macro start '%c'\n", p[u + 2]);
|
||||
unsigned char *name = p + u + 2;
|
||||
unsigned namelen = 0;
|
||||
|
||||
unsigned char *marg;
|
||||
unsigned marglen;
|
||||
|
||||
unsigned v;
|
||||
/* Scan forward to find end of macro name and
|
||||
* beginning of macro argument (marg).
|
||||
*/
|
||||
for (v = u + 2; v < end; v++)
|
||||
{ unsigned char c = p[v];
|
||||
|
||||
if (!isidchar(c))
|
||||
{ // We've gone past the end of the macro name.
|
||||
namelen = v - (u + 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
v += extractArgN(p + v, end - v, &marg, &marglen, 0);
|
||||
assert(v <= end);
|
||||
|
||||
if (v < end)
|
||||
{ // v is on the closing ')'
|
||||
if (u > start && p[u - 1] == '$')
|
||||
{ // Don't expand $$(NAME), but replace it with $(NAME)
|
||||
buf->remove(u - 1, 1);
|
||||
end--;
|
||||
u = v; // now u is one past the closing ')'
|
||||
continue;
|
||||
}
|
||||
|
||||
Macro *m = search(name, namelen);
|
||||
if (m)
|
||||
{
|
||||
#if 0
|
||||
if (m->textlen && m->text[0] == ' ')
|
||||
{ m->text++;
|
||||
m->textlen--;
|
||||
}
|
||||
#endif
|
||||
if (m->inuse && marglen == 0)
|
||||
{ // Remove macro invocation
|
||||
buf->remove(u, v + 1 - u);
|
||||
end -= v + 1 - u;
|
||||
}
|
||||
else if (m->inuse && arglen == marglen && memcmp(arg, marg, arglen) == 0)
|
||||
{ // Recursive expansion; just leave in place
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", m->namelen, m->name, marglen, marg, m->textlen, m->text);
|
||||
#if 1
|
||||
marg = memdup(marg, marglen);
|
||||
// Insert replacement text
|
||||
buf->spread(v + 1, 2 + m->textlen + 2);
|
||||
buf->data[v + 1] = 0xFF;
|
||||
buf->data[v + 2] = '{';
|
||||
memcpy(buf->data + v + 3, m->text, m->textlen);
|
||||
buf->data[v + 3 + m->textlen] = 0xFF;
|
||||
buf->data[v + 3 + m->textlen + 1] = '}';
|
||||
|
||||
end += 2 + m->textlen + 2;
|
||||
|
||||
// Scan replaced text for further expansion
|
||||
m->inuse++;
|
||||
unsigned mend = v + 1 + 2+m->textlen+2;
|
||||
expand(buf, v + 1, &mend, marg, marglen);
|
||||
end += mend - (v + 1 + 2+m->textlen+2);
|
||||
m->inuse--;
|
||||
|
||||
buf->remove(u, v + 1 - u);
|
||||
end -= v + 1 - u;
|
||||
u += mend - (v + 1);
|
||||
#else
|
||||
// Insert replacement text
|
||||
buf->insert(v + 1, m->text, m->textlen);
|
||||
end += m->textlen;
|
||||
|
||||
// Scan replaced text for further expansion
|
||||
m->inuse++;
|
||||
unsigned mend = v + 1 + m->textlen;
|
||||
expand(buf, v + 1, &mend, marg, marglen);
|
||||
end += mend - (v + 1 + m->textlen);
|
||||
m->inuse--;
|
||||
|
||||
buf->remove(u, v + 1 - u);
|
||||
end -= v + 1 - u;
|
||||
u += mend - (v + 1);
|
||||
#endif
|
||||
mem.free(marg);
|
||||
//printf("u = %d, end = %d\n", u, end);
|
||||
//printf("#%.*s#\n", end - u, &buf->data[u]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replace $(NAME) with nothing
|
||||
buf->remove(u, v + 1 - u);
|
||||
end -= (v + 1 - u);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
u++;
|
||||
}
|
||||
mem.free(arg);
|
||||
*pend = end;
|
||||
nest--;
|
||||
}
|
||||
45
dmd2/macro.h
Normal file
45
dmd2/macro.h
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_MACRO_H
|
||||
#define DMD_MACRO_H 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "root.h"
|
||||
|
||||
|
||||
struct Macro
|
||||
{
|
||||
private:
|
||||
Macro *next; // next in list
|
||||
|
||||
unsigned char *name; // macro name
|
||||
size_t namelen; // length of macro name
|
||||
|
||||
unsigned char *text; // macro replacement text
|
||||
size_t textlen; // length of replacement text
|
||||
|
||||
int inuse; // macro is in use (don't expand)
|
||||
|
||||
Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen);
|
||||
Macro *search(unsigned char *name, size_t namelen);
|
||||
|
||||
public:
|
||||
static Macro *define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen);
|
||||
|
||||
void expand(OutBuffer *buf, unsigned start, unsigned *pend,
|
||||
unsigned char *arg, unsigned arglen);
|
||||
};
|
||||
|
||||
#endif
|
||||
303
dmd2/mangle.c
Normal file
303
dmd2/mangle.c
Normal file
@@ -0,0 +1,303 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2010 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "root.h"
|
||||
|
||||
#include "init.h"
|
||||
#include "declaration.h"
|
||||
#include "aggregate.h"
|
||||
#include "mtype.h"
|
||||
#include "attrib.h"
|
||||
#include "template.h"
|
||||
#include "id.h"
|
||||
#include "module.h"
|
||||
|
||||
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
|
||||
char *cpp_mangle(Dsymbol *s);
|
||||
#endif
|
||||
|
||||
char *mangle(Declaration *sthis)
|
||||
{
|
||||
OutBuffer buf;
|
||||
char *id;
|
||||
Dsymbol *s;
|
||||
|
||||
//printf("::mangle(%s)\n", sthis->toChars());
|
||||
s = sthis;
|
||||
do
|
||||
{
|
||||
//printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent);
|
||||
if (s->ident)
|
||||
{
|
||||
FuncDeclaration *fd = s->isFuncDeclaration();
|
||||
if (s != sthis && fd)
|
||||
{
|
||||
id = mangle(fd);
|
||||
buf.prependstring(id);
|
||||
goto L1;
|
||||
}
|
||||
else
|
||||
{
|
||||
id = s->ident->toChars();
|
||||
int len = strlen(id);
|
||||
char tmp[sizeof(len) * 3 + 1];
|
||||
buf.prependstring(id);
|
||||
sprintf(tmp, "%d", len);
|
||||
buf.prependstring(tmp);
|
||||
}
|
||||
}
|
||||
else
|
||||
buf.prependstring("0");
|
||||
s = s->parent;
|
||||
} while (s);
|
||||
|
||||
// buf.prependstring("_D");
|
||||
L1:
|
||||
//printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null");
|
||||
//printf("sthis->type = %s\n", sthis->type->toChars());
|
||||
FuncDeclaration *fd = sthis->isFuncDeclaration();
|
||||
if (fd && (fd->needThis() || fd->isNested()))
|
||||
buf.writeByte(Type::needThisPrefix());
|
||||
if (sthis->type->deco)
|
||||
buf.writestring(sthis->type->deco);
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (!fd->inferRetType)
|
||||
printf("%s\n", fd->toChars());
|
||||
#endif
|
||||
assert(fd && fd->inferRetType);
|
||||
}
|
||||
|
||||
id = buf.toChars();
|
||||
buf.data = NULL;
|
||||
return id;
|
||||
}
|
||||
|
||||
char *Declaration::mangle()
|
||||
#if __DMC__
|
||||
__out(result)
|
||||
{
|
||||
int len = strlen(result);
|
||||
|
||||
assert(len > 0);
|
||||
//printf("mangle: '%s' => '%s'\n", toChars(), result);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
assert(result[i] == '_' ||
|
||||
result[i] == '@' ||
|
||||
isalnum(result[i]) || result[i] & 0x80);
|
||||
}
|
||||
}
|
||||
__body
|
||||
#endif
|
||||
{
|
||||
//printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", this, toChars(), parent ? parent->toChars() : "null", linkage);
|
||||
if (!parent || parent->isModule() || linkage == LINKcpp) // if at global scope
|
||||
{
|
||||
// If it's not a D declaration, no mangling
|
||||
switch (linkage)
|
||||
{
|
||||
case LINKd:
|
||||
break;
|
||||
|
||||
#if IN_LLVM
|
||||
case LINKintrinsic:
|
||||
#endif
|
||||
case LINKc:
|
||||
case LINKwindows:
|
||||
case LINKpascal:
|
||||
return ident->toChars();
|
||||
|
||||
case LINKcpp:
|
||||
#if CPP_MANGLE
|
||||
return cpp_mangle(this);
|
||||
#else
|
||||
// Windows C++ mangling is done by C++ back end
|
||||
return ident->toChars();
|
||||
#endif
|
||||
|
||||
case LINKdefault:
|
||||
error("forward declaration");
|
||||
return ident->toChars();
|
||||
|
||||
default:
|
||||
fprintf(stdmsg, "'%s', linkage = %d\n", toChars(), linkage);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
char *p = ::mangle(this);
|
||||
OutBuffer buf;
|
||||
buf.writestring("_D");
|
||||
buf.writestring(p);
|
||||
p = buf.toChars();
|
||||
buf.data = NULL;
|
||||
//printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d) = %s\n", this, toChars(), parent ? parent->toChars() : "null", linkage, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
char *FuncDeclaration::mangle()
|
||||
#if __DMC__
|
||||
__out(result)
|
||||
{
|
||||
assert(strlen(result) > 0);
|
||||
}
|
||||
__body
|
||||
#endif
|
||||
{
|
||||
if (isMain())
|
||||
return (char *)"_Dmain";
|
||||
|
||||
if (isWinMain() || isDllMain() || ident == Id::tls_get_addr)
|
||||
return ident->toChars();
|
||||
|
||||
assert(this);
|
||||
return Declaration::mangle();
|
||||
}
|
||||
|
||||
char *StructDeclaration::mangle()
|
||||
{
|
||||
//printf("StructDeclaration::mangle() '%s'\n", toChars());
|
||||
return Dsymbol::mangle();
|
||||
}
|
||||
|
||||
|
||||
char *TypedefDeclaration::mangle()
|
||||
{
|
||||
//printf("TypedefDeclaration::mangle() '%s'\n", toChars());
|
||||
return Dsymbol::mangle();
|
||||
}
|
||||
|
||||
|
||||
char *ClassDeclaration::mangle()
|
||||
{
|
||||
Dsymbol *parentsave = parent;
|
||||
|
||||
//printf("ClassDeclaration::mangle() %s.%s\n", parent->toChars(), toChars());
|
||||
|
||||
/* These are reserved to the compiler, so keep simple
|
||||
* names for them.
|
||||
*/
|
||||
if (ident == Id::Exception)
|
||||
{ if (parent->ident == Id::object)
|
||||
parent = NULL;
|
||||
}
|
||||
else if (ident == Id::TypeInfo ||
|
||||
// ident == Id::Exception ||
|
||||
ident == Id::TypeInfo_Struct ||
|
||||
ident == Id::TypeInfo_Class ||
|
||||
ident == Id::TypeInfo_Typedef ||
|
||||
ident == Id::TypeInfo_Tuple ||
|
||||
this == object ||
|
||||
this == classinfo ||
|
||||
#if !MODULEINFO_IS_STRUCT
|
||||
this == Module::moduleinfo ||
|
||||
#endif
|
||||
memcmp(ident->toChars(), "TypeInfo_", 9) == 0
|
||||
)
|
||||
parent = NULL;
|
||||
|
||||
char *id = Dsymbol::mangle();
|
||||
parent = parentsave;
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
char *TemplateInstance::mangle()
|
||||
{
|
||||
OutBuffer buf;
|
||||
|
||||
#if 0
|
||||
printf("TemplateInstance::mangle() %p %s", this, toChars());
|
||||
if (parent)
|
||||
printf(" parent = %s %s", parent->kind(), parent->toChars());
|
||||
printf("\n");
|
||||
#endif
|
||||
char *id = ident ? ident->toChars() : toChars();
|
||||
if (!tempdecl)
|
||||
error("is not defined");
|
||||
else
|
||||
{
|
||||
Dsymbol *par = isnested || isTemplateMixin() ? parent : tempdecl->parent;
|
||||
if (par)
|
||||
{
|
||||
char *p = par->mangle();
|
||||
if (p[0] == '_' && p[1] == 'D')
|
||||
p += 2;
|
||||
buf.writestring(p);
|
||||
}
|
||||
}
|
||||
buf.printf("%zu%s", strlen(id), id);
|
||||
id = buf.toChars();
|
||||
buf.data = NULL;
|
||||
//printf("TemplateInstance::mangle() %s = %s\n", toChars(), id);
|
||||
return id;
|
||||
}
|
||||
|
||||
#if IN_LLVM
|
||||
char *TemplateMixin::mangle()
|
||||
{
|
||||
OutBuffer buf;
|
||||
char *id;
|
||||
|
||||
#if 0
|
||||
printf("TemplateMixin::mangle() %s", toChars());
|
||||
if (parent)
|
||||
printf(" parent = %s %s", parent->kind(), parent->toChars());
|
||||
printf("\n");
|
||||
#endif
|
||||
id = ident ? ident->toChars() : toChars();
|
||||
if (parent)
|
||||
{
|
||||
char *p = parent->mangle();
|
||||
if (p[0] == '_' && p[1] == 'D')
|
||||
p += 2;
|
||||
buf.writestring(p);
|
||||
}
|
||||
buf.printf("%zu%s", strlen(id), id);
|
||||
id = buf.toChars();
|
||||
buf.data = NULL;
|
||||
//printf("TemplateMixin::mangle() %s = %s\n", toChars(), id);
|
||||
return id;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *Dsymbol::mangle()
|
||||
{
|
||||
OutBuffer buf;
|
||||
char *id;
|
||||
|
||||
#if 0
|
||||
printf("Dsymbol::mangle() '%s'", toChars());
|
||||
if (parent)
|
||||
printf(" parent = %s %s", parent->kind(), parent->toChars());
|
||||
printf("\n");
|
||||
#endif
|
||||
id = ident ? ident->toChars() : toChars();
|
||||
if (parent)
|
||||
{
|
||||
char *p = parent->mangle();
|
||||
if (p[0] == '_' && p[1] == 'D')
|
||||
p += 2;
|
||||
buf.writestring(p);
|
||||
}
|
||||
buf.printf("%zu%s", strlen(id), id);
|
||||
id = buf.toChars();
|
||||
buf.data = NULL;
|
||||
//printf("Dsymbol::mangle() %s = %s\n", toChars(), id);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
1605
dmd2/mars.c
Normal file
1605
dmd2/mars.c
Normal file
File diff suppressed because it is too large
Load Diff
503
dmd2/mars.h
Normal file
503
dmd2/mars.h
Normal file
@@ -0,0 +1,503 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_MARS_H
|
||||
#define DMD_MARS_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
/*
|
||||
It is very important to use version control macros correctly - the
|
||||
idea is that host and target are independent. If these are done
|
||||
correctly, cross compilers can be built.
|
||||
The host compiler and host operating system are also different,
|
||||
and are predefined by the host compiler. The ones used in
|
||||
dmd are:
|
||||
|
||||
Macros defined by the compiler, not the code:
|
||||
|
||||
Compiler:
|
||||
__DMC__ Digital Mars compiler
|
||||
_MSC_VER Microsoft compiler
|
||||
__GNUC__ Gnu compiler
|
||||
__clang__ Clang compiler
|
||||
|
||||
Host operating system:
|
||||
_WIN32 Microsoft NT, Windows 95, Windows 98, Win32s,
|
||||
Windows 2000, Win XP, Vista
|
||||
_WIN64 Windows for AMD64
|
||||
linux Linux
|
||||
__APPLE__ Mac OSX
|
||||
__FreeBSD__ FreeBSD
|
||||
__OpenBSD__ OpenBSD
|
||||
__sun&&__SVR4 Solaris, OpenSolaris (yes, both macros are necessary)
|
||||
|
||||
For the target systems, there are the target operating system and
|
||||
the target object file format:
|
||||
|
||||
Target operating system:
|
||||
TARGET_WINDOS Covers 32 bit windows and 64 bit windows
|
||||
TARGET_LINUX Covers 32 and 64 bit linux
|
||||
TARGET_OSX Covers 32 and 64 bit Mac OSX
|
||||
TARGET_FREEBSD Covers 32 and 64 bit FreeBSD
|
||||
TARGET_OPENBSD Covers 32 and 64 bit OpenBSD
|
||||
TARGET_SOLARIS Covers 32 and 64 bit Solaris
|
||||
TARGET_NET Covers .Net
|
||||
|
||||
It is expected that the compiler for each platform will be able
|
||||
to generate 32 and 64 bit code from the same compiler binary.
|
||||
|
||||
Target object module format:
|
||||
OMFOBJ Intel Object Module Format, used on Windows
|
||||
ELFOBJ Elf Object Module Format, used on linux, FreeBSD, OpenBSD and Solaris
|
||||
MACHOBJ Mach-O Object Module Format, used on Mac OSX
|
||||
|
||||
There are currently no macros for byte endianness order.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __DMC__
|
||||
#ifdef DEBUG
|
||||
#undef assert
|
||||
#define assert(e) (static_cast<void>((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt())))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define UNITTEST 1
|
||||
#endif
|
||||
void unittests();
|
||||
|
||||
#ifndef IS_PRINTF
|
||||
# ifdef __GNUC__
|
||||
# define IS_PRINTF(FMTARG) __attribute((__format__ (__printf__, (FMTARG), (FMTARG)+1) ))
|
||||
# else
|
||||
# define IS_PRINTF(FMTARG)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef IN_GCC
|
||||
/* Changes for the GDC compiler by David Friedman */
|
||||
#endif
|
||||
|
||||
#define DMDV1 0
|
||||
#define DMDV2 1 // Version 2.0 features
|
||||
#define BREAKABI 1 // 0 if not ready to break the ABI just yet
|
||||
#define STRUCTTHISREF DMDV2 // if 'this' for struct is a reference, not a pointer
|
||||
#define SNAN_DEFAULT_INIT DMDV2 // if floats are default initialized to signalling NaN
|
||||
#define SARRAYVALUE DMDV2 // static arrays are value types
|
||||
#define MODULEINFO_IS_STRUCT DMDV2 // if ModuleInfo is a struct rather than a class
|
||||
|
||||
// Set if C++ mangling is done by the front end
|
||||
#define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS))
|
||||
|
||||
/* Other targets are TARGET_LINUX, TARGET_OSX, TARGET_FREEBSD, TARGET_OPENBSD and
|
||||
* TARGET_SOLARIS, which are
|
||||
* set on the command line via the compiler makefile.
|
||||
*/
|
||||
|
||||
#if _WIN32
|
||||
#ifndef TARGET_WINDOS
|
||||
#define TARGET_WINDOS 1 // Windows dmd generates Windows targets
|
||||
#endif
|
||||
#ifndef OMFOBJ
|
||||
#define OMFOBJ TARGET_WINDOS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
|
||||
#ifndef ELFOBJ
|
||||
#define ELFOBJ 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if TARGET_OSX
|
||||
#ifndef MACHOBJ
|
||||
#define MACHOBJ 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
struct OutBuffer;
|
||||
|
||||
// Can't include arraytypes.h here, need to declare these directly.
|
||||
template <typename TYPE> struct ArrayBase;
|
||||
typedef ArrayBase<struct Identifier> Identifiers;
|
||||
typedef ArrayBase<char> Strings;
|
||||
|
||||
#if IN_LLVM
|
||||
enum ARCH
|
||||
{
|
||||
ARCHinvalid,
|
||||
ARCHx86,
|
||||
ARCHx86_64,
|
||||
ARCHppc,
|
||||
ARCHppc_64,
|
||||
ARCHarm,
|
||||
ARCHthumb
|
||||
};
|
||||
enum OUTPUTFLAG
|
||||
{
|
||||
OUTPUTFLAGno,
|
||||
OUTPUTFLAGdefault, // for the .o default
|
||||
OUTPUTFLAGset // for -output
|
||||
};
|
||||
|
||||
enum OS
|
||||
{
|
||||
OSinvalid,
|
||||
OSLinux,
|
||||
OSHaiku,
|
||||
OSWindows,
|
||||
OSMacOSX,
|
||||
OSFreeBSD,
|
||||
OSSolaris,
|
||||
};
|
||||
|
||||
typedef unsigned char ubyte;
|
||||
#endif
|
||||
|
||||
// Put command line switches in here
|
||||
struct Param
|
||||
{
|
||||
bool obj; // write object file
|
||||
bool link; // perform link
|
||||
bool verbose; // verbose compile
|
||||
bool vtls; // identify thread local variables
|
||||
ubyte symdebug; // insert debug symbolic information
|
||||
#if !IN_LLVM
|
||||
// LDC uses a different mechanism
|
||||
bool optimize; // run optimizer
|
||||
char optimizeLevel; // optimization level
|
||||
#endif
|
||||
ARCH cpu; // target CPU
|
||||
OS os;
|
||||
bool alwaysframe; // always emit standard stack frame
|
||||
char map; // generate linker .map file
|
||||
bool isLE; // generate little endian code
|
||||
bool is64bit; // generate 64 bit code
|
||||
bool useDeprecated; // allow use of deprecated features
|
||||
bool useAssert; // generate runtime code for assert()'s
|
||||
bool useInvariants; // generate class invariant checks
|
||||
bool useIn; // generate precondition checks
|
||||
bool useOut; // generate postcondition checks
|
||||
bool useArrayBounds; // generate array bounds checks
|
||||
bool useSwitchError; // check for switches without a default
|
||||
bool useUnitTests; // generate unittest code
|
||||
bool useInline; // inline expand functions
|
||||
ubyte warnings; // enable warnings
|
||||
ubyte Dversion; // D version number
|
||||
bool ignoreUnsupportedPragmas; // rather than error on them
|
||||
bool enforcePropertySyntax;
|
||||
|
||||
char *argv0; // program name
|
||||
Strings *imppath; // array of char*'s of where to look for import modules
|
||||
Strings *fileImppath; // array of char*'s of where to look for file import modules
|
||||
char *objdir; // .obj file output directory
|
||||
char *objname; // .obj file output name
|
||||
|
||||
bool doDocComments; // process embedded documentation comments
|
||||
char *docdir; // write documentation file to docdir directory
|
||||
char *docname; // write documentation file to docname
|
||||
Strings *ddocfiles; // macro include files for Ddoc
|
||||
|
||||
bool doHdrGeneration; // process embedded documentation comments
|
||||
char *hdrdir; // write 'header' file to docdir directory
|
||||
char *hdrname; // write 'header' file to docname
|
||||
|
||||
bool doXGeneration; // write JSON file
|
||||
char *xfilename; // write JSON file to xfilename
|
||||
|
||||
unsigned debuglevel; // debug level
|
||||
Strings *debugids; // debug identifiers
|
||||
|
||||
unsigned versionlevel; // version level
|
||||
Strings *versionids; // version identifiers
|
||||
|
||||
bool dump_source;
|
||||
|
||||
Strings *defaultlibnames; // default libraries for non-debug builds
|
||||
Strings *debuglibnames; // default libraries for debug builds
|
||||
|
||||
char *moduleDepsFile; // filename for deps output
|
||||
OutBuffer *moduleDeps; // contents to be written to deps file
|
||||
|
||||
// Hidden debug switches
|
||||
bool debuga;
|
||||
bool debugb;
|
||||
bool debugc;
|
||||
bool debugf;
|
||||
bool debugr;
|
||||
bool debugw;
|
||||
bool debugx;
|
||||
bool debugy;
|
||||
|
||||
bool run; // run resulting executable
|
||||
|
||||
// Linker stuff
|
||||
Strings *objfiles;
|
||||
Strings *linkswitches;
|
||||
Strings *libfiles;
|
||||
char *deffile;
|
||||
char *resfile;
|
||||
char *exefile;
|
||||
char *mapfile;
|
||||
#if IN_LLVM
|
||||
// LDC stuff
|
||||
OUTPUTFLAG output_ll;
|
||||
OUTPUTFLAG output_bc;
|
||||
OUTPUTFLAG output_s;
|
||||
OUTPUTFLAG output_o;
|
||||
bool llvmAnnotate;
|
||||
bool useInlineAsm;
|
||||
bool verbose_cg;
|
||||
bool useAvailableExternally;
|
||||
|
||||
// target stuff
|
||||
const char* llvmArch;
|
||||
const char *targetTriple;
|
||||
const char *dataLayout;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Global
|
||||
{
|
||||
const char *mars_ext;
|
||||
const char *sym_ext;
|
||||
const char *obj_ext;
|
||||
#if IN_LLVM
|
||||
#if _WIN32
|
||||
char *obj_ext_alt;
|
||||
#endif
|
||||
char *ll_ext;
|
||||
char *bc_ext;
|
||||
char *s_ext;
|
||||
#endif
|
||||
const char *lib_ext;
|
||||
const char *dll_ext;
|
||||
const char *doc_ext; // for Ddoc generated files
|
||||
const char *ddoc_ext; // for Ddoc macro include files
|
||||
const char *hdr_ext; // for D 'header' import files
|
||||
const char *json_ext; // for JSON files
|
||||
const char *map_ext; // for .map files
|
||||
const char *copyright;
|
||||
const char *written;
|
||||
Strings *path; // Array of char*'s which form the import lookup path
|
||||
Strings *filePath; // Array of char*'s which form the file import lookup path
|
||||
int structalign;
|
||||
const char *version;
|
||||
#if IN_LLVM
|
||||
char *ldc_version;
|
||||
char *llvm_version;
|
||||
#endif
|
||||
|
||||
Param params;
|
||||
unsigned errors; // number of errors reported so far
|
||||
unsigned warnings; // number of warnings reported so far
|
||||
unsigned gag; // !=0 means gag reporting of errors & warnings
|
||||
unsigned gaggedErrors; // number of errors reported while gagged
|
||||
|
||||
// Start gagging. Return the current number of gagged errors
|
||||
unsigned startGagging();
|
||||
|
||||
/* End gagging, restoring the old gagged state.
|
||||
* Return true if errors occured while gagged.
|
||||
*/
|
||||
bool endGagging(unsigned oldGagged);
|
||||
|
||||
Global();
|
||||
};
|
||||
|
||||
extern Global global;
|
||||
|
||||
/* Set if Windows Structured Exception Handling C extensions are supported.
|
||||
* Apparently, VC has dropped support for these?
|
||||
*/
|
||||
#define WINDOWS_SEH (_WIN32 && __DMC__)
|
||||
|
||||
|
||||
#ifdef __DMC__
|
||||
typedef _Complex long double complex_t;
|
||||
#else
|
||||
#ifndef IN_GCC
|
||||
#include "complex_t.h"
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
//#include "complex.h"//This causes problems with include the c++ <complex> and not the C "complex.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Be careful not to care about sign when using dinteger_t
|
||||
//typedef uint64_t integer_t;
|
||||
typedef uint64_t dinteger_t; // use this instead of integer_t to
|
||||
// avoid conflicts with system #include's
|
||||
|
||||
// Signed and unsigned variants
|
||||
typedef int64_t sinteger_t;
|
||||
typedef uint64_t uinteger_t;
|
||||
|
||||
typedef int8_t d_int8;
|
||||
typedef uint8_t d_uns8;
|
||||
typedef int16_t d_int16;
|
||||
typedef uint16_t d_uns16;
|
||||
typedef int32_t d_int32;
|
||||
typedef uint32_t d_uns32;
|
||||
typedef int64_t d_int64;
|
||||
typedef uint64_t d_uns64;
|
||||
|
||||
typedef float d_float32;
|
||||
typedef double d_float64;
|
||||
typedef long double d_float80;
|
||||
|
||||
typedef d_uns8 d_char;
|
||||
typedef d_uns16 d_wchar;
|
||||
typedef d_uns32 d_dchar;
|
||||
|
||||
#ifdef IN_GCC
|
||||
#include "d-gcc-real.h"
|
||||
#else
|
||||
typedef long double real_t;
|
||||
#endif
|
||||
|
||||
// Modify OutBuffer::writewchar to write the correct size of wchar
|
||||
#if _WIN32
|
||||
#define writewchar writeword
|
||||
#else
|
||||
// This needs a configuration test...
|
||||
#define writewchar write4
|
||||
#endif
|
||||
|
||||
#ifdef IN_GCC
|
||||
#include "d-gcc-complex_t.h"
|
||||
#endif
|
||||
|
||||
struct Module;
|
||||
|
||||
//typedef unsigned Loc; // file location
|
||||
struct Loc
|
||||
{
|
||||
const char *filename;
|
||||
unsigned linnum;
|
||||
|
||||
Loc()
|
||||
{
|
||||
linnum = 0;
|
||||
filename = NULL;
|
||||
}
|
||||
|
||||
Loc(int x)
|
||||
{
|
||||
linnum = x;
|
||||
filename = NULL;
|
||||
}
|
||||
|
||||
Loc(Module *mod, unsigned linnum);
|
||||
|
||||
char *toChars();
|
||||
bool equals(const Loc& loc);
|
||||
};
|
||||
|
||||
#ifndef GCC_SAFE_DMD
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define INTERFACE_OFFSET 0 // if 1, put classinfo as first entry
|
||||
// in interface vtbl[]'s
|
||||
#define INTERFACE_VIRTUAL 0 // 1 means if an interface appears
|
||||
// in the inheritance graph multiple
|
||||
// times, only one is used
|
||||
|
||||
enum LINK
|
||||
{
|
||||
LINKdefault,
|
||||
LINKd,
|
||||
LINKc,
|
||||
LINKcpp,
|
||||
LINKwindows,
|
||||
LINKpascal,
|
||||
|
||||
#if IN_LLVM
|
||||
LINKintrinsic,
|
||||
#endif
|
||||
};
|
||||
|
||||
enum DYNCAST
|
||||
{
|
||||
DYNCAST_OBJECT,
|
||||
DYNCAST_EXPRESSION,
|
||||
DYNCAST_DSYMBOL,
|
||||
DYNCAST_TYPE,
|
||||
DYNCAST_IDENTIFIER,
|
||||
DYNCAST_TUPLE,
|
||||
};
|
||||
|
||||
enum MATCH
|
||||
{
|
||||
MATCHnomatch, // no match
|
||||
MATCHconvert, // match with conversions
|
||||
#if DMDV2
|
||||
MATCHconst, // match with conversion to const
|
||||
#endif
|
||||
MATCHexact // exact match
|
||||
};
|
||||
|
||||
typedef uint64_t StorageClass;
|
||||
|
||||
|
||||
void warning(Loc loc, const char *format, ...) IS_PRINTF(2);
|
||||
void error(Loc loc, const char *format, ...) IS_PRINTF(2);
|
||||
void errorSupplemental(Loc loc, const char *format, ...);
|
||||
void verror(Loc loc, const char *format, va_list);
|
||||
void vwarning(Loc loc, const char *format, va_list);
|
||||
void verrorSupplemental(Loc loc, const char *format, va_list);
|
||||
void fatal();
|
||||
void err_nomem();
|
||||
#if IN_LLVM
|
||||
void inifile(char *argv0, const char *inifile);
|
||||
#else
|
||||
int runLINK();
|
||||
void deleteExeFile();
|
||||
int runProgram();
|
||||
const char *inifile(const char *argv0, const char *inifile);
|
||||
#endif
|
||||
void halt();
|
||||
#if !IN_LLVM
|
||||
void util_progress();
|
||||
#endif
|
||||
|
||||
/*** Where to send error messages ***/
|
||||
#if IN_GCC || IN_LLVM
|
||||
#define stdmsg stderr
|
||||
#else
|
||||
#define stdmsg stderr
|
||||
#endif
|
||||
|
||||
#if !IN_LLVM
|
||||
struct Dsymbol;
|
||||
struct Library;
|
||||
struct File;
|
||||
void obj_start(char *srcfile);
|
||||
void obj_end(Library *library, File *objfile);
|
||||
void obj_append(Dsymbol *s);
|
||||
void obj_write_deferred(Library *library);
|
||||
#endif
|
||||
|
||||
const char *importHint(const char *s);
|
||||
|
||||
#endif /* DMD_MARS_H */
|
||||
1365
dmd2/module.c
Normal file
1365
dmd2/module.c
Normal file
File diff suppressed because it is too large
Load Diff
232
dmd2/module.h
Normal file
232
dmd2/module.h
Normal file
@@ -0,0 +1,232 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2008 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_MODULE_H
|
||||
#define DMD_MODULE_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
#include "root.h"
|
||||
#include "dsymbol.h"
|
||||
|
||||
struct ModuleInfoDeclaration;
|
||||
struct ClassDeclaration;
|
||||
struct ModuleDeclaration;
|
||||
struct Macro;
|
||||
struct Escape;
|
||||
struct VarDeclaration;
|
||||
struct Library;
|
||||
|
||||
// Back end
|
||||
#if IN_LLVM
|
||||
class Ir;
|
||||
struct DValue;
|
||||
typedef DValue elem;
|
||||
namespace llvm {
|
||||
class LLVMContext;
|
||||
class Module;
|
||||
class GlobalVariable;
|
||||
class StructType;
|
||||
}
|
||||
#else
|
||||
|
||||
#ifdef IN_GCC
|
||||
union tree_node; typedef union tree_node elem;
|
||||
#else
|
||||
struct elem;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct Package : ScopeDsymbol
|
||||
{
|
||||
Package(Identifier *ident);
|
||||
const char *kind();
|
||||
|
||||
static DsymbolTable *resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg);
|
||||
|
||||
Package *isPackage() { return this; }
|
||||
|
||||
virtual void semantic(Scope *sc) { }
|
||||
};
|
||||
|
||||
struct Module : Package
|
||||
{
|
||||
static Module *rootModule;
|
||||
static DsymbolTable *modules; // symbol table of all modules
|
||||
static Modules amodules; // array of all modules
|
||||
static Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them
|
||||
static unsigned dprogress; // progress resolving the deferred list
|
||||
static void init();
|
||||
|
||||
static AggregateDeclaration *moduleinfo;
|
||||
|
||||
const char *arg; // original argument name
|
||||
ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration
|
||||
File *srcfile; // input source file
|
||||
File *objfile; // output .obj file
|
||||
File *hdrfile; // 'header' file
|
||||
File *symfile; // output symbol file
|
||||
File *docfile; // output documentation file
|
||||
|
||||
unsigned errors; // if any errors in file
|
||||
unsigned numlines; // number of lines in source file
|
||||
int isHtml; // if it is an HTML file
|
||||
int isDocFile; // if it is a documentation input file, not D source
|
||||
int needmoduleinfo;
|
||||
#ifdef IN_GCC
|
||||
int strictlyneedmoduleinfo;
|
||||
#endif
|
||||
|
||||
int selfimports; // 0: don't know, 1: does not, 2: does
|
||||
int selfImports(); // returns !=0 if module imports itself
|
||||
|
||||
int insearch;
|
||||
Identifier *searchCacheIdent;
|
||||
Dsymbol *searchCacheSymbol; // cached value of search
|
||||
int searchCacheFlags; // cached flags
|
||||
|
||||
int semanticstarted; // has semantic() been started?
|
||||
int semanticRun; // has semantic() been done?
|
||||
int root; // != 0 if this is a 'root' module,
|
||||
// i.e. a module that will be taken all the
|
||||
// way to an object file
|
||||
Module *importedFrom; // module from command line we're imported from,
|
||||
// i.e. a module that will be taken all the
|
||||
// way to an object file
|
||||
|
||||
Dsymbols *decldefs; // top level declarations for this Module
|
||||
|
||||
Modules aimports; // all imported modules
|
||||
|
||||
ModuleInfoDeclaration *vmoduleinfo;
|
||||
|
||||
unsigned debuglevel; // debug level
|
||||
Strings *debugids; // debug identifiers
|
||||
Strings *debugidsNot; // forward referenced debug identifiers
|
||||
|
||||
unsigned versionlevel; // version level
|
||||
Strings *versionids; // version identifiers
|
||||
Strings *versionidsNot; // forward referenced version identifiers
|
||||
|
||||
Macro *macrotable; // document comment macros
|
||||
Escape *escapetable; // document comment escapes
|
||||
bool safe; // TRUE if module is marked as 'safe'
|
||||
|
||||
size_t nameoffset; // offset of module name from start of ModuleInfo
|
||||
size_t namelen; // length of module name in characters
|
||||
|
||||
int doDocComment; // enable generating doc comments for this module
|
||||
int doHdrGen; // enable generating header file for this module
|
||||
|
||||
Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen);
|
||||
~Module();
|
||||
|
||||
static Module *load(Loc loc, Identifiers *packages, Identifier *ident);
|
||||
|
||||
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||
void toJsonBuffer(OutBuffer *buf);
|
||||
const char *kind();
|
||||
#if !IN_LLVM
|
||||
void setDocfile(); // set docfile member
|
||||
#endif
|
||||
void read(Loc loc); // read file
|
||||
#if IN_LLVM
|
||||
void parse(bool gen_docs = false); // syntactic parse
|
||||
#elif IN_GCC
|
||||
void parse(bool dump_source = false); // syntactic parse
|
||||
#else
|
||||
void parse(); // syntactic parse
|
||||
#endif
|
||||
void importAll(Scope *sc);
|
||||
void semantic(Scope* unused_sc = NULL); // semantic analysis
|
||||
void semantic2(Scope* unused_sc = NULL); // pass 2 semantic analysis
|
||||
void semantic3(Scope* unused_sc = NULL); // pass 3 semantic analysis
|
||||
void inlineScan(); // scan for functions to inline
|
||||
#if !IN_LLVM
|
||||
void setHdrfile(); // set hdrfile member
|
||||
#endif
|
||||
void genhdrfile(); // generate D import file
|
||||
// void gensymfile();
|
||||
void gendocfile();
|
||||
int needModuleInfo();
|
||||
Dsymbol *search(Loc loc, Identifier *ident, int flags);
|
||||
Dsymbol *symtabInsert(Dsymbol *s);
|
||||
void deleteObjFile();
|
||||
void addDeferredSemantic(Dsymbol *s);
|
||||
static void runDeferredSemantic();
|
||||
static void clearCache();
|
||||
int imports(Module *m);
|
||||
|
||||
// Back end
|
||||
#if IN_DMD
|
||||
int doppelganger; // sub-module
|
||||
Symbol *cov; // private uint[] __coverage;
|
||||
unsigned *covb; // bit array of valid code line numbers
|
||||
|
||||
Symbol *sictor; // module order independent constructor
|
||||
Symbol *sctor; // module constructor
|
||||
Symbol *sdtor; // module destructor
|
||||
Symbol *ssharedctor; // module shared constructor
|
||||
Symbol *sshareddtor; // module shared destructor
|
||||
Symbol *stest; // module unit test
|
||||
|
||||
Symbol *sfilename; // symbol for filename
|
||||
|
||||
Symbol *massert; // module assert function
|
||||
Symbol *toModuleAssert(); // get module assert function
|
||||
|
||||
Symbol *munittest; // module unittest failure function
|
||||
Symbol *toModuleUnittest(); // get module unittest failure function
|
||||
|
||||
Symbol *marray; // module array bounds function
|
||||
Symbol *toModuleArray(); // get module array bounds function
|
||||
|
||||
|
||||
static Symbol *gencritsec();
|
||||
elem *toEfilename();
|
||||
|
||||
Symbol *toSymbol();
|
||||
#endif
|
||||
void genmoduleinfo();
|
||||
|
||||
#if IN_LLVM
|
||||
// LDC
|
||||
llvm::Module* genLLVMModule(llvm::LLVMContext& context, Ir* sir);
|
||||
void buildTargetFiles(bool singleObj);
|
||||
File* buildFilePath(const char* forcename, const char* path, const char* ext);
|
||||
Module *isModule() { return this; }
|
||||
llvm::GlobalVariable* moduleInfoSymbol();
|
||||
|
||||
bool llvmForceLogging;
|
||||
llvm::GlobalVariable* moduleInfoVar;
|
||||
llvm::StructType* moduleInfoType;
|
||||
|
||||
// array ops emitted in this module already
|
||||
AA *arrayfuncs;
|
||||
|
||||
bool isRoot;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
struct ModuleDeclaration
|
||||
{
|
||||
Identifier *id;
|
||||
Identifiers *packages; // array of Identifier's representing packages
|
||||
bool safe;
|
||||
|
||||
ModuleDeclaration(Identifiers *packages, Identifier *id, bool safe);
|
||||
|
||||
char *toChars();
|
||||
};
|
||||
|
||||
#endif /* DMD_MODULE_H */
|
||||
9323
dmd2/mtype.c
Normal file
9323
dmd2/mtype.c
Normal file
File diff suppressed because it is too large
Load Diff
1067
dmd2/mtype.h
Normal file
1067
dmd2/mtype.h
Normal file
File diff suppressed because it is too large
Load Diff
1612
dmd2/opover.c
Normal file
1612
dmd2/opover.c
Normal file
File diff suppressed because it is too large
Load Diff
1219
dmd2/optimize.c
Normal file
1219
dmd2/optimize.c
Normal file
File diff suppressed because it is too large
Load Diff
6709
dmd2/parse.c
Normal file
6709
dmd2/parse.c
Normal file
File diff suppressed because it is too large
Load Diff
187
dmd2/parse.h
Normal file
187
dmd2/parse.h
Normal file
@@ -0,0 +1,187 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef DMD_PARSE_H
|
||||
#define DMD_PARSE_H
|
||||
|
||||
#ifdef __DMC__
|
||||
#pragma once
|
||||
#endif /* __DMC__ */
|
||||
|
||||
#include "arraytypes.h"
|
||||
#include "lexer.h"
|
||||
#include "enum.h"
|
||||
|
||||
struct Type;
|
||||
struct TypeQualified;
|
||||
struct Expression;
|
||||
struct Declaration;
|
||||
struct Statement;
|
||||
struct Import;
|
||||
struct Initializer;
|
||||
struct FuncDeclaration;
|
||||
struct CtorDeclaration;
|
||||
struct PostBlitDeclaration;
|
||||
struct DtorDeclaration;
|
||||
struct StaticCtorDeclaration;
|
||||
struct StaticDtorDeclaration;
|
||||
struct SharedStaticCtorDeclaration;
|
||||
struct SharedStaticDtorDeclaration;
|
||||
struct ConditionalDeclaration;
|
||||
struct InvariantDeclaration;
|
||||
struct UnitTestDeclaration;
|
||||
struct NewDeclaration;
|
||||
struct DeleteDeclaration;
|
||||
struct Condition;
|
||||
struct Module;
|
||||
struct ModuleDeclaration;
|
||||
struct TemplateDeclaration;
|
||||
struct TemplateInstance;
|
||||
struct StaticAssert;
|
||||
|
||||
/************************************
|
||||
* These control how parseStatement() works.
|
||||
*/
|
||||
|
||||
enum ParseStatementFlags
|
||||
{
|
||||
PSsemi = 1, // empty ';' statements are allowed, but deprecated
|
||||
PSscope = 2, // start a new scope
|
||||
PScurly = 4, // { } statement is required
|
||||
PScurlyscope = 8, // { } starts a new scope
|
||||
PSsemi_ok = 0x10, // empty ';' are really ok
|
||||
};
|
||||
|
||||
|
||||
struct Parser : Lexer
|
||||
{
|
||||
ModuleDeclaration *md;
|
||||
enum LINK linkage;
|
||||
Loc endloc; // set to location of last right curly
|
||||
int inBrackets; // inside [] of array index or slice
|
||||
Loc lookingForElse; // location of lonely if looking for an else
|
||||
|
||||
Parser(Module *module, unsigned char *base, unsigned length, int doDocComment);
|
||||
|
||||
Dsymbols *parseModule();
|
||||
Dsymbols *parseDeclDefs(int once);
|
||||
Dsymbols *parseAutoDeclarations(StorageClass storageClass, unsigned char *comment);
|
||||
Dsymbols *parseBlock();
|
||||
void composeStorageClass(StorageClass stc);
|
||||
StorageClass parseAttribute();
|
||||
StorageClass parsePostfix();
|
||||
Expression *parseConstraint();
|
||||
TemplateDeclaration *parseTemplateDeclaration(int ismixin);
|
||||
TemplateParameters *parseTemplateParameterList(int flag = 0);
|
||||
Dsymbol *parseMixin();
|
||||
Objects *parseTemplateArgumentList();
|
||||
Objects *parseTemplateArgumentList2();
|
||||
Objects *parseTemplateArgument();
|
||||
StaticAssert *parseStaticAssert();
|
||||
TypeQualified *parseTypeof();
|
||||
Type *parseVector();
|
||||
enum LINK parseLinkage();
|
||||
Condition *parseDebugCondition();
|
||||
Condition *parseVersionCondition();
|
||||
Condition *parseStaticIfCondition();
|
||||
Dsymbol *parseCtor();
|
||||
PostBlitDeclaration *parsePostBlit();
|
||||
DtorDeclaration *parseDtor();
|
||||
StaticCtorDeclaration *parseStaticCtor();
|
||||
StaticDtorDeclaration *parseStaticDtor();
|
||||
SharedStaticCtorDeclaration *parseSharedStaticCtor();
|
||||
SharedStaticDtorDeclaration *parseSharedStaticDtor();
|
||||
InvariantDeclaration *parseInvariant();
|
||||
UnitTestDeclaration *parseUnitTest();
|
||||
NewDeclaration *parseNew();
|
||||
DeleteDeclaration *parseDelete();
|
||||
Parameters *parseParameters(int *pvarargs, TemplateParameters **tpl = NULL);
|
||||
EnumDeclaration *parseEnum();
|
||||
Dsymbol *parseAggregate();
|
||||
BaseClasses *parseBaseClasses();
|
||||
Import *parseImport(Dsymbols *decldefs, int isstatic);
|
||||
Type *parseType(Identifier **pident = NULL, TemplateParameters **tpl = NULL);
|
||||
Type *parseBasicType();
|
||||
Type *parseBasicType2(Type *t);
|
||||
Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL, StorageClass storage_class = 0, int* pdisable = NULL);
|
||||
Dsymbols *parseDeclarations(StorageClass storage_class, unsigned char *comment);
|
||||
void parseContracts(FuncDeclaration *f);
|
||||
void checkDanglingElse(Loc elseloc);
|
||||
Statement *parseStatement(int flags);
|
||||
Initializer *parseInitializer();
|
||||
Expression *parseDefaultInitExp();
|
||||
void check(Loc loc, enum TOK value);
|
||||
void check(enum TOK value);
|
||||
void check(enum TOK value, const char *string);
|
||||
void checkParens(enum TOK value, Expression *e);
|
||||
int isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt);
|
||||
int isBasicType(Token **pt);
|
||||
int isDeclarator(Token **pt, int *haveId, enum TOK endtok);
|
||||
int isParameters(Token **pt);
|
||||
int isExpression(Token **pt);
|
||||
int isTemplateInstance(Token *t, Token **pt);
|
||||
int skipParens(Token *t, Token **pt);
|
||||
int skipAttributes(Token *t, Token **pt);
|
||||
|
||||
Expression *parseExpression();
|
||||
Expression *parsePrimaryExp();
|
||||
Expression *parseUnaryExp();
|
||||
Expression *parsePostExp(Expression *e);
|
||||
Expression *parseMulExp();
|
||||
Expression *parseAddExp();
|
||||
Expression *parseShiftExp();
|
||||
#if DMDV1
|
||||
Expression *parseRelExp();
|
||||
Expression *parseEqualExp();
|
||||
#endif
|
||||
Expression *parseCmpExp();
|
||||
Expression *parseAndExp();
|
||||
Expression *parseXorExp();
|
||||
Expression *parseOrExp();
|
||||
Expression *parseAndAndExp();
|
||||
Expression *parseOrOrExp();
|
||||
Expression *parseCondExp();
|
||||
Expression *parseAssignExp();
|
||||
|
||||
Expressions *parseArguments();
|
||||
|
||||
Expression *parseNewExp(Expression *thisexp);
|
||||
|
||||
void addComment(Dsymbol *s, unsigned char *blockComment);
|
||||
};
|
||||
|
||||
// Operator precedence - greater values are higher precedence
|
||||
|
||||
enum PREC
|
||||
{
|
||||
PREC_zero,
|
||||
PREC_expr,
|
||||
PREC_assign,
|
||||
PREC_cond,
|
||||
PREC_oror,
|
||||
PREC_andand,
|
||||
PREC_or,
|
||||
PREC_xor,
|
||||
PREC_and,
|
||||
PREC_equal,
|
||||
PREC_rel,
|
||||
PREC_shift,
|
||||
PREC_add,
|
||||
PREC_mul,
|
||||
PREC_pow,
|
||||
PREC_unary,
|
||||
PREC_primary,
|
||||
};
|
||||
|
||||
extern enum PREC precedence[TOKMAX];
|
||||
|
||||
void initPrecedence();
|
||||
|
||||
#endif /* DMD_PARSE_H */
|
||||
24
dmd2/readme.txt
Normal file
24
dmd2/readme.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
The D Programming Language
|
||||
Compiler Front End Source
|
||||
Copyright (c) 1999-2009, by Digital Mars
|
||||
http://www.digitalmars.com
|
||||
All Rights Reserved
|
||||
|
||||
|
||||
This is the source code to the front end Digital Mars D compiler.
|
||||
It covers the lexical analysis, parsing, and semantic analysis
|
||||
of the D Programming Language defined in the documents at
|
||||
http://www.digitalmars.com/d/
|
||||
|
||||
These sources are free, they are redistributable and modifiable
|
||||
under the terms of the GNU General Public License (attached as gpl.txt),
|
||||
or the Artistic License (attached as artistic.txt).
|
||||
|
||||
The optimizer and code generator sources are
|
||||
covered under a separate license, backendlicense.txt.
|
||||
|
||||
It does not apply to anything else distributed by Digital Mars,
|
||||
including D compiler executables.
|
||||
|
||||
-Walter Bright
|
||||
188
dmd2/root/aav.c
Normal file
188
dmd2/root/aav.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* Implementation of associative arrays.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "aav.h"
|
||||
|
||||
static const size_t prime_list[] = {
|
||||
31UL,
|
||||
97UL, 389UL,
|
||||
1543UL, 6151UL,
|
||||
24593UL, 98317UL,
|
||||
393241UL, 1572869UL,
|
||||
6291469UL, 25165843UL,
|
||||
100663319UL, 402653189UL,
|
||||
1610612741UL, 4294967291UL,
|
||||
};
|
||||
|
||||
struct aaA
|
||||
{
|
||||
aaA *next;
|
||||
Key key;
|
||||
Value value;
|
||||
};
|
||||
|
||||
struct AA
|
||||
{
|
||||
aaA* *b;
|
||||
size_t b_length;
|
||||
size_t nodes; // total number of aaA nodes
|
||||
aaA* binit[4]; // initial value of b[]
|
||||
};
|
||||
|
||||
static const AA bbinit = { NULL, };
|
||||
|
||||
/****************************************************
|
||||
* Determine number of entries in associative array.
|
||||
*/
|
||||
|
||||
size_t _aaLen(AA* aa)
|
||||
{
|
||||
return aa ? aa->nodes : 0;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Get pointer to value in associative array indexed by key.
|
||||
* Add entry for key if it is not already there.
|
||||
*/
|
||||
|
||||
Value* _aaGet(AA** paa, Key key)
|
||||
{
|
||||
//printf("paa = %p\n", paa);
|
||||
|
||||
if (!*paa)
|
||||
{ AA *a = new AA();
|
||||
*a = bbinit;
|
||||
a->b = a->binit;
|
||||
a->b_length = sizeof(a->binit) / sizeof(a->binit[0]);
|
||||
*paa = a;
|
||||
assert((*paa)->b_length == 4);
|
||||
}
|
||||
//printf("paa = %p, *paa = %p\n", paa, *paa);
|
||||
|
||||
assert((*paa)->b_length);
|
||||
size_t i = (size_t)key % (*paa)->b_length;
|
||||
aaA** pe = &(*paa)->b[i];
|
||||
aaA *e;
|
||||
while ((e = *pe) != NULL)
|
||||
{
|
||||
if (key == e->key)
|
||||
return &e->value;
|
||||
pe = &e->next;
|
||||
}
|
||||
|
||||
// Not found, create new elem
|
||||
//printf("create new one\n");
|
||||
e = new aaA();
|
||||
e->next = NULL;
|
||||
e->key = key;
|
||||
e->value = NULL;
|
||||
*pe = e;
|
||||
|
||||
size_t nodes = ++(*paa)->nodes;
|
||||
//printf("length = %d, nodes = %d\n", paa.a.b.length, nodes);
|
||||
if (nodes > (*paa)->b_length * 4)
|
||||
{
|
||||
//printf("rehash\n");
|
||||
_aaRehash(paa);
|
||||
}
|
||||
|
||||
return &e->value;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Get value in associative array indexed by key.
|
||||
* Returns NULL if it is not already there.
|
||||
*/
|
||||
|
||||
Value _aaGetRvalue(AA* aa, Key key)
|
||||
{
|
||||
//printf("_aaGetRvalue(key = %p)\n", key);
|
||||
if (!aa)
|
||||
return NULL;
|
||||
|
||||
size_t len = aa->b_length;
|
||||
|
||||
if (len)
|
||||
{
|
||||
size_t i = (size_t)key % len;
|
||||
aaA* e = aa->b[i];
|
||||
while (e)
|
||||
{
|
||||
if (key == e->key)
|
||||
return e->value;
|
||||
e = e->next;
|
||||
}
|
||||
}
|
||||
return NULL; // not found
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
* Rehash an array.
|
||||
*/
|
||||
|
||||
void _aaRehash(AA** paa)
|
||||
{
|
||||
//printf("Rehash\n");
|
||||
if (*paa)
|
||||
{
|
||||
AA newb = bbinit;
|
||||
AA *aa = *paa;
|
||||
size_t len = _aaLen(*paa);
|
||||
if (len)
|
||||
{ size_t i;
|
||||
|
||||
for (i = 0; i < sizeof(prime_list)/sizeof(prime_list[0]) - 1; i++)
|
||||
{
|
||||
if (len <= prime_list[i])
|
||||
break;
|
||||
}
|
||||
len = prime_list[i];
|
||||
newb.b = new aaA*[len];
|
||||
memset(newb.b, 0, len * sizeof(aaA*));
|
||||
newb.b_length = len;
|
||||
|
||||
for (size_t k = 0; k < aa->b_length; k++)
|
||||
{ aaA *e = aa->b[k];
|
||||
while (e)
|
||||
{ aaA* enext = e->next;
|
||||
size_t j = (size_t)e->key % len;
|
||||
e->next = newb.b[j];
|
||||
newb.b[j] = e;
|
||||
e = enext;
|
||||
}
|
||||
}
|
||||
if (aa->b != aa->binit)
|
||||
delete[] aa->b;
|
||||
|
||||
newb.nodes = aa->nodes;
|
||||
}
|
||||
|
||||
**paa = newb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
void unittest_aa()
|
||||
{
|
||||
AA* aa = NULL;
|
||||
Value v = _aaGetRvalue(aa, NULL);
|
||||
assert(!v);
|
||||
Value *pv = _aaGet(&aa, NULL);
|
||||
assert(pv);
|
||||
*pv = (void *)3;
|
||||
v = _aaGetRvalue(aa, NULL);
|
||||
assert(v == (void *)3);
|
||||
}
|
||||
|
||||
#endif
|
||||
11
dmd2/root/aav.h
Normal file
11
dmd2/root/aav.h
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
typedef void* Value;
|
||||
typedef void* Key;
|
||||
|
||||
struct AA;
|
||||
|
||||
size_t _aaLen(AA* aa);
|
||||
Value* _aaGet(AA** aa, Key key);
|
||||
Value _aaGetRvalue(AA* aa, Key key);
|
||||
void _aaRehash(AA** paa);
|
||||
|
||||
257
dmd2/root/array.c
Normal file
257
dmd2/root/array.c
Normal file
@@ -0,0 +1,257 @@
|
||||
|
||||
// Copyright (c) 1999-2010 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if (defined (__SVR4) && defined (__sun))
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
#if _MSC_VER || __MINGW32__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#if IN_GCC
|
||||
#include "gdc_alloca.h"
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
#endif
|
||||
|
||||
#include "port.h"
|
||||
#include "root.h"
|
||||
#include "dchar.h"
|
||||
#include "rmem.h"
|
||||
|
||||
|
||||
/********************************* Array ****************************/
|
||||
|
||||
Array::Array()
|
||||
{
|
||||
data = SMALLARRAYCAP ? &smallarray[0] : NULL;
|
||||
dim = 0;
|
||||
allocdim = SMALLARRAYCAP;
|
||||
}
|
||||
|
||||
Array::~Array()
|
||||
{
|
||||
if (data != &smallarray[0])
|
||||
mem.free(data);
|
||||
}
|
||||
|
||||
void Array::mark()
|
||||
{ unsigned u;
|
||||
|
||||
mem.mark(data);
|
||||
for (u = 0; u < dim; u++)
|
||||
mem.mark(data[u]); // BUG: what if arrays of Object's?
|
||||
}
|
||||
|
||||
void Array::reserve(unsigned nentries)
|
||||
{
|
||||
//printf("Array::reserve: dim = %d, allocdim = %d, nentries = %d\n", dim, allocdim, nentries);
|
||||
if (allocdim - dim < nentries)
|
||||
{
|
||||
if (allocdim == 0)
|
||||
{ // Not properly initialized, someone memset it to zero
|
||||
if (nentries <= SMALLARRAYCAP)
|
||||
{ allocdim = SMALLARRAYCAP;
|
||||
data = SMALLARRAYCAP ? &smallarray[0] : NULL;
|
||||
}
|
||||
else
|
||||
{ allocdim = nentries;
|
||||
data = (void **)mem.malloc(allocdim * sizeof(*data));
|
||||
}
|
||||
}
|
||||
else if (allocdim == SMALLARRAYCAP)
|
||||
{
|
||||
allocdim = dim + nentries;
|
||||
data = (void **)mem.malloc(allocdim * sizeof(*data));
|
||||
memcpy(data, &smallarray[0], dim * sizeof(*data));
|
||||
}
|
||||
else
|
||||
{ allocdim = dim + nentries;
|
||||
data = (void **)mem.realloc(data, allocdim * sizeof(*data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Array::setDim(unsigned newdim)
|
||||
{
|
||||
if (dim < newdim)
|
||||
{
|
||||
reserve(newdim - dim);
|
||||
}
|
||||
dim = newdim;
|
||||
}
|
||||
|
||||
void Array::fixDim()
|
||||
{
|
||||
if (dim != allocdim)
|
||||
{
|
||||
if (allocdim >= SMALLARRAYCAP)
|
||||
{
|
||||
if (dim <= SMALLARRAYCAP)
|
||||
{
|
||||
memcpy(&smallarray[0], data, dim * sizeof(*data));
|
||||
mem.free(data);
|
||||
}
|
||||
else
|
||||
data = (void **)mem.realloc(data, dim * sizeof(*data));
|
||||
}
|
||||
allocdim = dim;
|
||||
}
|
||||
}
|
||||
|
||||
void Array::push(void *ptr)
|
||||
{
|
||||
reserve(1);
|
||||
data[dim++] = ptr;
|
||||
}
|
||||
|
||||
void *Array::pop()
|
||||
{
|
||||
return data[--dim];
|
||||
}
|
||||
|
||||
void Array::shift(void *ptr)
|
||||
{
|
||||
reserve(1);
|
||||
memmove(data + 1, data, dim * sizeof(*data));
|
||||
data[0] = ptr;
|
||||
dim++;
|
||||
}
|
||||
|
||||
void Array::insert(unsigned index, void *ptr)
|
||||
{
|
||||
reserve(1);
|
||||
memmove(data + index + 1, data + index, (dim - index) * sizeof(*data));
|
||||
data[index] = ptr;
|
||||
dim++;
|
||||
}
|
||||
|
||||
|
||||
void Array::insert(unsigned index, Array *a)
|
||||
{
|
||||
if (a)
|
||||
{ unsigned d;
|
||||
|
||||
d = a->dim;
|
||||
reserve(d);
|
||||
if (dim != index)
|
||||
memmove(data + index + d, data + index, (dim - index) * sizeof(*data));
|
||||
memcpy(data + index, a->data, d * sizeof(*data));
|
||||
dim += d;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************
|
||||
* Append array a to this array.
|
||||
*/
|
||||
|
||||
void Array::append(Array *a)
|
||||
{
|
||||
insert(dim, a);
|
||||
}
|
||||
|
||||
void Array::remove(unsigned i)
|
||||
{
|
||||
if (dim - i - 1)
|
||||
memmove(data + i, data + i + 1, (dim - i - 1) * sizeof(data[0]));
|
||||
dim--;
|
||||
}
|
||||
|
||||
char *Array::toChars()
|
||||
{
|
||||
unsigned len;
|
||||
unsigned u;
|
||||
char **buf;
|
||||
char *str;
|
||||
char *p;
|
||||
|
||||
buf = (char **)malloc(dim * sizeof(char *));
|
||||
assert(buf);
|
||||
len = 2;
|
||||
for (u = 0; u < dim; u++)
|
||||
{
|
||||
buf[u] = ((Object *)data[u])->toChars();
|
||||
len += strlen(buf[u]) + 1;
|
||||
}
|
||||
str = (char *)mem.malloc(len);
|
||||
|
||||
str[0] = '[';
|
||||
p = str + 1;
|
||||
for (u = 0; u < dim; u++)
|
||||
{
|
||||
if (u)
|
||||
*p++ = ',';
|
||||
len = strlen(buf[u]);
|
||||
memcpy(p,buf[u],len);
|
||||
p += len;
|
||||
}
|
||||
*p++ = ']';
|
||||
*p = 0;
|
||||
free(buf);
|
||||
return str;
|
||||
}
|
||||
|
||||
void Array::zero()
|
||||
{
|
||||
memset(data,0,dim * sizeof(data[0]));
|
||||
}
|
||||
|
||||
void *Array::tos()
|
||||
{
|
||||
return dim ? data[dim - 1] : NULL;
|
||||
}
|
||||
|
||||
int
|
||||
#if _WIN32
|
||||
__cdecl
|
||||
#endif
|
||||
Array_sort_compare(const void *x, const void *y)
|
||||
{
|
||||
Object *ox = *(Object **)x;
|
||||
Object *oy = *(Object **)y;
|
||||
|
||||
return ox->compare(oy);
|
||||
}
|
||||
|
||||
void Array::sort()
|
||||
{
|
||||
if (dim)
|
||||
{
|
||||
qsort(data, dim, sizeof(Object *), Array_sort_compare);
|
||||
}
|
||||
}
|
||||
|
||||
Array *Array::copy()
|
||||
{
|
||||
Array *a = new Array();
|
||||
|
||||
a->setDim(dim);
|
||||
memcpy(a->data, data, dim * sizeof(void *));
|
||||
return a;
|
||||
}
|
||||
|
||||
325
dmd2/root/async.c
Normal file
325
dmd2/root/async.c
Normal file
@@ -0,0 +1,325 @@
|
||||
|
||||
#define _MT 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
#include <errno.h>
|
||||
#include <process.h>
|
||||
|
||||
#include "root.h"
|
||||
|
||||
static unsigned __stdcall startthread(void *p);
|
||||
|
||||
struct FileData
|
||||
{
|
||||
File *file;
|
||||
int result;
|
||||
HANDLE event;
|
||||
};
|
||||
|
||||
struct AsyncRead
|
||||
{
|
||||
static AsyncRead *create(size_t nfiles);
|
||||
void addFile(File *file);
|
||||
void start();
|
||||
int read(size_t i);
|
||||
static void dispose(AsyncRead *);
|
||||
|
||||
HANDLE hThread;
|
||||
|
||||
size_t filesdim;
|
||||
size_t filesmax;
|
||||
FileData files[1];
|
||||
};
|
||||
|
||||
|
||||
AsyncRead *AsyncRead::create(size_t nfiles)
|
||||
{
|
||||
AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) +
|
||||
(nfiles - 1) * sizeof(FileData));
|
||||
aw->filesmax = nfiles;
|
||||
return aw;
|
||||
}
|
||||
|
||||
void AsyncRead::addFile(File *file)
|
||||
{
|
||||
//printf("addFile(file = %p)\n", file);
|
||||
//printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax);
|
||||
assert(filesdim < filesmax);
|
||||
files[filesdim].file = file;
|
||||
files[filesdim].event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
ResetEvent(files[filesdim].event);
|
||||
filesdim++;
|
||||
}
|
||||
|
||||
void AsyncRead::start()
|
||||
{
|
||||
//printf("aw->filesdim = %p %d\n", this, filesdim);
|
||||
if (filesdim)
|
||||
{
|
||||
unsigned threadaddr;
|
||||
hThread = (HANDLE) _beginthreadex(NULL,
|
||||
0,
|
||||
&startthread,
|
||||
this,
|
||||
0,
|
||||
(unsigned *)&threadaddr);
|
||||
|
||||
if (hThread)
|
||||
{
|
||||
SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int AsyncRead::read(size_t i)
|
||||
{
|
||||
FileData *f = &files[i];
|
||||
WaitForSingleObject(f->event, INFINITE);
|
||||
Sleep(0); // give up time slice
|
||||
return f->result;
|
||||
}
|
||||
|
||||
void AsyncRead::dispose(AsyncRead *aw)
|
||||
{
|
||||
free(aw);
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned __stdcall startthread(void *p)
|
||||
{
|
||||
AsyncRead *aw = (AsyncRead *)p;
|
||||
|
||||
//printf("aw->filesdim = %p %d\n", aw, aw->filesdim);
|
||||
for (size_t i = 0; i < aw->filesdim; i++)
|
||||
{ FileData *f = &aw->files[i];
|
||||
|
||||
f->result = f->file->read();
|
||||
SetEvent(f->event);
|
||||
}
|
||||
_endthreadex(EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS; // if skidding
|
||||
}
|
||||
|
||||
#elif linux // Posix
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "root.h"
|
||||
|
||||
void *startthread(void *arg);
|
||||
|
||||
void err_abort(int status, const char *msg)
|
||||
{
|
||||
fprintf(stderr, "fatal error = %d, %s\n", status, msg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct FileData
|
||||
{
|
||||
File *file;
|
||||
int result;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct AsyncRead
|
||||
{
|
||||
static AsyncRead *create(size_t nfiles);
|
||||
void addFile(File *file);
|
||||
void start();
|
||||
int read(size_t i);
|
||||
static void dispose(AsyncRead *);
|
||||
|
||||
size_t filesdim;
|
||||
size_t filesmax;
|
||||
FileData files[1];
|
||||
};
|
||||
|
||||
|
||||
AsyncRead *AsyncRead::create(size_t nfiles)
|
||||
{
|
||||
AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) +
|
||||
(nfiles - 1) * sizeof(FileData));
|
||||
aw->filesmax = nfiles;
|
||||
return aw;
|
||||
}
|
||||
|
||||
void AsyncRead::addFile(File *file)
|
||||
{
|
||||
//printf("addFile(file = %p)\n", file);
|
||||
//printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax);
|
||||
assert(filesdim < filesmax);
|
||||
FileData *f = &files[filesdim];
|
||||
f->file = file;
|
||||
|
||||
int status = pthread_mutex_init(&f->mutex, NULL);
|
||||
if (status != 0)
|
||||
err_abort(status, "init mutex");
|
||||
status = pthread_cond_init(&f->cond, NULL);
|
||||
if (status != 0)
|
||||
err_abort(status, "init cond");
|
||||
|
||||
filesdim++;
|
||||
}
|
||||
|
||||
void AsyncRead::start()
|
||||
{
|
||||
//printf("aw->filesdim = %p %d\n", this, filesdim);
|
||||
if (filesdim)
|
||||
{
|
||||
pthread_t thread_id;
|
||||
int status = pthread_create(&thread_id,
|
||||
NULL,
|
||||
&startthread,
|
||||
this);
|
||||
if (status != 0)
|
||||
err_abort(status, "create thread");
|
||||
}
|
||||
}
|
||||
|
||||
int AsyncRead::read(size_t i)
|
||||
{
|
||||
FileData *f = &files[i];
|
||||
|
||||
// Wait for the event
|
||||
int status = pthread_mutex_lock(&f->mutex);
|
||||
if (status != 0)
|
||||
err_abort(status, "lock mutex");
|
||||
while (f->value == 0)
|
||||
{
|
||||
status = pthread_cond_wait(&f->cond, &f->mutex);
|
||||
if (status != 0)
|
||||
err_abort(status, "wait on condition");
|
||||
}
|
||||
status = pthread_mutex_unlock(&f->mutex);
|
||||
if (status != 0)
|
||||
err_abort(status, "unlock mutex");
|
||||
|
||||
return f->result;
|
||||
}
|
||||
|
||||
void AsyncRead::dispose(AsyncRead *aw)
|
||||
{
|
||||
//printf("AsyncRead::dispose()\n");
|
||||
for (int i = 0; i < aw->filesdim; i++)
|
||||
{
|
||||
FileData *f = &aw->files[i];
|
||||
int status = pthread_cond_destroy(&f->cond);
|
||||
if (status != 0)
|
||||
err_abort(status, "cond destroy");
|
||||
status = pthread_mutex_destroy(&f->mutex);
|
||||
if (status != 0)
|
||||
err_abort(status, "mutex destroy");
|
||||
}
|
||||
free(aw);
|
||||
}
|
||||
|
||||
|
||||
void *startthread(void *p)
|
||||
{
|
||||
AsyncRead *aw = (AsyncRead *)p;
|
||||
|
||||
//printf("startthread: aw->filesdim = %p %d\n", aw, aw->filesdim);
|
||||
size_t dim = aw->filesdim;
|
||||
for (size_t i = 0; i < dim; i++)
|
||||
{ FileData *f = &aw->files[i];
|
||||
|
||||
f->result = f->file->read();
|
||||
|
||||
// Set event
|
||||
int status = pthread_mutex_lock(&f->mutex);
|
||||
if (status != 0)
|
||||
err_abort(status, "lock mutex");
|
||||
f->value = 1;
|
||||
status = pthread_cond_signal(&f->cond);
|
||||
if (status != 0)
|
||||
err_abort(status, "signal condition");
|
||||
status = pthread_mutex_unlock(&f->mutex);
|
||||
if (status != 0)
|
||||
err_abort(status, "unlock mutex");
|
||||
}
|
||||
|
||||
return NULL; // end thread
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "root.h"
|
||||
|
||||
struct FileData
|
||||
{
|
||||
File *file;
|
||||
int result;
|
||||
//HANDLE event;
|
||||
};
|
||||
|
||||
struct AsyncRead
|
||||
{
|
||||
static AsyncRead *create(size_t nfiles);
|
||||
void addFile(File *file);
|
||||
void start();
|
||||
int read(size_t i);
|
||||
static void dispose(AsyncRead *);
|
||||
|
||||
//HANDLE hThread;
|
||||
|
||||
size_t filesdim;
|
||||
size_t filesmax;
|
||||
FileData files[1];
|
||||
};
|
||||
|
||||
|
||||
AsyncRead *AsyncRead::create(size_t nfiles)
|
||||
{
|
||||
AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) +
|
||||
(nfiles - 1) * sizeof(FileData));
|
||||
aw->filesmax = nfiles;
|
||||
return aw;
|
||||
}
|
||||
|
||||
void AsyncRead::addFile(File *file)
|
||||
{
|
||||
//printf("addFile(file = %p)\n", file);
|
||||
//printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax);
|
||||
assert(filesdim < filesmax);
|
||||
files[filesdim].file = file;
|
||||
//files[filesdim].event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
//ResetEvent(files[filesdim].event);
|
||||
filesdim++;
|
||||
}
|
||||
|
||||
void AsyncRead::start()
|
||||
{
|
||||
}
|
||||
|
||||
int AsyncRead::read(size_t i)
|
||||
{
|
||||
FileData *f = &files[i];
|
||||
f->result = f->file->read();
|
||||
return f->result;
|
||||
}
|
||||
|
||||
void AsyncRead::dispose(AsyncRead *aw)
|
||||
{
|
||||
free(aw);
|
||||
}
|
||||
|
||||
#endif
|
||||
33
dmd2/root/async.h
Normal file
33
dmd2/root/async.h
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
// Copyright (c) 2009-2009 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef ASYNC_H
|
||||
#define ASYNC_H
|
||||
|
||||
#if __DMC__
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
/*******************
|
||||
* Simple interface to read files asynchronously in another
|
||||
* thread.
|
||||
*/
|
||||
|
||||
struct AsyncRead
|
||||
{
|
||||
static AsyncRead *create(size_t nfiles);
|
||||
void addFile(File *file);
|
||||
void start();
|
||||
int read(size_t i);
|
||||
static void dispose(AsyncRead *);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
482
dmd2/root/dchar.c
Normal file
482
dmd2/root/dchar.c
Normal file
@@ -0,0 +1,482 @@
|
||||
|
||||
// Copyright (c) 1999-2006 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "dchar.h"
|
||||
#include "rmem.h"
|
||||
|
||||
#if M_UNICODE
|
||||
|
||||
// Converts a char string to Unicode
|
||||
|
||||
dchar *Dchar::dup(char *p)
|
||||
{
|
||||
dchar *s;
|
||||
size_t len;
|
||||
|
||||
if (!p)
|
||||
return NULL;
|
||||
len = strlen(p);
|
||||
s = (dchar *)mem.malloc((len + 1) * sizeof(dchar));
|
||||
for (unsigned i = 0; i < len; i++)
|
||||
{
|
||||
s[i] = (dchar)(p[i] & 0xFF);
|
||||
}
|
||||
s[len] = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
dchar *Dchar::memchr(dchar *p, int c, int count)
|
||||
{
|
||||
int u;
|
||||
|
||||
for (u = 0; u < count; u++)
|
||||
{
|
||||
if (p[u] == c)
|
||||
return p + u;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if _WIN32 && __DMC__
|
||||
__declspec(naked)
|
||||
unsigned Dchar::calcHash(const dchar *str, unsigned len)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov ECX,4[ESP]
|
||||
mov EDX,8[ESP]
|
||||
xor EAX,EAX
|
||||
test EDX,EDX
|
||||
je L92
|
||||
|
||||
LC8: cmp EDX,1
|
||||
je L98
|
||||
cmp EDX,2
|
||||
je LAE
|
||||
|
||||
add EAX,[ECX]
|
||||
// imul EAX,EAX,025h
|
||||
lea EAX,[EAX][EAX*8]
|
||||
add ECX,4
|
||||
sub EDX,2
|
||||
jmp LC8
|
||||
|
||||
L98: mov DX,[ECX]
|
||||
and EDX,0FFFFh
|
||||
add EAX,EDX
|
||||
ret
|
||||
|
||||
LAE: add EAX,[ECX]
|
||||
L92: ret
|
||||
}
|
||||
}
|
||||
#else
|
||||
hash_t Dchar::calcHash(const dchar *str, size_t len)
|
||||
{
|
||||
unsigned hash = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
switch (len)
|
||||
{
|
||||
case 0:
|
||||
return hash;
|
||||
|
||||
case 1:
|
||||
hash += *(const uint16_t *)str;
|
||||
return hash;
|
||||
|
||||
case 2:
|
||||
hash += *(const uint32_t *)str;
|
||||
return hash;
|
||||
|
||||
default:
|
||||
hash += *(const uint32_t *)str;
|
||||
hash *= 37;
|
||||
str += 2;
|
||||
len -= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
hash_t Dchar::icalcHash(const dchar *str, size_t len)
|
||||
{
|
||||
hash_t hash = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
switch (len)
|
||||
{
|
||||
case 0:
|
||||
return hash;
|
||||
|
||||
case 1:
|
||||
hash += *(const uint16_t *)str | 0x20;
|
||||
return hash;
|
||||
|
||||
case 2:
|
||||
hash += *(const uint32_t *)str | 0x200020;
|
||||
return hash;
|
||||
|
||||
default:
|
||||
hash += *(const uint32_t *)str | 0x200020;
|
||||
hash *= 37;
|
||||
str += 2;
|
||||
len -= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif MCBS
|
||||
|
||||
hash_t Dchar::calcHash(const dchar *str, size_t len)
|
||||
{
|
||||
hash_t hash = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
switch (len)
|
||||
{
|
||||
case 0:
|
||||
return hash;
|
||||
|
||||
case 1:
|
||||
hash *= 37;
|
||||
hash += *(const uint8_t *)str;
|
||||
return hash;
|
||||
|
||||
case 2:
|
||||
hash *= 37;
|
||||
hash += *(const uint16_t *)str;
|
||||
return hash;
|
||||
|
||||
case 3:
|
||||
hash *= 37;
|
||||
hash += (*(const uint16_t *)str << 8) +
|
||||
((const uint8_t *)str)[2];
|
||||
return hash;
|
||||
|
||||
default:
|
||||
hash *= 37;
|
||||
hash += *(const uint32_t *)str;
|
||||
str += 4;
|
||||
len -= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif UTF8
|
||||
|
||||
// Specification is: http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335
|
||||
|
||||
char Dchar::mblen[256] =
|
||||
{
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||
4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
|
||||
};
|
||||
|
||||
dchar *Dchar::dec(dchar *pstart, dchar *p)
|
||||
{
|
||||
while ((p[-1] & 0xC0) == 0x80)
|
||||
p--;
|
||||
return p;
|
||||
}
|
||||
|
||||
int Dchar::get(dchar *p)
|
||||
{
|
||||
unsigned c;
|
||||
unsigned char *q = (unsigned char *)p;
|
||||
|
||||
c = q[0];
|
||||
switch (mblen[c])
|
||||
{
|
||||
case 2:
|
||||
c = ((c - 0xC0) << 6) |
|
||||
(q[1] - 0x80);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
c = ((c - 0xE0) << 12) |
|
||||
((q[1] - 0x80) << 6) |
|
||||
(q[2] - 0x80);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
c = ((c - 0xF0) << 18) |
|
||||
((q[1] - 0x80) << 12) |
|
||||
((q[2] - 0x80) << 6) |
|
||||
(q[3] - 0x80);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
c = ((c - 0xF8) << 24) |
|
||||
((q[1] - 0x80) << 18) |
|
||||
((q[2] - 0x80) << 12) |
|
||||
((q[3] - 0x80) << 6) |
|
||||
(q[4] - 0x80);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
c = ((c - 0xFC) << 30) |
|
||||
((q[1] - 0x80) << 24) |
|
||||
((q[2] - 0x80) << 18) |
|
||||
((q[3] - 0x80) << 12) |
|
||||
((q[4] - 0x80) << 6) |
|
||||
(q[5] - 0x80);
|
||||
break;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
dchar *Dchar::put(dchar *p, unsigned c)
|
||||
{
|
||||
if (c <= 0x7F)
|
||||
{
|
||||
*p++ = c;
|
||||
}
|
||||
else if (c <= 0x7FF)
|
||||
{
|
||||
p[0] = 0xC0 + (c >> 6);
|
||||
p[1] = 0x80 + (c & 0x3F);
|
||||
p += 2;
|
||||
}
|
||||
else if (c <= 0xFFFF)
|
||||
{
|
||||
p[0] = 0xE0 + (c >> 12);
|
||||
p[1] = 0x80 + ((c >> 6) & 0x3F);
|
||||
p[2] = 0x80 + (c & 0x3F);
|
||||
p += 3;
|
||||
}
|
||||
else if (c <= 0x1FFFFF)
|
||||
{
|
||||
p[0] = 0xF0 + (c >> 18);
|
||||
p[1] = 0x80 + ((c >> 12) & 0x3F);
|
||||
p[2] = 0x80 + ((c >> 6) & 0x3F);
|
||||
p[3] = 0x80 + (c & 0x3F);
|
||||
p += 4;
|
||||
}
|
||||
else if (c <= 0x3FFFFFF)
|
||||
{
|
||||
p[0] = 0xF8 + (c >> 24);
|
||||
p[1] = 0x80 + ((c >> 18) & 0x3F);
|
||||
p[2] = 0x80 + ((c >> 12) & 0x3F);
|
||||
p[3] = 0x80 + ((c >> 6) & 0x3F);
|
||||
p[4] = 0x80 + (c & 0x3F);
|
||||
p += 5;
|
||||
}
|
||||
else if (c <= 0x7FFFFFFF)
|
||||
{
|
||||
p[0] = 0xFC + (c >> 30);
|
||||
p[1] = 0x80 + ((c >> 24) & 0x3F);
|
||||
p[2] = 0x80 + ((c >> 18) & 0x3F);
|
||||
p[3] = 0x80 + ((c >> 12) & 0x3F);
|
||||
p[4] = 0x80 + ((c >> 6) & 0x3F);
|
||||
p[5] = 0x80 + (c & 0x3F);
|
||||
p += 6;
|
||||
}
|
||||
else
|
||||
assert(0); // not a UCS-4 character
|
||||
return p;
|
||||
}
|
||||
|
||||
hash_t Dchar::calcHash(const dchar *str, size_t len)
|
||||
{
|
||||
hash_t hash = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
switch (len)
|
||||
{
|
||||
case 0:
|
||||
return hash;
|
||||
|
||||
case 1:
|
||||
hash *= 37;
|
||||
hash += *(const uint8_t *)str;
|
||||
return hash;
|
||||
|
||||
case 2:
|
||||
hash *= 37;
|
||||
#if LITTLE_ENDIAN
|
||||
hash += *(const uint16_t *)str;
|
||||
#else
|
||||
hash += str[0] * 256 + str[1];
|
||||
#endif
|
||||
return hash;
|
||||
|
||||
case 3:
|
||||
hash *= 37;
|
||||
#if LITTLE_ENDIAN
|
||||
hash += (*(const uint16_t *)str << 8) +
|
||||
((const uint8_t *)str)[2];
|
||||
#else
|
||||
hash += (str[0] * 256 + str[1]) * 256 + str[2];
|
||||
#endif
|
||||
return hash;
|
||||
|
||||
default:
|
||||
hash *= 37;
|
||||
#if LITTLE_ENDIAN
|
||||
hash += *(const uint32_t *)str;
|
||||
#else
|
||||
hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3];
|
||||
#endif
|
||||
|
||||
str += 4;
|
||||
len -= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else // ascii
|
||||
|
||||
hash_t Dchar::calcHash(const dchar *str, size_t len)
|
||||
{
|
||||
hash_t hash = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
switch (len)
|
||||
{
|
||||
case 0:
|
||||
return hash;
|
||||
|
||||
case 1:
|
||||
hash *= 37;
|
||||
hash += *(const uint8_t *)str;
|
||||
return hash;
|
||||
|
||||
case 2:
|
||||
hash *= 37;
|
||||
#if LITTLE_ENDIAN
|
||||
hash += *(const uint16_t *)str;
|
||||
#else
|
||||
hash += str[0] * 256 + str[1];
|
||||
#endif
|
||||
return hash;
|
||||
|
||||
case 3:
|
||||
hash *= 37;
|
||||
#if LITTLE_ENDIAN
|
||||
hash += (*(const uint16_t *)str << 8) +
|
||||
((const uint8_t *)str)[2];
|
||||
#else
|
||||
hash += (str[0] * 256 + str[1]) * 256 + str[2];
|
||||
#endif
|
||||
return hash;
|
||||
|
||||
default:
|
||||
hash *= 37;
|
||||
#if LITTLE_ENDIAN
|
||||
hash += *(const uint32_t *)str;
|
||||
#else
|
||||
hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3];
|
||||
#endif
|
||||
str += 4;
|
||||
len -= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hash_t Dchar::icalcHash(const dchar *str, size_t len)
|
||||
{
|
||||
hash_t hash = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
switch (len)
|
||||
{
|
||||
case 0:
|
||||
return hash;
|
||||
|
||||
case 1:
|
||||
hash *= 37;
|
||||
hash += *(const uint8_t *)str | 0x20;
|
||||
return hash;
|
||||
|
||||
case 2:
|
||||
hash *= 37;
|
||||
hash += *(const uint16_t *)str | 0x2020;
|
||||
return hash;
|
||||
|
||||
case 3:
|
||||
hash *= 37;
|
||||
hash += ((*(const uint16_t *)str << 8) +
|
||||
((const uint8_t *)str)[2]) | 0x202020;
|
||||
return hash;
|
||||
|
||||
default:
|
||||
hash *= 37;
|
||||
hash += *(const uint32_t *)str | 0x20202020;
|
||||
str += 4;
|
||||
len -= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
|
||||
void main()
|
||||
{
|
||||
// Print out values to hardcode into Dchar::mblen[]
|
||||
int c;
|
||||
int s;
|
||||
|
||||
for (c = 0; c < 256; c++)
|
||||
{
|
||||
s = 1;
|
||||
if (c >= 0xC0 && c <= 0xDF)
|
||||
s = 2;
|
||||
if (c >= 0xE0 && c <= 0xEF)
|
||||
s = 3;
|
||||
if (c >= 0xF0 && c <= 0xF7)
|
||||
s = 4;
|
||||
if (c >= 0xF8 && c <= 0xFB)
|
||||
s = 5;
|
||||
if (c >= 0xFC && c <= 0xFD)
|
||||
s = 6;
|
||||
|
||||
printf("%d", s);
|
||||
if ((c & 15) == 15)
|
||||
printf(",\n");
|
||||
else
|
||||
printf(",");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
194
dmd2/root/dchar.h
Normal file
194
dmd2/root/dchar.h
Normal file
@@ -0,0 +1,194 @@
|
||||
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
|
||||
#ifndef DCHAR_H
|
||||
#define DCHAR_H
|
||||
|
||||
#if __GNUC__ && !_WIN32
|
||||
#include "gnuc.h"
|
||||
#endif
|
||||
|
||||
#if _MSC_VER
|
||||
// Disable useless warnings about unreferenced functions
|
||||
#pragma warning (disable : 4514)
|
||||
#endif
|
||||
|
||||
//#include "root.h"
|
||||
typedef size_t hash_t;
|
||||
|
||||
#undef TEXT
|
||||
|
||||
// NOTE: All functions accepting pointer arguments must not be NULL
|
||||
|
||||
#if M_UNICODE
|
||||
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
typedef wchar_t dchar;
|
||||
#define TEXT(x) L##x
|
||||
|
||||
#define Dchar_mbmax 1
|
||||
|
||||
struct Dchar
|
||||
{
|
||||
static dchar *inc(dchar *p) { return p + 1; }
|
||||
static dchar *dec(dchar *pstart, dchar *p) { (void)pstart; return p - 1; }
|
||||
static int len(const dchar *p) { return wcslen(p); }
|
||||
static dchar get(dchar *p) { return *p; }
|
||||
static dchar getprev(dchar *pstart, dchar *p) { (void)pstart; return p[-1]; }
|
||||
static dchar *put(dchar *p, dchar c) { *p = c; return p + 1; }
|
||||
static int cmp(dchar *s1, dchar *s2)
|
||||
{
|
||||
#if __DMC__
|
||||
if (!*s1 && !*s2) // wcscmp is broken
|
||||
return 0;
|
||||
#endif
|
||||
return wcscmp(s1, s2);
|
||||
#if 0
|
||||
return (*s1 == *s2)
|
||||
? wcscmp(s1, s2)
|
||||
: ((int)*s1 - (int)*s2);
|
||||
#endif
|
||||
}
|
||||
static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars * sizeof(dchar)); }
|
||||
static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
|
||||
static int isAlpha(dchar c) { return iswalpha(c); }
|
||||
static int isUpper(dchar c) { return iswupper(c); }
|
||||
static int isLower(dchar c) { return iswlower(c); }
|
||||
static int isLocaleUpper(dchar c) { return isUpper(c); }
|
||||
static int isLocaleLower(dchar c) { return isLower(c); }
|
||||
static int toLower(dchar c) { return isUpper(c) ? towlower(c) : c; }
|
||||
static int toLower(dchar *p) { return toLower(*p); }
|
||||
static int toUpper(dchar c) { return isLower(c) ? towupper(c) : c; }
|
||||
static dchar *dup(dchar *p) { return ::_wcsdup(p); } // BUG: out of memory?
|
||||
static dchar *dup(char *p);
|
||||
static dchar *chr(dchar *p, unsigned c) { return wcschr(p, (dchar)c); }
|
||||
static dchar *rchr(dchar *p, unsigned c) { return wcsrchr(p, (dchar)c); }
|
||||
static dchar *memchr(dchar *p, int c, int count);
|
||||
static dchar *cpy(dchar *s1, dchar *s2) { return wcscpy(s1, s2); }
|
||||
static dchar *str(dchar *s1, dchar *s2) { return wcsstr(s1, s2); }
|
||||
static hash_t calcHash(const dchar *str, size_t len);
|
||||
|
||||
// Case insensitive versions
|
||||
static int icmp(dchar *s1, dchar *s2) { return wcsicmp(s1, s2); }
|
||||
static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::wcsnicmp(s1, s2, nchars); }
|
||||
static hash_t icalcHash(const dchar *str, size_t len);
|
||||
};
|
||||
|
||||
#elif MCBS
|
||||
|
||||
#include <limits.h>
|
||||
#include <mbstring.h>
|
||||
|
||||
typedef char dchar;
|
||||
#define TEXT(x) x
|
||||
|
||||
#define Dchar_mbmax MB_LEN_MAX
|
||||
|
||||
#elif UTF8
|
||||
|
||||
typedef char dchar;
|
||||
#define TEXT(x) x
|
||||
|
||||
#define Dchar_mbmax 6
|
||||
|
||||
struct Dchar
|
||||
{
|
||||
static char mblen[256];
|
||||
|
||||
static dchar *inc(dchar *p) { return p + mblen[*p & 0xFF]; }
|
||||
static dchar *dec(dchar *pstart, dchar *p);
|
||||
static int len(const dchar *p) { return strlen(p); }
|
||||
static int get(dchar *p);
|
||||
static int getprev(dchar *pstart, dchar *p)
|
||||
{ return *dec(pstart, p) & 0xFF; }
|
||||
static dchar *put(dchar *p, unsigned c);
|
||||
static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); }
|
||||
static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); }
|
||||
static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
|
||||
static int isAlpha(dchar c) { return c <= 0x7F ? isalpha(c) : 0; }
|
||||
static int isUpper(dchar c) { return c <= 0x7F ? isupper(c) : 0; }
|
||||
static int isLower(dchar c) { return c <= 0x7F ? islower(c) : 0; }
|
||||
static int isLocaleUpper(dchar c) { return isUpper(c); }
|
||||
static int isLocaleLower(dchar c) { return isLower(c); }
|
||||
static int toLower(dchar c) { return isUpper(c) ? tolower(c) : c; }
|
||||
static int toLower(dchar *p) { return toLower(*p); }
|
||||
static int toUpper(dchar c) { return isLower(c) ? toupper(c) : c; }
|
||||
static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory?
|
||||
static dchar *chr(dchar *p, int c) { return strchr(p, c); }
|
||||
static dchar *rchr(dchar *p, int c) { return strrchr(p, c); }
|
||||
static dchar *memchr(dchar *p, int c, int count)
|
||||
{ return (dchar *)::memchr(p, c, count); }
|
||||
static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); }
|
||||
static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); }
|
||||
static hash_t calcHash(const dchar *str, size_t len);
|
||||
|
||||
// Case insensitive versions
|
||||
static int icmp(dchar *s1, dchar *s2) { return _mbsicmp(s1, s2); }
|
||||
static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::_mbsnicmp(s1, s2, nchars); }
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef GCC_SAFE_DMD
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
typedef char dchar;
|
||||
#define TEXT(x) x
|
||||
|
||||
#define Dchar_mbmax 1
|
||||
|
||||
struct Dchar
|
||||
{
|
||||
static dchar *inc(dchar *p) { return p + 1; }
|
||||
static dchar *dec(dchar *pstart, dchar *p) { return p - 1; }
|
||||
static int len(const dchar *p) { return strlen(p); }
|
||||
static int get(dchar *p) { return *p & 0xFF; }
|
||||
static int getprev(dchar *pstart, dchar *p) { return p[-1] & 0xFF; }
|
||||
static dchar *put(dchar *p, unsigned c) { *p = c; return p + 1; }
|
||||
static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); }
|
||||
static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); }
|
||||
static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
|
||||
#ifndef GCC_SAFE_DMD
|
||||
static int isAlpha(dchar c) { return isalpha((unsigned char)c); }
|
||||
static int isUpper(dchar c) { return isupper((unsigned char)c); }
|
||||
static int isLower(dchar c) { return islower((unsigned char)c); }
|
||||
static int isLocaleUpper(dchar c) { return isupper((unsigned char)c); }
|
||||
static int isLocaleLower(dchar c) { return islower((unsigned char)c); }
|
||||
static int toLower(dchar c) { return isupper((unsigned char)c) ? tolower(c) : c; }
|
||||
static int toLower(dchar *p) { return toLower(*p); }
|
||||
static int toUpper(dchar c) { return islower((unsigned char)c) ? toupper(c) : c; }
|
||||
static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory?
|
||||
#endif
|
||||
static dchar *chr(dchar *p, int c) { return strchr(p, c); }
|
||||
static dchar *rchr(dchar *p, int c) { return strrchr(p, c); }
|
||||
static dchar *memchr(dchar *p, int c, int count)
|
||||
{ return (dchar *)::memchr(p, c, count); }
|
||||
static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); }
|
||||
static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); }
|
||||
static hash_t calcHash(const dchar *str, size_t len);
|
||||
|
||||
// Case insensitive versions
|
||||
#ifdef __GNUC__
|
||||
static int icmp(dchar *s1, dchar *s2) { return strcasecmp(s1, s2); }
|
||||
#else
|
||||
static int icmp(dchar *s1, dchar *s2) { return stricmp(s1, s2); }
|
||||
#endif
|
||||
static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::memicmp(s1, s2, nchars); }
|
||||
static hash_t icalcHash(const dchar *str, size_t len);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
499
dmd2/root/dmgcmem.c
Normal file
499
dmd2/root/dmgcmem.c
Normal file
@@ -0,0 +1,499 @@
|
||||
|
||||
|
||||
// Copyright (c) 2000-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "rmem.h"
|
||||
#include "gc/gc.h"
|
||||
//#include "printf.h"
|
||||
|
||||
/* This implementation of the storage allocator uses the Digital Mars gc.
|
||||
*/
|
||||
|
||||
Mem mem;
|
||||
|
||||
//static int nuncollectable;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void gc_init();
|
||||
GC *gc_get();
|
||||
}
|
||||
|
||||
void Mem::init()
|
||||
{
|
||||
gc_init();
|
||||
}
|
||||
|
||||
char *Mem::strdup(const char *s)
|
||||
{
|
||||
return gc_get()->strdup(s);
|
||||
}
|
||||
|
||||
void *Mem::malloc(size_t size)
|
||||
{
|
||||
if (gc) // if cached allocator
|
||||
{
|
||||
// PRINTF("Using cached gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line);
|
||||
// GC::file = NULL;
|
||||
// GC::line = 0;
|
||||
return ((GC *)gc)->malloc(size);
|
||||
}
|
||||
if (this == &mem) // don't cache global mem
|
||||
{
|
||||
// PRINTF("Using global gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line);
|
||||
// GC::file = NULL;
|
||||
// GC::line = 0;
|
||||
return gc_get()->malloc(size);
|
||||
}
|
||||
// PRINTF("Generating cached gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line);
|
||||
gc = gc_get();
|
||||
return gc->malloc(size);
|
||||
}
|
||||
|
||||
void *Mem::malloc_uncollectable(size_t size)
|
||||
{ void *p;
|
||||
|
||||
p = ::malloc(size);
|
||||
if (!p)
|
||||
error();
|
||||
addroots((char *)p, (char *)p + size);
|
||||
|
||||
#if 0
|
||||
++nuncollectable;
|
||||
WPRINTF(L"malloc_uncollectable(%u) = %x, n=%d\n", size, p, nuncollectable);
|
||||
#endif
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void *Mem::calloc(size_t size, size_t n)
|
||||
{
|
||||
return gc_get()->calloc(size, n);
|
||||
}
|
||||
|
||||
void *Mem::realloc(void *p, size_t size)
|
||||
{
|
||||
return gc_get()->realloc(p, size);
|
||||
}
|
||||
|
||||
void Mem::free(void *p)
|
||||
{
|
||||
gc_get()->free(p);
|
||||
}
|
||||
|
||||
void Mem::free_uncollectable(void *p)
|
||||
{
|
||||
if (p)
|
||||
{ removeroots((char *)p);
|
||||
::free(p);
|
||||
|
||||
#if 0
|
||||
--nuncollectable;
|
||||
WPRINTF(L"free_uncollectable(%x) n=%d\n", p, nuncollectable);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
gc_get()->fullcollect();
|
||||
|
||||
GCStats stats;
|
||||
|
||||
getStats(&stats);
|
||||
WPRINTF(L"poolsize = %x, usedsize = %x, freelistsize = %x\n",
|
||||
stats.poolsize, stats.usedsize, stats.freelistsize);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void *Mem::mallocdup(void *o, size_t size)
|
||||
{
|
||||
return gc_get()->mallocdup(o, size);
|
||||
}
|
||||
|
||||
void Mem::check(void *p)
|
||||
{
|
||||
if (gc)
|
||||
gc->check(p);
|
||||
else
|
||||
gc_get()->check(p);
|
||||
}
|
||||
|
||||
void Mem::error()
|
||||
{
|
||||
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__
|
||||
assert(0);
|
||||
#endif
|
||||
printf("Error: out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void Mem::fullcollect()
|
||||
{
|
||||
gc_get()->fullcollect();
|
||||
|
||||
#if 0
|
||||
{
|
||||
GCStats stats;
|
||||
|
||||
gc_get()->getStats(&stats);
|
||||
WPRINTF(L"Thread %x ", Thread::getId());
|
||||
WPRINTF(L"poolsize=x%x, usedsize=x%x, freelistsize=x%x, freeblocks=%d, pageblocks=%d\n",
|
||||
stats.poolsize, stats.usedsize, stats.freelistsize, stats.freeblocks, stats.pageblocks);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Mem::fullcollectNoStack()
|
||||
{
|
||||
gc_get()->fullcollectNoStack();
|
||||
|
||||
#if 0
|
||||
{
|
||||
GCStats stats;
|
||||
|
||||
gc_get()->getStats(&stats);
|
||||
WPRINTF(L"Thread %x ", Thread::getId());
|
||||
WPRINTF(L"poolsize=x%x, usedsize=x%x, freelistsize=x%x, freeblocks=%d, pageblocks=%d\n",
|
||||
stats.poolsize, stats.usedsize, stats.freelistsize, stats.freeblocks, stats.pageblocks);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Mem::mark(void *pointer)
|
||||
{
|
||||
(void) pointer; // for VC /W4 compatibility
|
||||
}
|
||||
|
||||
|
||||
void Mem::addroots(char* pStart, char* pEnd)
|
||||
{
|
||||
gc_get()->addRange(pStart, pEnd);
|
||||
}
|
||||
|
||||
|
||||
void Mem::removeroots(char* pStart)
|
||||
{
|
||||
gc_get()->removeRange(pStart);
|
||||
}
|
||||
|
||||
|
||||
void Mem::setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData)
|
||||
{
|
||||
(void)pClientData;
|
||||
gc_get()->setFinalizer(pObj, pFn);
|
||||
}
|
||||
|
||||
|
||||
void Mem::setStackBottom(void *stackbottom)
|
||||
{
|
||||
gc_get()->setStackBottom(stackbottom);
|
||||
}
|
||||
|
||||
|
||||
GC *Mem::getThreadGC()
|
||||
{
|
||||
return gc_get();
|
||||
}
|
||||
|
||||
|
||||
/* =================================================== */
|
||||
|
||||
#if 1
|
||||
void * operator new(size_t m_size)
|
||||
{
|
||||
//PRINTF("Call to global operator new(%d), file = '%s', line = %d\n", m_size, GC::file ? GC::file : "(null)", GC::line);
|
||||
GC::file = NULL;
|
||||
GC::line = 0;
|
||||
return mem.malloc(m_size);
|
||||
}
|
||||
|
||||
void operator delete(void *p)
|
||||
{
|
||||
//WPRINTF(L"Call to global operator delete\n");
|
||||
mem.free(p);
|
||||
}
|
||||
|
||||
void* operator new[](size_t size)
|
||||
{
|
||||
return operator new(size);
|
||||
}
|
||||
|
||||
void operator delete[](void *pv)
|
||||
{
|
||||
operator delete(pv);
|
||||
}
|
||||
#endif
|
||||
|
||||
void * Mem::operator new(size_t m_size)
|
||||
{ void *p;
|
||||
|
||||
p = gc_get()->malloc(m_size);
|
||||
//printf("Mem::operator new(%d) = %p\n", m_size, p);
|
||||
if (!p)
|
||||
mem.error();
|
||||
return p;
|
||||
}
|
||||
|
||||
void * Mem::operator new(size_t m_size, Mem *mem)
|
||||
{ void *p;
|
||||
|
||||
p = mem->malloc(m_size);
|
||||
//printf("Mem::operator new(%d) = %p\n", m_size, p);
|
||||
if (!p)
|
||||
::mem.error();
|
||||
return p;
|
||||
}
|
||||
|
||||
void * Mem::operator new(size_t m_size, GC *gc)
|
||||
{ void *p;
|
||||
|
||||
// if (!gc)
|
||||
// WPRINTF(L"gc is NULL\n");
|
||||
p = gc->malloc(m_size);
|
||||
//printf("Mem::operator new(%d) = %p\n", m_size, p);
|
||||
if (!p)
|
||||
::mem.error();
|
||||
return p;
|
||||
}
|
||||
|
||||
void Mem::operator delete(void *p)
|
||||
{
|
||||
// printf("Mem::operator delete(%p)\n", p);
|
||||
gc_get()->free(p);
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
/* The following section of code exists to find the right
|
||||
* garbage collector for this thread. There is one independent instance
|
||||
* of the collector per thread.
|
||||
*/
|
||||
|
||||
/* ===================== linux ================================ */
|
||||
|
||||
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define LOG 0 // log thread creation / destruction
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Key identifying the thread-specific data
|
||||
static pthread_key_t gc_key;
|
||||
|
||||
/* "Once" variable ensuring that the key for gc_alloc will be allocated
|
||||
* exactly once.
|
||||
*/
|
||||
static pthread_once_t gc_alloc_key_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
/* Forward functions */
|
||||
static void gc_alloc_key();
|
||||
static void gc_alloc_destroy_gc(void * accu);
|
||||
|
||||
|
||||
void gc_init()
|
||||
{
|
||||
#if LOG
|
||||
WPRINTF(L"Thread %lx: gc_init()\n", pthread_self());
|
||||
#endif
|
||||
pthread_once(&gc_alloc_key_once, gc_alloc_key);
|
||||
#if LOG
|
||||
WPRINTF(L"Thread %lx: gc_init() return\n", pthread_self());
|
||||
#endif
|
||||
}
|
||||
|
||||
GC *gc_get()
|
||||
{
|
||||
GC *gc;
|
||||
|
||||
// Get the thread-specific data associated with the key
|
||||
gc = (GC *) pthread_getspecific(gc_key);
|
||||
|
||||
// It's initially NULL, meaning that we must allocate the buffer first.
|
||||
if (gc == NULL)
|
||||
{
|
||||
GC_LOG();
|
||||
gc = new GC();
|
||||
gc->init();
|
||||
|
||||
// Store the buffer pointer in the thread-specific data.
|
||||
pthread_setspecific(gc_key, (void *) gc);
|
||||
#if LOG
|
||||
WPRINTF(L"Thread %lx: allocating gc at %x\n", pthread_self(), gc);
|
||||
#endif
|
||||
}
|
||||
return gc;
|
||||
}
|
||||
|
||||
// Function to allocate the key for gc_alloc thread-specific data.
|
||||
|
||||
static void gc_alloc_key()
|
||||
{
|
||||
pthread_key_create(&gc_key, gc_alloc_destroy_gc);
|
||||
#if LOG
|
||||
WPRINTF(L"Thread %lx: allocated gc key %d\n", pthread_self(), gc_key);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Function to free the buffer when the thread exits.
|
||||
// Called only when the thread-specific data is not NULL.
|
||||
|
||||
static void gc_alloc_destroy_gc(void *gc)
|
||||
{
|
||||
#if LOG
|
||||
WPRINTF(L"Thread %x: freeing gc at %x\n", pthread_self(), gc);
|
||||
#endif
|
||||
delete (GC *)gc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ===================== win32 ================================ */
|
||||
|
||||
#if !defined(linux) && defined(_WIN32)
|
||||
|
||||
#if 1 // single threaded version
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
static GC *gc;
|
||||
|
||||
void gc_init()
|
||||
{
|
||||
if (!gc)
|
||||
{ gc = (GC *)::malloc(sizeof(GC));
|
||||
gc->init();
|
||||
}
|
||||
}
|
||||
|
||||
GC *gc_get()
|
||||
{
|
||||
return gc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else // multi threaded version
|
||||
|
||||
#include "mutex.h"
|
||||
#include "thread.h"
|
||||
|
||||
/* This is the win32 version. It suffers from the bug that
|
||||
* when the thread exits the data structure is not cleared,
|
||||
* but the memory pool it points to is free'd.
|
||||
* Thus, if a new thread comes along with the same thread id,
|
||||
* the data will look initialized, but will point to garbage.
|
||||
*
|
||||
* What needs to happen is when a thread exits, the associated
|
||||
* GC_context data struct is cleared.
|
||||
*/
|
||||
|
||||
struct GC_context
|
||||
{
|
||||
ThreadId threadid; // identifier of current thread
|
||||
GC *gc;
|
||||
};
|
||||
|
||||
Mutex gc_mutex;
|
||||
|
||||
static GC_context array[64];
|
||||
|
||||
// Array of pointers to GC_context objects, one per threadid
|
||||
GC_context *gccontext = array;
|
||||
unsigned gccontext_allocdim = 64;
|
||||
unsigned gccontext_dim;
|
||||
|
||||
ThreadId gc_cache_ti;
|
||||
GC_context *gc_cache_cc;
|
||||
|
||||
extern "C" void gc_init()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
extern "C" GC *gc_get()
|
||||
{
|
||||
/* This works by creating an array of GC_context's, one
|
||||
* for each thread. We match up by thread id.
|
||||
*/
|
||||
|
||||
ThreadId ti;
|
||||
GC_context *cc;
|
||||
|
||||
//PRINTF("gc_get()\n");
|
||||
|
||||
ti = Thread::getId();
|
||||
gc_mutex.acquire();
|
||||
|
||||
// Used cached version if we can
|
||||
if (ti == gc_cache_ti)
|
||||
{
|
||||
cc = gc_cache_cc;
|
||||
//exception(L"getGC_context(): cache x%x", ti);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This does a linear search through gccontext[].
|
||||
// A hash table might be faster if there are more
|
||||
// than a dozen threads.
|
||||
GC_context *ccp;
|
||||
GC_context *ccptop = &gccontext[gccontext_dim];
|
||||
for (ccp = gccontext; ccp < ccptop; ccp++)
|
||||
{
|
||||
cc = ccp;
|
||||
if (cc->threadid == ti)
|
||||
{
|
||||
WPRINTF(L"getGC_context(): existing x%x", ti);
|
||||
goto Lret;
|
||||
}
|
||||
}
|
||||
|
||||
// Do not allocate with garbage collector, as this must reside
|
||||
// global to all threads.
|
||||
|
||||
assert(gccontext_dim < gccontext_allocdim);
|
||||
cc = ccp;
|
||||
memset(cc, 0, sizeof(*cc));
|
||||
cc->threadid = ti;
|
||||
cc->gc = new GC();
|
||||
cc->gc->init();
|
||||
|
||||
gccontext_dim++;
|
||||
WPRINTF(L"getGC_context(): new x%x\n", ti);
|
||||
|
||||
Lret:
|
||||
// Cache for next time
|
||||
gc_cache_ti = ti;
|
||||
gc_cache_cc = cc;
|
||||
}
|
||||
|
||||
gc_mutex.release();
|
||||
return cc->gc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
55
dmd2/root/gnuc.c
Normal file
55
dmd2/root/gnuc.c
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
// Put functions in here missing from gnu C
|
||||
|
||||
#include "gnuc.h"
|
||||
|
||||
int memicmp(const char *s1, const char *s2, int n)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{ char c1 = s1[i];
|
||||
char c2 = s2[i];
|
||||
|
||||
result = c1 - c2;
|
||||
if (result)
|
||||
{
|
||||
if ('A' <= c1 && c1 <= 'Z')
|
||||
c1 += 'a' - 'A';
|
||||
if ('A' <= c2 && c2 <= 'Z')
|
||||
c2 += 'a' - 'A';
|
||||
result = c1 - c2;
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int stricmp(const char *s1, const char *s2)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
for (;;)
|
||||
{ char c1 = *s1;
|
||||
char c2 = *s2;
|
||||
|
||||
result = c1 - c2;
|
||||
if (result)
|
||||
{
|
||||
if ('A' <= c1 && c1 <= 'Z')
|
||||
c1 += 'a' - 'A';
|
||||
if ('A' <= c2 && c2 <= 'Z')
|
||||
c2 += 'a' - 'A';
|
||||
result = c1 - c2;
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
if (!c1)
|
||||
break;
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
8
dmd2/root/gnuc.h
Normal file
8
dmd2/root/gnuc.h
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
#ifndef _GNUC_H
|
||||
#define _GNUC_H 1
|
||||
|
||||
int memicmp(const char *s1, const char *s2, int n);
|
||||
int stricmp(const char *s1, const char *s2);
|
||||
|
||||
#endif
|
||||
63
dmd2/root/lstring.c
Normal file
63
dmd2/root/lstring.c
Normal file
@@ -0,0 +1,63 @@
|
||||
// lstring.c
|
||||
|
||||
// Copyright (c) 1999-2002 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dchar.h"
|
||||
#include "rmem.h"
|
||||
#include "lstring.h"
|
||||
|
||||
#ifdef _MSC_VER // prevent compiler internal crash
|
||||
Lstring Lstring::zero;
|
||||
#else
|
||||
Lstring Lstring::zero = LSTRING_EMPTY();
|
||||
#endif
|
||||
|
||||
Lstring *Lstring::ctor(const dchar *p, unsigned length)
|
||||
{
|
||||
Lstring *s;
|
||||
|
||||
s = alloc(length);
|
||||
memcpy(s->string, p, length * sizeof(dchar));
|
||||
return s;
|
||||
}
|
||||
|
||||
Lstring *Lstring::alloc(unsigned length)
|
||||
{
|
||||
Lstring *s;
|
||||
|
||||
s = (Lstring *)mem.malloc(size(length));
|
||||
s->length = length;
|
||||
s->string[length] = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
Lstring *Lstring::append(const Lstring *s)
|
||||
{
|
||||
Lstring *t;
|
||||
|
||||
if (!s->length)
|
||||
return this;
|
||||
t = alloc(length + s->length);
|
||||
memcpy(t->string, string, length * sizeof(dchar));
|
||||
memcpy(t->string + length, s->string, s->length * sizeof(dchar));
|
||||
return t;
|
||||
}
|
||||
|
||||
Lstring *Lstring::substring(int start, int end)
|
||||
{
|
||||
Lstring *t;
|
||||
|
||||
if (start == end)
|
||||
return &zero;
|
||||
t = alloc(end - start);
|
||||
memcpy(t->string, string + start, (end - start) * sizeof(dchar));
|
||||
return t;
|
||||
}
|
||||
72
dmd2/root/lstring.h
Normal file
72
dmd2/root/lstring.h
Normal file
@@ -0,0 +1,72 @@
|
||||
|
||||
// lstring.h
|
||||
// length-prefixed strings
|
||||
|
||||
// Copyright (c) 1999-2002 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef LSTRING_H
|
||||
#define LSTRING_H 1
|
||||
|
||||
#include "dchar.h"
|
||||
|
||||
struct Lstring
|
||||
{
|
||||
unsigned length;
|
||||
|
||||
// Disable warning about nonstandard extension
|
||||
#pragma warning (disable : 4200)
|
||||
dchar string[];
|
||||
|
||||
static Lstring zero; // 0 length string
|
||||
|
||||
// No constructors because we want to be able to statically
|
||||
// initialize Lstring's, and Lstrings are of variable size.
|
||||
|
||||
#if M_UNICODE
|
||||
#define LSTRING(p,length) { length, L##p }
|
||||
#else
|
||||
#define LSTRING(p,length) { length, p }
|
||||
#endif
|
||||
|
||||
#if __GNUC__
|
||||
#define LSTRING_EMPTY() { 0 }
|
||||
#else
|
||||
#define LSTRING_EMPTY() LSTRING("", 0)
|
||||
#endif
|
||||
|
||||
static Lstring *ctor(const dchar *p) { return ctor(p, Dchar::len(p)); }
|
||||
static Lstring *ctor(const dchar *p, unsigned length);
|
||||
static unsigned size(unsigned length) { return sizeof(Lstring) + (length + 1) * sizeof(dchar); }
|
||||
static Lstring *alloc(unsigned length);
|
||||
Lstring *clone();
|
||||
|
||||
unsigned len() { return length; }
|
||||
|
||||
dchar *toDchars() { return string; }
|
||||
|
||||
hash_t hash() { return Dchar::calcHash(string, length); }
|
||||
hash_t ihash() { return Dchar::icalcHash(string, length); }
|
||||
|
||||
static int cmp(const Lstring *s1, const Lstring *s2)
|
||||
{
|
||||
int c = s2->length - s1->length;
|
||||
return c ? c : Dchar::memcmp(s1->string, s2->string, s1->length);
|
||||
}
|
||||
|
||||
static int icmp(const Lstring *s1, const Lstring *s2)
|
||||
{
|
||||
int c = s2->length - s1->length;
|
||||
return c ? c : Dchar::memicmp(s1->string, s2->string, s1->length);
|
||||
}
|
||||
|
||||
Lstring *append(const Lstring *s);
|
||||
Lstring *substring(int start, int end);
|
||||
};
|
||||
|
||||
#endif
|
||||
100
dmd2/root/man.c
Normal file
100
dmd2/root/man.c
Normal file
@@ -0,0 +1,100 @@
|
||||
|
||||
// Compiler implementation of the D programming language
|
||||
// Copyright (c) 2008-2009 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#pragma comment(lib,"shell32.lib")
|
||||
|
||||
void browse(const char *url)
|
||||
{
|
||||
ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if linux || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void browse(const char *url)
|
||||
{
|
||||
pid_t childpid;
|
||||
const char *args[3];
|
||||
|
||||
const char *browser = getenv("BROWSER");
|
||||
if (browser)
|
||||
browser = strdup(browser);
|
||||
else
|
||||
browser = "x-www-browser";
|
||||
|
||||
args[0] = browser;
|
||||
args[1] = url;
|
||||
args[2] = NULL;
|
||||
|
||||
childpid = fork();
|
||||
if (childpid == 0)
|
||||
{
|
||||
execvp(args[0], (char**)args);
|
||||
perror(args[0]); // failed to execute
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void browse(const char *url)
|
||||
{
|
||||
pid_t childpid;
|
||||
const char *args[5];
|
||||
|
||||
char *browser = getenv("BROWSER");
|
||||
if (browser)
|
||||
{ browser = strdup(browser);
|
||||
args[0] = browser;
|
||||
args[1] = url;
|
||||
args[2] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
//browser = "/Applications/Safari.app/Contents/MacOS/Safari";
|
||||
args[0] = "open";
|
||||
args[1] = "-a";
|
||||
args[2] = "/Applications/Safari.app";
|
||||
args[3] = url;
|
||||
args[4] = NULL;
|
||||
}
|
||||
|
||||
childpid = fork();
|
||||
if (childpid == 0)
|
||||
{
|
||||
execvp(args[0], (char**)args);
|
||||
perror(args[0]); // failed to execute
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
796
dmd2/root/port.c
Normal file
796
dmd2/root/port.c
Normal file
@@ -0,0 +1,796 @@
|
||||
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
|
||||
#include "port.h"
|
||||
#if __DMC__
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <fp.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
double Port::nan = NAN;
|
||||
double Port::infinity = INFINITY;
|
||||
double Port::dbl_max = DBL_MAX;
|
||||
double Port::dbl_min = DBL_MIN;
|
||||
long double Port::ldbl_max = LDBL_MAX;
|
||||
|
||||
int Port::isNan(double r)
|
||||
{
|
||||
return ::isnan(r);
|
||||
}
|
||||
|
||||
int Port::isNan(long double r)
|
||||
{
|
||||
return ::isnan(r);
|
||||
}
|
||||
|
||||
int Port::isSignallingNan(double r)
|
||||
{
|
||||
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||
* its significand, which is bit 51 of 0..63 for 64 bit doubles.
|
||||
*/
|
||||
return isNan(r) && !((((unsigned char*)&r)[6]) & 8);
|
||||
}
|
||||
|
||||
int Port::isSignallingNan(long double r)
|
||||
{
|
||||
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||
* its significand, which is bit 62 of 0..79 for 80 bit reals.
|
||||
*/
|
||||
return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40);
|
||||
}
|
||||
|
||||
int Port::isFinite(double r)
|
||||
{
|
||||
return ::isfinite(r);
|
||||
}
|
||||
|
||||
int Port::isInfinity(double r)
|
||||
{
|
||||
return (::fpclassify(r) == FP_INFINITE);
|
||||
}
|
||||
|
||||
int Port::Signbit(double r)
|
||||
{
|
||||
return ::signbit(r);
|
||||
}
|
||||
|
||||
double Port::floor(double d)
|
||||
{
|
||||
return ::floor(d);
|
||||
}
|
||||
|
||||
double Port::pow(double x, double y)
|
||||
{
|
||||
return ::pow(x, y);
|
||||
}
|
||||
|
||||
long double Port::fmodl(long double x, long double y)
|
||||
{
|
||||
return ::fmodl(x, y);
|
||||
}
|
||||
|
||||
unsigned long long Port::strtoull(const char *p, char **pend, int base)
|
||||
{
|
||||
return ::strtoull(p, pend, base);
|
||||
}
|
||||
|
||||
char *Port::ull_to_string(char *buffer, ulonglong ull)
|
||||
{
|
||||
sprintf(buffer, "%llu", ull);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull)
|
||||
{
|
||||
swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
double Port::ull_to_double(ulonglong ull)
|
||||
{
|
||||
return (double) ull;
|
||||
}
|
||||
|
||||
const char *Port::list_separator()
|
||||
{
|
||||
// LOCALE_SLIST for Windows
|
||||
return ",";
|
||||
}
|
||||
|
||||
const wchar_t *Port::wlist_separator()
|
||||
{
|
||||
// LOCALE_SLIST for Windows
|
||||
return L",";
|
||||
}
|
||||
|
||||
char *Port::strupr(char *s)
|
||||
{
|
||||
return ::strupr(s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if _MSC_VER
|
||||
|
||||
// Disable useless warnings about unreferenced functions
|
||||
#pragma warning (disable : 4514)
|
||||
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits> // for std::numeric_limits
|
||||
|
||||
static unsigned long nanarray[2]= { 0xFFFFFFFF, 0x7FFFFFFF };
|
||||
//static unsigned long nanarray[2] = {0,0x7FF80000 };
|
||||
double Port::nan = (*(double *)nanarray);
|
||||
|
||||
//static unsigned long infinityarray[2] = {0,0x7FF00000 };
|
||||
static double zero = 0;
|
||||
double Port::infinity = 1 / zero;
|
||||
|
||||
double Port::dbl_max = DBL_MAX;
|
||||
double Port::dbl_min = DBL_MIN;
|
||||
long double Port::ldbl_max = LDBL_MAX;
|
||||
|
||||
struct PortInitializer
|
||||
{
|
||||
PortInitializer();
|
||||
};
|
||||
|
||||
static PortInitializer portinitializer;
|
||||
|
||||
PortInitializer::PortInitializer()
|
||||
{
|
||||
Port::infinity = std::numeric_limits<long double>::infinity();
|
||||
}
|
||||
|
||||
int Port::isNan(double r)
|
||||
{
|
||||
return ::_isnan(r);
|
||||
}
|
||||
|
||||
int Port::isNan(long double r)
|
||||
{
|
||||
return ::_isnan(r);
|
||||
}
|
||||
|
||||
int Port::isSignallingNan(double r)
|
||||
{
|
||||
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||
* its significand, which is bit 51 of 0..63 for 64 bit doubles.
|
||||
*/
|
||||
return isNan(r) && !((((unsigned char*)&r)[6]) & 8);
|
||||
}
|
||||
|
||||
int Port::isSignallingNan(long double r)
|
||||
{
|
||||
/* MSVC doesn't have 80 bit long doubles
|
||||
*/
|
||||
return isSignallingNan((double) r);
|
||||
}
|
||||
|
||||
int Port::isFinite(double r)
|
||||
{
|
||||
return ::_finite(r);
|
||||
}
|
||||
|
||||
int Port::isInfinity(double r)
|
||||
{
|
||||
return (::_fpclass(r) & (_FPCLASS_NINF | _FPCLASS_PINF));
|
||||
}
|
||||
|
||||
int Port::Signbit(double r)
|
||||
{
|
||||
return (long)(((long *)&(r))[1] & 0x80000000);
|
||||
}
|
||||
|
||||
double Port::floor(double d)
|
||||
{
|
||||
return ::floor(d);
|
||||
}
|
||||
|
||||
double Port::pow(double x, double y)
|
||||
{
|
||||
if (y == 0)
|
||||
return 1; // even if x is NAN
|
||||
return ::pow(x, y);
|
||||
}
|
||||
|
||||
long double Port::fmodl(long double x, long double y)
|
||||
{
|
||||
return ::fmodl(x, y);
|
||||
}
|
||||
|
||||
unsigned _int64 Port::strtoull(const char *p, char **pend, int base)
|
||||
{
|
||||
unsigned _int64 number = 0;
|
||||
int c;
|
||||
int error;
|
||||
#ifndef ULLONG_MAX
|
||||
#define ULLONG_MAX ((unsigned _int64)~0I64)
|
||||
#endif
|
||||
|
||||
while (isspace((unsigned char)*p)) /* skip leading white space */
|
||||
p++;
|
||||
if (*p == '+')
|
||||
p++;
|
||||
switch (base)
|
||||
{ case 0:
|
||||
base = 10; /* assume decimal base */
|
||||
if (*p == '0')
|
||||
{ base = 8; /* could be octal */
|
||||
p++;
|
||||
switch (*p)
|
||||
{ case 'x':
|
||||
case 'X':
|
||||
base = 16; /* hex */
|
||||
p++;
|
||||
break;
|
||||
#if BINARY
|
||||
case 'b':
|
||||
case 'B':
|
||||
base = 2; /* binary */
|
||||
p++;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 16: /* skip over '0x' and '0X' */
|
||||
if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
|
||||
p += 2;
|
||||
break;
|
||||
#if BINARY
|
||||
case 2: /* skip over '0b' and '0B' */
|
||||
if (*p == '0' && (p[1] == 'b' || p[1] == 'B'))
|
||||
p += 2;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
error = 0;
|
||||
for (;;)
|
||||
{ c = *p;
|
||||
if (isdigit(c))
|
||||
c -= '0';
|
||||
else if (isalpha(c))
|
||||
c = (c & ~0x20) - ('A' - 10);
|
||||
else /* unrecognized character */
|
||||
break;
|
||||
if (c >= base) /* not in number base */
|
||||
break;
|
||||
if ((ULLONG_MAX - c) / base < number)
|
||||
error = 1;
|
||||
number = number * base + c;
|
||||
p++;
|
||||
}
|
||||
if (pend)
|
||||
*pend = (char *)p;
|
||||
if (error)
|
||||
{ number = ULLONG_MAX;
|
||||
errno = ERANGE;
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
char *Port::ull_to_string(char *buffer, ulonglong ull)
|
||||
{
|
||||
_ui64toa(ull, buffer, 10);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull)
|
||||
{
|
||||
_ui64tow(ull, buffer, 10);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
double Port::ull_to_double(ulonglong ull)
|
||||
{ double d;
|
||||
|
||||
if ((__int64) ull < 0)
|
||||
{
|
||||
// MSVC doesn't implement the conversion
|
||||
d = (double) (__int64)(ull - 0x8000000000000000i64);
|
||||
d += (double)(signed __int64)(0x7FFFFFFFFFFFFFFFi64) + 1.0;
|
||||
}
|
||||
else
|
||||
d = (double)(__int64)ull;
|
||||
return d;
|
||||
}
|
||||
|
||||
const char *Port::list_separator()
|
||||
{
|
||||
// LOCALE_SLIST for Windows
|
||||
return ",";
|
||||
}
|
||||
|
||||
const wchar_t *Port::wlist_separator()
|
||||
{
|
||||
// LOCALE_SLIST for Windows
|
||||
return L",";
|
||||
}
|
||||
|
||||
char *Port::strupr(char *s)
|
||||
{
|
||||
return ::strupr(s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __HAIKU__
|
||||
|
||||
#include <math.h>
|
||||
#if linux
|
||||
#include <bits/nan.h>
|
||||
#include <bits/mathdef.h>
|
||||
#endif
|
||||
#if __FreeBSD__ && __i386__
|
||||
#include <ieeefp.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
#include <assert.h>
|
||||
|
||||
static double zero = 0;
|
||||
double Port::nan = copysign(NAN, 1.0);
|
||||
double Port::infinity = 1 / zero;
|
||||
double Port::dbl_max = 1.7976931348623157e308;
|
||||
double Port::dbl_min = 5e-324;
|
||||
long double Port::ldbl_max = LDBL_MAX;
|
||||
|
||||
struct PortInitializer
|
||||
{
|
||||
PortInitializer();
|
||||
};
|
||||
|
||||
static PortInitializer portinitializer;
|
||||
|
||||
PortInitializer::PortInitializer()
|
||||
{
|
||||
assert(!signbit(Port::nan));
|
||||
|
||||
#if __FreeBSD__ && __i386__
|
||||
// LDBL_MAX comes out as infinity. Fix.
|
||||
static unsigned char x[sizeof(long double)] =
|
||||
{ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7F };
|
||||
Port::ldbl_max = *(long double *)&x[0];
|
||||
// FreeBSD defaults to double precision. Switch to extended precision.
|
||||
fpsetprec(FP_PE);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef __HAIKU__
|
||||
#endif
|
||||
int Port::isNan(double r)
|
||||
{
|
||||
#if __APPLE__
|
||||
return __inline_isnan(r);
|
||||
#elif defined __HAIKU__ || __OpenBSD__
|
||||
return isnan(r);
|
||||
#else
|
||||
#undef isnan
|
||||
return ::isnan(r);
|
||||
#endif
|
||||
}
|
||||
|
||||
int Port::isNan(long double r)
|
||||
{
|
||||
#if __APPLE__
|
||||
return __inline_isnan(r);
|
||||
#elif defined __HAIKU__ || __OpenBSD__
|
||||
return isnan(r);
|
||||
#else
|
||||
#undef isnan
|
||||
return ::isnan(r);
|
||||
#endif
|
||||
}
|
||||
|
||||
int Port::isSignallingNan(double r)
|
||||
{
|
||||
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||
* its significand, which is bit 51 of 0..63 for 64 bit doubles.
|
||||
*/
|
||||
return isNan(r) && !((((unsigned char*)&r)[6]) & 8);
|
||||
}
|
||||
|
||||
int Port::isSignallingNan(long double r)
|
||||
{
|
||||
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||
* its significand, which is bit 62 of 0..79 for 80 bit reals.
|
||||
*/
|
||||
return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40);
|
||||
}
|
||||
|
||||
#undef isfinite
|
||||
int Port::isFinite(double r)
|
||||
{
|
||||
return ::finite(r);
|
||||
}
|
||||
|
||||
#if !defined __HAIKU__
|
||||
#endif
|
||||
int Port::isInfinity(double r)
|
||||
{
|
||||
#if __APPLE__
|
||||
return fpclassify(r) == FP_INFINITE;
|
||||
#elif defined __HAIKU__ || __OpenBSD__
|
||||
return isinf(r);
|
||||
#else
|
||||
#undef isinf
|
||||
return ::isinf(r);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef signbit
|
||||
int Port::Signbit(double r)
|
||||
{
|
||||
union { double d; long long ll; } u;
|
||||
u.d = r;
|
||||
return u.ll < 0;
|
||||
}
|
||||
|
||||
double Port::floor(double d)
|
||||
{
|
||||
return ::floor(d);
|
||||
}
|
||||
|
||||
double Port::pow(double x, double y)
|
||||
{
|
||||
return ::pow(x, y);
|
||||
}
|
||||
|
||||
long double Port::fmodl(long double x, long double y)
|
||||
{
|
||||
#if __FreeBSD__ || __OpenBSD__
|
||||
return ::fmod(x, y); // hack for now, fix later
|
||||
#else
|
||||
return ::fmodl(x, y);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long long Port::strtoull(const char *p, char **pend, int base)
|
||||
{
|
||||
return ::strtoull(p, pend, base);
|
||||
}
|
||||
|
||||
char *Port::ull_to_string(char *buffer, ulonglong ull)
|
||||
{
|
||||
sprintf(buffer, "%llu", ull);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull)
|
||||
{
|
||||
#if __OpenBSD__
|
||||
assert(0);
|
||||
#else
|
||||
swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull);
|
||||
#endif
|
||||
return buffer;
|
||||
}
|
||||
|
||||
double Port::ull_to_double(ulonglong ull)
|
||||
{
|
||||
return (double) ull;
|
||||
}
|
||||
|
||||
const char *Port::list_separator()
|
||||
{
|
||||
return ",";
|
||||
}
|
||||
|
||||
const wchar_t *Port::wlist_separator()
|
||||
{
|
||||
return L",";
|
||||
}
|
||||
|
||||
char *Port::strupr(char *s)
|
||||
{
|
||||
char *t = s;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
*s = toupper(*s);
|
||||
s++;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if __sun&&__SVR4
|
||||
|
||||
#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
#include <ieeefp.h>
|
||||
|
||||
static double zero = 0;
|
||||
double Port::nan = NAN;
|
||||
double Port::infinity = 1 / zero;
|
||||
double Port::dbl_max = 1.7976931348623157e308;
|
||||
double Port::dbl_min = 5e-324;
|
||||
long double Port::ldbl_max = LDBL_MAX;
|
||||
|
||||
struct PortInitializer
|
||||
{
|
||||
PortInitializer();
|
||||
};
|
||||
|
||||
static PortInitializer portinitializer;
|
||||
|
||||
PortInitializer::PortInitializer()
|
||||
{
|
||||
// gcc nan's have the sign bit set by default, so turn it off
|
||||
// Need the volatile to prevent gcc from doing incorrect
|
||||
// constant folding.
|
||||
volatile long double foo;
|
||||
foo = NAN;
|
||||
if (signbit(foo)) // signbit sometimes, not always, set
|
||||
foo = -foo; // turn off sign bit
|
||||
Port::nan = foo;
|
||||
}
|
||||
|
||||
int Port::isNan(double r)
|
||||
{
|
||||
return isnan(r);
|
||||
}
|
||||
|
||||
int Port::isNan(long double r)
|
||||
{
|
||||
return isnan(r);
|
||||
}
|
||||
|
||||
int Port::isSignallingNan(double r)
|
||||
{
|
||||
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||
* its significand, which is bit 51 of 0..63 for 64 bit doubles.
|
||||
*/
|
||||
return isNan(r) && !((((unsigned char*)&r)[6]) & 8);
|
||||
}
|
||||
|
||||
int Port::isSignallingNan(long double r)
|
||||
{
|
||||
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||
* its significand, which is bit 62 of 0..79 for 80 bit reals.
|
||||
*/
|
||||
return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40);
|
||||
}
|
||||
|
||||
#undef isfinite
|
||||
int Port::isFinite(double r)
|
||||
{
|
||||
return finite(r);
|
||||
}
|
||||
|
||||
int Port::isInfinity(double r)
|
||||
{
|
||||
return isinf(r);
|
||||
}
|
||||
|
||||
#undef signbit
|
||||
int Port::Signbit(double r)
|
||||
{
|
||||
return (long)(((long *)&r)[1] & 0x80000000);
|
||||
}
|
||||
|
||||
double Port::floor(double d)
|
||||
{
|
||||
return ::floor(d);
|
||||
}
|
||||
|
||||
double Port::pow(double x, double y)
|
||||
{
|
||||
return ::pow(x, y);
|
||||
}
|
||||
|
||||
unsigned long long Port::strtoull(const char *p, char **pend, int base)
|
||||
{
|
||||
return ::strtoull(p, pend, base);
|
||||
}
|
||||
|
||||
char *Port::ull_to_string(char *buffer, ulonglong ull)
|
||||
{
|
||||
sprintf(buffer, "%llu", ull);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull)
|
||||
{
|
||||
swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
double Port::ull_to_double(ulonglong ull)
|
||||
{
|
||||
return (double) ull;
|
||||
}
|
||||
|
||||
const char *Port::list_separator()
|
||||
{
|
||||
return ",";
|
||||
}
|
||||
|
||||
const wchar_t *Port::wlist_separator()
|
||||
{
|
||||
return L",";
|
||||
}
|
||||
|
||||
char *Port::strupr(char *s)
|
||||
{
|
||||
char *t = s;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
*s = toupper(*s);
|
||||
s++;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if IN_GCC
|
||||
|
||||
#include <math.h>
|
||||
#include <bits/nan.h>
|
||||
#include <bits/mathdef.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static double zero = 0;
|
||||
double Port::nan = NAN;
|
||||
double Port::infinity = 1 / zero;
|
||||
double Port::dbl_max = 1.7976931348623157e308;
|
||||
double Port::dbl_min = 5e-324;
|
||||
long double Port::ldbl_max = LDBL_MAX;
|
||||
|
||||
#include "d-gcc-real.h"
|
||||
extern "C" bool real_isnan (const real_t *);
|
||||
|
||||
struct PortInitializer
|
||||
{
|
||||
PortInitializer();
|
||||
};
|
||||
|
||||
static PortInitializer portinitializer;
|
||||
|
||||
PortInitializer::PortInitializer()
|
||||
{
|
||||
Port::infinity = real_t::getinfinity();
|
||||
Port::nan = real_t::getnan(real_t::LongDouble);
|
||||
}
|
||||
|
||||
#undef isnan
|
||||
int Port::isNan(double r)
|
||||
{
|
||||
#if __APPLE__
|
||||
return __inline_isnan(r);
|
||||
#else
|
||||
return ::isnan(r);
|
||||
#endif
|
||||
}
|
||||
|
||||
int Port::isNan(long double r)
|
||||
{
|
||||
return real_isnan(&r);
|
||||
}
|
||||
|
||||
int Port::isSignallingNan(double r)
|
||||
{
|
||||
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||
* its significand, which is bit 51 of 0..63 for 64 bit doubles.
|
||||
*/
|
||||
return isNan(r) && !((((unsigned char*)&r)[6]) & 8);
|
||||
}
|
||||
|
||||
int Port::isSignallingNan(long double r)
|
||||
{
|
||||
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||
* its significand, which is bit 62 of 0..79 for 80 bit reals.
|
||||
*/
|
||||
return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40);
|
||||
}
|
||||
|
||||
#undef isfinite
|
||||
int Port::isFinite(double r)
|
||||
{
|
||||
return ::finite(r);
|
||||
}
|
||||
|
||||
#undef isinf
|
||||
int Port::isInfinity(double r)
|
||||
{
|
||||
return ::isinf(r);
|
||||
}
|
||||
|
||||
#undef signbit
|
||||
int Port::Signbit(double r)
|
||||
{
|
||||
return (long)(((long *)&r)[1] & 0x80000000);
|
||||
}
|
||||
|
||||
double Port::floor(double d)
|
||||
{
|
||||
return ::floor(d);
|
||||
}
|
||||
|
||||
double Port::pow(double x, double y)
|
||||
{
|
||||
return ::pow(x, y);
|
||||
}
|
||||
|
||||
unsigned long long Port::strtoull(const char *p, char **pend, int base)
|
||||
{
|
||||
return ::strtoull(p, pend, base);
|
||||
}
|
||||
|
||||
char *Port::ull_to_string(char *buffer, ulonglong ull)
|
||||
{
|
||||
sprintf(buffer, "%llu", ull);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull)
|
||||
{
|
||||
swprintf(buffer, L"%llu", ull);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
double Port::ull_to_double(ulonglong ull)
|
||||
{
|
||||
return (double) ull;
|
||||
}
|
||||
|
||||
const char *Port::list_separator()
|
||||
{
|
||||
return ",";
|
||||
}
|
||||
|
||||
const wchar_t *Port::wlist_separator()
|
||||
{
|
||||
return L",";
|
||||
}
|
||||
|
||||
char *Port::strupr(char *s)
|
||||
{
|
||||
char *t = s;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
*s = toupper(*s);
|
||||
s++;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
81
dmd2/root/port.h
Normal file
81
dmd2/root/port.h
Normal file
@@ -0,0 +1,81 @@
|
||||
|
||||
// Copyright (c) 1999-2009 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
|
||||
#ifndef PORT_H
|
||||
#define PORT_H
|
||||
|
||||
// Portable wrapper around compiler/system specific things.
|
||||
// The idea is to minimize #ifdef's in the app code.
|
||||
|
||||
#ifndef TYPEDEFS
|
||||
#define TYPEDEFS
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
#if _MSC_VER
|
||||
typedef __int64 longlong;
|
||||
typedef unsigned __int64 ulonglong;
|
||||
|
||||
// According to VC 8.0 docs, long double is the same as double
|
||||
#define strtold strtod
|
||||
#define strtof strtod
|
||||
|
||||
#else
|
||||
typedef long long longlong;
|
||||
typedef unsigned long long ulonglong;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
typedef double d_time;
|
||||
|
||||
struct Port
|
||||
{
|
||||
static double nan;
|
||||
static double infinity;
|
||||
static double dbl_max;
|
||||
static double dbl_min;
|
||||
static long double ldbl_max;
|
||||
|
||||
#if !defined __HAIKU__ || __OpenBSD__
|
||||
#elif __GNUC__
|
||||
// These conflict with macros in math.h, should rename them
|
||||
#undef isnan
|
||||
#undef isfinite
|
||||
#undef isinfinity
|
||||
#undef signbit
|
||||
#endif
|
||||
static int isNan(double);
|
||||
static int isNan(long double);
|
||||
|
||||
static int isSignallingNan(double);
|
||||
static int isSignallingNan(long double);
|
||||
|
||||
static int isFinite(double);
|
||||
static int isInfinity(double);
|
||||
static int Signbit(double);
|
||||
|
||||
static double floor(double);
|
||||
static double pow(double x, double y);
|
||||
|
||||
static long double fmodl(long double x, long double y);
|
||||
|
||||
static ulonglong strtoull(const char *p, char **pend, int base);
|
||||
|
||||
static char *ull_to_string(char *buffer, ulonglong ull);
|
||||
static wchar_t *ull_to_string(wchar_t *buffer, ulonglong ull);
|
||||
|
||||
// Convert ulonglong to double
|
||||
static double ull_to_double(ulonglong ull);
|
||||
|
||||
// Get locale-dependent list separator
|
||||
static const char *list_separator();
|
||||
static const wchar_t *wlist_separator();
|
||||
|
||||
static char *strupr(char *);
|
||||
};
|
||||
|
||||
#endif
|
||||
290
dmd2/root/response.c
Normal file
290
dmd2/root/response.c
Normal file
@@ -0,0 +1,290 @@
|
||||
// Copyright (C) 1990-1998 by Symantec
|
||||
// Copyright (C) 2000-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// http://www.digitalmars.com
|
||||
// Written by Walter Bright
|
||||
/*
|
||||
* This source file is made available for personal use
|
||||
* only. The license is in /dmd/src/dmd/backendlicense.txt
|
||||
* For any other uses, please contact Digital Mars.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if _WIN32
|
||||
#include <tchar.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
#endif
|
||||
|
||||
/*********************************
|
||||
* #include <stdlib.h>
|
||||
* int response_expand(int *pargc,char ***pargv);
|
||||
*
|
||||
* Expand any response files in command line.
|
||||
* Response files are arguments that look like:
|
||||
* @NAME
|
||||
* The name is first searched for in the environment. If it is not
|
||||
* there, it is searched for as a file name.
|
||||
* Arguments are separated by spaces, tabs, or newlines. These can be
|
||||
* imbedded within arguments by enclosing the argument in '' or "".
|
||||
* Recursively expands nested response files.
|
||||
*
|
||||
* To use, put the line:
|
||||
* response_expand(&argc,&argv);
|
||||
* as the first executable statement in main(int argc, char **argv).
|
||||
* argc and argv are adjusted to be the new command line arguments
|
||||
* after response file expansion.
|
||||
*
|
||||
* Digital Mars's MAKE program can be notified that a program can accept
|
||||
* long command lines via environment variables by preceding the rule
|
||||
* line for the program with a *.
|
||||
*
|
||||
* Returns:
|
||||
* 0 success
|
||||
* !=0 failure (argc, argv unchanged)
|
||||
*/
|
||||
|
||||
struct Narg
|
||||
{
|
||||
int argc; /* arg count */
|
||||
int argvmax; /* dimension of nargv[] */
|
||||
char **argv;
|
||||
};
|
||||
|
||||
static int addargp(struct Narg *n, char *p)
|
||||
{
|
||||
/* The 2 is to always allow room for a NULL argp at the end */
|
||||
if (n->argc + 2 > n->argvmax)
|
||||
{
|
||||
n->argvmax = n->argc + 2;
|
||||
char **ap = n->argv;
|
||||
ap = (char **) realloc(ap,n->argvmax * sizeof(char *));
|
||||
if (!ap)
|
||||
{ if (n->argv)
|
||||
free(n->argv);
|
||||
memset(n, 0, sizeof(*n));
|
||||
return 1;
|
||||
}
|
||||
n->argv = ap;
|
||||
}
|
||||
n->argv[n->argc++] = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int response_expand(int *pargc, char ***pargv)
|
||||
{
|
||||
struct Narg n;
|
||||
int i;
|
||||
char *cp;
|
||||
int recurse = 0;
|
||||
|
||||
n.argc = 0;
|
||||
n.argvmax = 0; /* dimension of n.argv[] */
|
||||
n.argv = NULL;
|
||||
for(i=0; i<*pargc; ++i)
|
||||
{
|
||||
cp = (*pargv)[i];
|
||||
if (*cp == '@')
|
||||
{
|
||||
char *buffer;
|
||||
char *bufend;
|
||||
char *p;
|
||||
|
||||
cp++;
|
||||
p = getenv(cp);
|
||||
if (p)
|
||||
{
|
||||
buffer = strdup(p);
|
||||
if (!buffer)
|
||||
goto noexpand;
|
||||
bufend = buffer + strlen(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
long length;
|
||||
int fd;
|
||||
int nread;
|
||||
size_t len;
|
||||
|
||||
#if __DMC__
|
||||
length = filesize(cp);
|
||||
#else
|
||||
struct stat statbuf;
|
||||
if (stat(cp, &statbuf))
|
||||
goto noexpand;
|
||||
length = statbuf.st_size;
|
||||
#endif
|
||||
if (length & 0xF0000000) /* error or file too big */
|
||||
goto noexpand;
|
||||
len = length;
|
||||
buffer = (char *)malloc(len + 1);
|
||||
if (!buffer)
|
||||
goto noexpand;
|
||||
bufend = &buffer[len];
|
||||
/* Read file into buffer */
|
||||
#if _WIN32
|
||||
fd = _open(cp,O_RDONLY|O_BINARY);
|
||||
#else
|
||||
fd = open(cp,O_RDONLY);
|
||||
#endif
|
||||
if (fd == -1)
|
||||
goto noexpand;
|
||||
nread = read(fd,buffer,len);
|
||||
close(fd);
|
||||
|
||||
if (nread != len)
|
||||
goto noexpand;
|
||||
}
|
||||
|
||||
// The logic of this should match that in setargv()
|
||||
|
||||
for (p = buffer; p < bufend; p++)
|
||||
{
|
||||
char *d;
|
||||
char c,lastc;
|
||||
unsigned char instring;
|
||||
int num_slashes,non_slashes;
|
||||
|
||||
switch (*p)
|
||||
{
|
||||
case 26: /* ^Z marks end of file */
|
||||
goto L2;
|
||||
|
||||
case 0xD:
|
||||
case 0:
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
continue; // scan to start of argument
|
||||
|
||||
case '@':
|
||||
recurse = 1;
|
||||
default: /* start of new argument */
|
||||
if (addargp(&n,p))
|
||||
goto noexpand;
|
||||
instring = 0;
|
||||
c = 0;
|
||||
num_slashes = 0;
|
||||
for (d = p; 1; p++)
|
||||
{
|
||||
lastc = c;
|
||||
if (p >= bufend)
|
||||
goto Lend;
|
||||
c = *p;
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
/*
|
||||
Yes this looks strange,but this is so that we are
|
||||
MS Compatible, tests have shown that:
|
||||
\\\\"foo bar" gets passed as \\foo bar
|
||||
\\\\foo gets passed as \\\\foo
|
||||
\\\"foo gets passed as \"foo
|
||||
and \"foo gets passed as "foo in VC!
|
||||
*/
|
||||
non_slashes = num_slashes % 2;
|
||||
num_slashes = num_slashes / 2;
|
||||
for (; num_slashes > 0; num_slashes--)
|
||||
{
|
||||
d--;
|
||||
*d = '\0';
|
||||
}
|
||||
|
||||
if (non_slashes)
|
||||
{
|
||||
*(d-1) = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
instring ^= 1;
|
||||
}
|
||||
break;
|
||||
case 26:
|
||||
Lend:
|
||||
*d = 0; // terminate argument
|
||||
goto L2;
|
||||
|
||||
case 0xD: // CR
|
||||
c = lastc;
|
||||
continue; // ignore
|
||||
|
||||
case '@':
|
||||
recurse = 1;
|
||||
goto Ladd;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
if (!instring)
|
||||
{
|
||||
case '\n':
|
||||
case 0:
|
||||
*d = 0; // terminate argument
|
||||
goto Lnextarg;
|
||||
}
|
||||
default:
|
||||
Ladd:
|
||||
if (c == '\\')
|
||||
num_slashes++;
|
||||
else
|
||||
num_slashes = 0;
|
||||
*d++ = c;
|
||||
break;
|
||||
}
|
||||
#ifdef _MBCS
|
||||
if (_istlead (c)) {
|
||||
*d++ = *++p;
|
||||
if (*(d - 1) == '\0') {
|
||||
d--;
|
||||
goto Lnextarg;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
Lnextarg:
|
||||
;
|
||||
}
|
||||
L2:
|
||||
;
|
||||
}
|
||||
else if (addargp(&n,(*pargv)[i]))
|
||||
goto noexpand;
|
||||
}
|
||||
if (n.argvmax == 0)
|
||||
{
|
||||
n.argvmax = 1;
|
||||
n.argv = (char **) calloc(n.argvmax, sizeof(char *));
|
||||
if (!n.argv)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
n.argv[n.argc] = NULL;
|
||||
if (recurse)
|
||||
{
|
||||
/* Recursively expand @filename */
|
||||
if (response_expand(&n.argc,&n.argv))
|
||||
goto noexpand;
|
||||
}
|
||||
*pargc = n.argc;
|
||||
*pargv = n.argv;
|
||||
return 0; /* success */
|
||||
|
||||
noexpand: /* error */
|
||||
free(n.argv);
|
||||
/* BUG: any file buffers are not free'd */
|
||||
return 1;
|
||||
}
|
||||
155
dmd2/root/rmem.c
Normal file
155
dmd2/root/rmem.c
Normal file
@@ -0,0 +1,155 @@
|
||||
|
||||
/* Copyright (c) 2000 Digital Mars */
|
||||
/* All Rights Reserved */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
|
||||
#include "../root/rmem.h"
|
||||
#else
|
||||
#include "rmem.h"
|
||||
#endif
|
||||
|
||||
/* This implementation of the storage allocator uses the standard C allocation package.
|
||||
*/
|
||||
|
||||
Mem mem;
|
||||
|
||||
void Mem::init()
|
||||
{
|
||||
}
|
||||
|
||||
char *Mem::strdup(const char *s)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (s)
|
||||
{
|
||||
p = ::strdup(s);
|
||||
if (p)
|
||||
return p;
|
||||
error();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *Mem::malloc(size_t size)
|
||||
{ void *p;
|
||||
|
||||
if (!size)
|
||||
p = NULL;
|
||||
else
|
||||
{
|
||||
p = ::malloc(size);
|
||||
if (!p)
|
||||
error();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *Mem::calloc(size_t size, size_t n)
|
||||
{ void *p;
|
||||
|
||||
if (!size || !n)
|
||||
p = NULL;
|
||||
else
|
||||
{
|
||||
p = ::calloc(size, n);
|
||||
if (!p)
|
||||
error();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *Mem::realloc(void *p, size_t size)
|
||||
{
|
||||
if (!size)
|
||||
{ if (p)
|
||||
{ ::free(p);
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
else if (!p)
|
||||
{
|
||||
p = ::malloc(size);
|
||||
if (!p)
|
||||
error();
|
||||
}
|
||||
else
|
||||
{
|
||||
void *psave = p;
|
||||
p = ::realloc(psave, size);
|
||||
if (!p)
|
||||
{ free(psave);
|
||||
error();
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void Mem::free(void *p)
|
||||
{
|
||||
if (p)
|
||||
::free(p);
|
||||
}
|
||||
|
||||
void *Mem::mallocdup(void *o, size_t size)
|
||||
{ void *p;
|
||||
|
||||
if (!size)
|
||||
p = NULL;
|
||||
else
|
||||
{
|
||||
p = ::malloc(size);
|
||||
if (!p)
|
||||
error();
|
||||
else
|
||||
memcpy(p,o,size);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void Mem::error()
|
||||
{
|
||||
printf("Error: out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void Mem::fullcollect()
|
||||
{
|
||||
}
|
||||
|
||||
void Mem::mark(void *pointer)
|
||||
{
|
||||
(void) pointer; // necessary for VC /W4
|
||||
}
|
||||
|
||||
void Mem::setStackBottom(void *bottom)
|
||||
{
|
||||
}
|
||||
|
||||
void Mem::addroots(char* pStart, char* pEnd)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/* =================================================== */
|
||||
|
||||
void * operator new(size_t m_size)
|
||||
{
|
||||
void *p = malloc(m_size);
|
||||
if (p)
|
||||
return p;
|
||||
printf("Error: out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
return p;
|
||||
}
|
||||
|
||||
void operator delete(void *p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
||||
51
dmd2/root/rmem.h
Normal file
51
dmd2/root/rmem.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (C) 2000-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
|
||||
#ifndef ROOT_MEM_H
|
||||
#define ROOT_MEM_H
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
|
||||
typedef void (*FINALIZERPROC)(void* pObj, void* pClientData);
|
||||
|
||||
struct GC; // thread specific allocator
|
||||
|
||||
struct Mem
|
||||
{
|
||||
GC *gc; // pointer to our thread specific allocator
|
||||
Mem() { gc = NULL; }
|
||||
|
||||
void init();
|
||||
|
||||
// Derive from Mem to get these storage allocators instead of global new/delete
|
||||
void * operator new(size_t m_size);
|
||||
void * operator new(size_t m_size, Mem *mem);
|
||||
void * operator new(size_t m_size, GC *gc);
|
||||
void operator delete(void *p);
|
||||
|
||||
void * operator new[](size_t m_size);
|
||||
void operator delete[](void *p);
|
||||
|
||||
char *strdup(const char *s);
|
||||
void *malloc(size_t size);
|
||||
void *malloc_uncollectable(size_t size);
|
||||
void *calloc(size_t size, size_t n);
|
||||
void *realloc(void *p, size_t size);
|
||||
void free(void *p);
|
||||
void free_uncollectable(void *p);
|
||||
void *mallocdup(void *o, size_t size);
|
||||
void error();
|
||||
void check(void *p); // validate pointer
|
||||
void fullcollect(); // do full garbage collection
|
||||
void fullcollectNoStack(); // do full garbage collection, no scan stack
|
||||
void mark(void *pointer);
|
||||
void addroots(char* pStart, char* pEnd);
|
||||
void removeroots(char* pStart);
|
||||
void setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData);
|
||||
void setStackBottom(void *bottom);
|
||||
GC *getThreadGC(); // get apartment allocator for this thread
|
||||
};
|
||||
|
||||
extern Mem mem;
|
||||
|
||||
#endif /* ROOT_MEM_H */
|
||||
2095
dmd2/root/root.c
Normal file
2095
dmd2/root/root.c
Normal file
File diff suppressed because it is too large
Load Diff
417
dmd2/root/root.h
Normal file
417
dmd2/root/root.h
Normal file
@@ -0,0 +1,417 @@
|
||||
|
||||
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#ifndef ROOT_H
|
||||
#define ROOT_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#ifdef DEBUG
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#if __DMC__
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
typedef size_t hash_t;
|
||||
|
||||
#include "dchar.h"
|
||||
|
||||
char *wchar2ascii(wchar_t *);
|
||||
int wcharIsAscii(wchar_t *);
|
||||
char *wchar2ascii(wchar_t *, unsigned len);
|
||||
int wcharIsAscii(wchar_t *, unsigned len);
|
||||
|
||||
int bstrcmp(unsigned char *s1, unsigned char *s2);
|
||||
char *bstr2str(unsigned char *b);
|
||||
void error(const char *format, ...);
|
||||
void error(const wchar_t *format, ...);
|
||||
void warning(const char *format, ...);
|
||||
|
||||
#ifndef TYPEDEFS
|
||||
#define TYPEDEFS
|
||||
|
||||
#if _MSC_VER
|
||||
#include <float.h> // for _isnan
|
||||
#include <malloc.h> // for alloca
|
||||
// According to VC 8.0 docs, long double is the same as double
|
||||
#define strtold strtod
|
||||
#define strtof strtod
|
||||
#define isnan _isnan
|
||||
|
||||
typedef __int64 longlong;
|
||||
typedef unsigned __int64 ulonglong;
|
||||
#else
|
||||
typedef long long longlong;
|
||||
typedef unsigned long long ulonglong;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
longlong randomx();
|
||||
|
||||
/*
|
||||
* Root of our class library.
|
||||
*/
|
||||
|
||||
struct OutBuffer;
|
||||
|
||||
// Can't include arraytypes.h here, need to declare these directly.
|
||||
template <typename TYPE> struct ArrayBase;
|
||||
typedef ArrayBase<struct File> Files;
|
||||
typedef ArrayBase<char> Strings;
|
||||
|
||||
|
||||
struct Object
|
||||
{
|
||||
Object() { }
|
||||
virtual ~Object() { }
|
||||
|
||||
virtual int equals(Object *o);
|
||||
|
||||
/**
|
||||
* Returns a hash code, useful for things like building hash tables of Objects.
|
||||
*/
|
||||
virtual hash_t hashCode();
|
||||
|
||||
/**
|
||||
* Return <0, ==0, or >0 if this is less than, equal to, or greater than obj.
|
||||
* Useful for sorting Objects.
|
||||
*/
|
||||
virtual int compare(Object *obj);
|
||||
|
||||
/**
|
||||
* Pretty-print an Object. Useful for debugging the old-fashioned way.
|
||||
*/
|
||||
virtual void print();
|
||||
|
||||
virtual char *toChars();
|
||||
virtual dchar *toDchars();
|
||||
virtual void toBuffer(OutBuffer *buf);
|
||||
|
||||
/**
|
||||
* Used as a replacement for dynamic_cast. Returns a unique number
|
||||
* defined by the library user. For Object, the return value is 0.
|
||||
*/
|
||||
virtual int dyncast();
|
||||
|
||||
/**
|
||||
* Marks pointers for garbage collector by calling mem.mark() for all pointers into heap.
|
||||
*/
|
||||
/*virtual*/ // not used, disable for now
|
||||
void mark();
|
||||
};
|
||||
|
||||
struct String : Object
|
||||
{
|
||||
int ref; // != 0 if this is a reference to someone else's string
|
||||
char *str; // the string itself
|
||||
|
||||
String(char *str, int ref = 1);
|
||||
|
||||
~String();
|
||||
|
||||
static hash_t calcHash(const char *str, size_t len);
|
||||
static hash_t calcHash(const char *str);
|
||||
hash_t hashCode();
|
||||
unsigned len();
|
||||
int equals(Object *obj);
|
||||
int compare(Object *obj);
|
||||
char *toChars();
|
||||
void print();
|
||||
void mark();
|
||||
};
|
||||
|
||||
struct FileName : String
|
||||
{
|
||||
FileName(char *str, int ref);
|
||||
FileName(char *path, char *name);
|
||||
hash_t hashCode();
|
||||
int equals(Object *obj);
|
||||
static int equals(const char *name1, const char *name2);
|
||||
int compare(Object *obj);
|
||||
static int compare(const char *name1, const char *name2);
|
||||
static int absolute(const char *name);
|
||||
static char *ext(const char *);
|
||||
char *ext();
|
||||
static char *removeExt(const char *str);
|
||||
static char *name(const char *);
|
||||
char *name();
|
||||
static char *path(const char *);
|
||||
static const char *replaceName(const char *path, const char *name);
|
||||
|
||||
static char *combine(const char *path, const char *name);
|
||||
static Strings *splitPath(const char *path);
|
||||
static FileName *defaultExt(const char *name, const char *ext);
|
||||
static FileName *forceExt(const char *name, const char *ext);
|
||||
int equalsExt(const char *ext);
|
||||
|
||||
void CopyTo(FileName *to);
|
||||
static char *searchPath(Strings *path, const char *name, int cwd);
|
||||
static char *safeSearchPath(Strings *path, const char *name);
|
||||
static int exists(const char *name);
|
||||
static void ensurePathExists(const char *path);
|
||||
static char *canonicalName(const char *name);
|
||||
};
|
||||
|
||||
struct File : Object
|
||||
{
|
||||
int ref; // != 0 if this is a reference to someone else's buffer
|
||||
unsigned char *buffer; // data for our file
|
||||
unsigned len; // amount of data in buffer[]
|
||||
void *touchtime; // system time to use for file
|
||||
|
||||
FileName *name; // name of our file
|
||||
|
||||
File(char *);
|
||||
File(FileName *);
|
||||
~File();
|
||||
|
||||
void mark();
|
||||
|
||||
char *toChars();
|
||||
|
||||
/* Read file, return !=0 if error
|
||||
*/
|
||||
|
||||
int read();
|
||||
|
||||
/* Write file, either succeed or fail
|
||||
* with error message & exit.
|
||||
*/
|
||||
|
||||
void readv();
|
||||
|
||||
/* Read file, return !=0 if error
|
||||
*/
|
||||
|
||||
int mmread();
|
||||
|
||||
/* Write file, either succeed or fail
|
||||
* with error message & exit.
|
||||
*/
|
||||
|
||||
void mmreadv();
|
||||
|
||||
/* Write file, return !=0 if error
|
||||
*/
|
||||
|
||||
int write();
|
||||
|
||||
/* Write file, either succeed or fail
|
||||
* with error message & exit.
|
||||
*/
|
||||
|
||||
void writev();
|
||||
|
||||
/* Return !=0 if file exists.
|
||||
* 0: file doesn't exist
|
||||
* 1: normal file
|
||||
* 2: directory
|
||||
*/
|
||||
|
||||
/* Append to file, return !=0 if error
|
||||
*/
|
||||
|
||||
int append();
|
||||
|
||||
/* Append to file, either succeed or fail
|
||||
* with error message & exit.
|
||||
*/
|
||||
|
||||
void appendv();
|
||||
|
||||
/* Return !=0 if file exists.
|
||||
* 0: file doesn't exist
|
||||
* 1: normal file
|
||||
* 2: directory
|
||||
*/
|
||||
|
||||
int exists();
|
||||
|
||||
/* Given wildcard filespec, return an array of
|
||||
* matching File's.
|
||||
*/
|
||||
|
||||
static Files *match(char *);
|
||||
static Files *match(FileName *);
|
||||
|
||||
// Compare file times.
|
||||
// Return <0 this < f
|
||||
// =0 this == f
|
||||
// >0 this > f
|
||||
int compareTime(File *f);
|
||||
|
||||
// Read system file statistics
|
||||
void stat();
|
||||
|
||||
/* Set buffer
|
||||
*/
|
||||
|
||||
void setbuffer(void *buffer, unsigned len)
|
||||
{
|
||||
this->buffer = (unsigned char *)buffer;
|
||||
this->len = len;
|
||||
}
|
||||
|
||||
void checkoffset(size_t offset, size_t nbytes);
|
||||
|
||||
void remove(); // delete file
|
||||
};
|
||||
|
||||
struct OutBuffer : Object
|
||||
{
|
||||
unsigned char *data;
|
||||
unsigned offset;
|
||||
unsigned size;
|
||||
|
||||
OutBuffer();
|
||||
~OutBuffer();
|
||||
char *extractData();
|
||||
void mark();
|
||||
|
||||
void reserve(unsigned nbytes);
|
||||
void setsize(unsigned size);
|
||||
void reset();
|
||||
void write(const void *data, unsigned nbytes);
|
||||
void writebstring(unsigned char *string);
|
||||
void writestring(const char *string);
|
||||
void writedstring(const char *string);
|
||||
void writedstring(const wchar_t *string);
|
||||
void prependstring(const char *string);
|
||||
void writenl(); // write newline
|
||||
void writeByte(unsigned b);
|
||||
void writebyte(unsigned b) { writeByte(b); }
|
||||
void writeUTF8(unsigned b);
|
||||
void writedchar(unsigned b);
|
||||
void prependbyte(unsigned b);
|
||||
void writeword(unsigned w);
|
||||
void writeUTF16(unsigned w);
|
||||
void write4(unsigned w);
|
||||
void write(OutBuffer *buf);
|
||||
void write(Object *obj);
|
||||
void fill0(unsigned nbytes);
|
||||
void align(unsigned size);
|
||||
void vprintf(const char *format, va_list args);
|
||||
void printf(const char *format, ...);
|
||||
#if M_UNICODE
|
||||
void vprintf(const unsigned short *format, va_list args);
|
||||
void printf(const unsigned short *format, ...);
|
||||
#endif
|
||||
void bracket(char left, char right);
|
||||
unsigned bracket(unsigned i, const char *left, unsigned j, const char *right);
|
||||
void spread(unsigned offset, unsigned nbytes);
|
||||
unsigned insert(unsigned offset, const void *data, unsigned nbytes);
|
||||
void remove(unsigned offset, unsigned nbytes);
|
||||
char *toChars();
|
||||
char *extractString();
|
||||
};
|
||||
|
||||
struct Array : Object
|
||||
{
|
||||
unsigned dim;
|
||||
void **data;
|
||||
|
||||
private:
|
||||
unsigned allocdim;
|
||||
#define SMALLARRAYCAP 1
|
||||
void *smallarray[SMALLARRAYCAP]; // inline storage for small arrays
|
||||
|
||||
public:
|
||||
Array();
|
||||
~Array();
|
||||
//Array(const Array&);
|
||||
void mark();
|
||||
char *toChars();
|
||||
|
||||
void reserve(unsigned nentries);
|
||||
void setDim(unsigned newdim);
|
||||
void fixDim();
|
||||
void push(void *ptr);
|
||||
void *pop();
|
||||
void shift(void *ptr);
|
||||
void insert(unsigned index, void *ptr);
|
||||
void insert(unsigned index, Array *a);
|
||||
void append(Array *a);
|
||||
void remove(unsigned i);
|
||||
void zero();
|
||||
void *tos();
|
||||
void sort();
|
||||
Array *copy();
|
||||
};
|
||||
|
||||
template <typename TYPE>
|
||||
struct ArrayBase : Array
|
||||
{
|
||||
TYPE **tdata()
|
||||
{
|
||||
return (TYPE **)data;
|
||||
}
|
||||
|
||||
TYPE*& operator[] (size_t index)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
assert(index < dim);
|
||||
#endif
|
||||
return ((TYPE **)data)[index];
|
||||
}
|
||||
|
||||
void insert(size_t index, TYPE *v)
|
||||
{
|
||||
Array::insert(index, (void *)v);
|
||||
}
|
||||
|
||||
void insert(size_t index, ArrayBase *a)
|
||||
{
|
||||
Array::insert(index, (Array *)a);
|
||||
}
|
||||
|
||||
void append(ArrayBase *a)
|
||||
{
|
||||
Array::append((Array *)a);
|
||||
}
|
||||
|
||||
void push(TYPE *a)
|
||||
{
|
||||
Array::push((void *)a);
|
||||
}
|
||||
|
||||
ArrayBase *copy()
|
||||
{
|
||||
return (ArrayBase *)Array::copy();
|
||||
}
|
||||
};
|
||||
|
||||
struct Bits : Object
|
||||
{
|
||||
unsigned bitdim;
|
||||
unsigned allocdim;
|
||||
unsigned *data;
|
||||
|
||||
Bits();
|
||||
~Bits();
|
||||
void mark();
|
||||
|
||||
void resize(unsigned bitdim);
|
||||
|
||||
void set(unsigned bitnum);
|
||||
void clear(unsigned bitnum);
|
||||
int test(unsigned bitnum);
|
||||
|
||||
void set();
|
||||
void clear();
|
||||
void copy(Bits *from);
|
||||
Bits *clone();
|
||||
|
||||
void sub(Bits *b);
|
||||
};
|
||||
|
||||
#endif
|
||||
257
dmd2/root/speller.c
Normal file
257
dmd2/root/speller.c
Normal file
@@ -0,0 +1,257 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if __sun&&__SVR4
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
#include "speller.h"
|
||||
|
||||
const char idchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
|
||||
|
||||
/**************************************************
|
||||
* Looks for correct spelling.
|
||||
* Currently only looks a 'distance' of one from the seed[].
|
||||
* This does an exhaustive search, so can potentially be very slow.
|
||||
* Input:
|
||||
* seed wrongly spelled word
|
||||
* fp search function
|
||||
* fparg argument to search function
|
||||
* charset character set
|
||||
* Returns:
|
||||
* NULL no correct spellings found
|
||||
* void* value returned by fp() for first possible correct spelling
|
||||
*/
|
||||
|
||||
void *spellerY(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg,
|
||||
const char *charset, size_t index)
|
||||
{
|
||||
if (!seedlen)
|
||||
return NULL;
|
||||
assert(seed[seedlen] == 0);
|
||||
|
||||
char tmp[30];
|
||||
char *buf;
|
||||
if (seedlen <= sizeof(tmp) - 2)
|
||||
buf = tmp;
|
||||
else
|
||||
{
|
||||
buf = (char *)alloca(seedlen + 2); // leave space for extra char
|
||||
if (!buf)
|
||||
return NULL; // no matches
|
||||
}
|
||||
|
||||
memcpy(buf, seed, index);
|
||||
|
||||
/* Delete at seed[index] */
|
||||
if (index < seedlen)
|
||||
{
|
||||
memcpy(buf + index, seed + index + 1, seedlen - index);
|
||||
assert(buf[seedlen - 1] == 0);
|
||||
void *p = (*fp)(fparg, buf);
|
||||
if (p)
|
||||
return p;
|
||||
}
|
||||
|
||||
if (charset && *charset)
|
||||
{
|
||||
/* Substitutions */
|
||||
if (index < seedlen)
|
||||
{
|
||||
memcpy(buf, seed, seedlen + 1);
|
||||
for (const char *s = charset; *s; s++)
|
||||
{
|
||||
buf[index] = *s;
|
||||
|
||||
//printf("sub buf = '%s'\n", buf);
|
||||
void *p = (*fp)(fparg, buf);
|
||||
if (p)
|
||||
return p;
|
||||
}
|
||||
assert(buf[seedlen] == 0);
|
||||
}
|
||||
|
||||
/* Insertions */
|
||||
memcpy (buf + index + 1, seed + index, seedlen + 1 - index);
|
||||
|
||||
for (const char *s = charset; *s; s++)
|
||||
{
|
||||
buf[index] = *s;
|
||||
|
||||
//printf("ins buf = '%s'\n", buf);
|
||||
void *p = (*fp)(fparg, buf);
|
||||
if (p)
|
||||
return p;
|
||||
}
|
||||
assert(buf[seedlen + 1] == 0);
|
||||
}
|
||||
|
||||
return NULL; // didn't find any corrections
|
||||
}
|
||||
|
||||
void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg,
|
||||
const char *charset, int flag)
|
||||
{
|
||||
if (!seedlen)
|
||||
return NULL;
|
||||
|
||||
char tmp[30];
|
||||
char *buf;
|
||||
if (seedlen <= sizeof(tmp) - 2)
|
||||
buf = tmp;
|
||||
else
|
||||
{
|
||||
buf = (char *)alloca(seedlen + 2); // leave space for extra char
|
||||
if (!buf)
|
||||
return NULL; // no matches
|
||||
}
|
||||
|
||||
/* Deletions */
|
||||
memcpy(buf, seed + 1, seedlen);
|
||||
for (size_t i = 0; i < seedlen; i++)
|
||||
{
|
||||
//printf("del buf = '%s'\n", buf);
|
||||
void *p;
|
||||
if (flag)
|
||||
p = spellerY(buf, seedlen - 1, fp, fparg, charset, i);
|
||||
else
|
||||
p = (*fp)(fparg, buf);
|
||||
if (p)
|
||||
return p;
|
||||
|
||||
buf[i] = seed[i];
|
||||
}
|
||||
|
||||
/* Transpositions */
|
||||
if (!flag)
|
||||
{
|
||||
memcpy(buf, seed, seedlen + 1);
|
||||
for (size_t i = 0; i + 1 < seedlen; i++)
|
||||
{
|
||||
// swap [i] and [i + 1]
|
||||
buf[i] = seed[i + 1];
|
||||
buf[i + 1] = seed[i];
|
||||
|
||||
//printf("tra buf = '%s'\n", buf);
|
||||
void *p = (*fp)(fparg, buf);
|
||||
if (p)
|
||||
return p;
|
||||
|
||||
buf[i] = seed[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (charset && *charset)
|
||||
{
|
||||
/* Substitutions */
|
||||
memcpy(buf, seed, seedlen + 1);
|
||||
for (size_t i = 0; i < seedlen; i++)
|
||||
{
|
||||
for (const char *s = charset; *s; s++)
|
||||
{
|
||||
buf[i] = *s;
|
||||
|
||||
//printf("sub buf = '%s'\n", buf);
|
||||
void *p;
|
||||
if (flag)
|
||||
p = spellerY(buf, seedlen, fp, fparg, charset, i + 1);
|
||||
else
|
||||
p = (*fp)(fparg, buf);
|
||||
if (p)
|
||||
return p;
|
||||
}
|
||||
buf[i] = seed[i];
|
||||
}
|
||||
|
||||
/* Insertions */
|
||||
memcpy(buf + 1, seed, seedlen + 1);
|
||||
for (size_t i = 0; i <= seedlen; i++) // yes, do seedlen+1 iterations
|
||||
{
|
||||
for (const char *s = charset; *s; s++)
|
||||
{
|
||||
buf[i] = *s;
|
||||
|
||||
//printf("ins buf = '%s'\n", buf);
|
||||
void *p;
|
||||
if (flag)
|
||||
p = spellerY(buf, seedlen + 1, fp, fparg, charset, i + 1);
|
||||
else
|
||||
p = (*fp)(fparg, buf);
|
||||
if (p)
|
||||
return p;
|
||||
}
|
||||
buf[i] = seed[i]; // going past end of seed[] is ok, as we hit the 0
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; // didn't find any corrections
|
||||
}
|
||||
|
||||
void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset)
|
||||
{
|
||||
size_t seedlen = strlen(seed);
|
||||
for (int distance = 0; distance < 2; distance++)
|
||||
{ void *p = spellerX(seed, seedlen, fp, fparg, charset, distance);
|
||||
if (p)
|
||||
return p;
|
||||
// if (seedlen > 10)
|
||||
// break;
|
||||
}
|
||||
return NULL; // didn't find it
|
||||
}
|
||||
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
void *speller_test(void *fparg, const char *s)
|
||||
{
|
||||
//printf("speller_test(%s, %s)\n", fparg, s);
|
||||
if (strcmp((char *)fparg, s) == 0)
|
||||
return fparg;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void unittest_speller()
|
||||
{
|
||||
static const char *cases[][3] =
|
||||
{
|
||||
{ "hello", "hell", "y" },
|
||||
{ "hello", "hel", "y" },
|
||||
{ "hello", "ello", "y" },
|
||||
{ "hello", "llo", "y" },
|
||||
{ "hello", "hellox", "y" },
|
||||
{ "hello", "helloxy", "y" },
|
||||
{ "hello", "xhello", "y" },
|
||||
{ "hello", "xyhello", "y" },
|
||||
{ "hello", "ehllo", "y" },
|
||||
{ "hello", "helol", "y" },
|
||||
{ "hello", "abcd", "n" },
|
||||
//{ "ehllo", "helol", "y" },
|
||||
{ "hello", "helxxlo", "y" },
|
||||
{ "hello", "ehlxxlo", "n" },
|
||||
{ "hello", "heaao", "y" },
|
||||
{ "_123456789_123456789_123456789_123456789", "_123456789_123456789_123456789_12345678", "y" },
|
||||
};
|
||||
//printf("unittest_speller()\n");
|
||||
const void *p = speller("hello", &speller_test, (void *)"hell", idchars);
|
||||
assert(p != NULL);
|
||||
for (int i = 0; i < sizeof(cases)/sizeof(cases[0]); i++)
|
||||
{
|
||||
//printf("case [%d]\n", i);
|
||||
void *p = speller(cases[i][0], &speller_test, (void *)cases[i][1], idchars);
|
||||
if (p)
|
||||
assert(cases[i][2][0] == 'y');
|
||||
else
|
||||
assert(cases[i][2][0] == 'n');
|
||||
}
|
||||
//printf("unittest_speller() success\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
7
dmd2/root/speller.h
Normal file
7
dmd2/root/speller.h
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
typedef void *(fp_speller_t)(void *, const char *);
|
||||
|
||||
extern const char idchars[];
|
||||
|
||||
void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset);
|
||||
|
||||
139
dmd2/root/stringtable.c
Normal file
139
dmd2/root/stringtable.c
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "root.h"
|
||||
#include "rmem.h"
|
||||
#include "dchar.h"
|
||||
#include "lstring.h"
|
||||
#include "stringtable.h"
|
||||
|
||||
void StringTable::init(unsigned size)
|
||||
{
|
||||
table = (void **)mem.calloc(size, sizeof(void *));
|
||||
tabledim = size;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
StringTable::~StringTable()
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
// Zero out dangling pointers to help garbage collector.
|
||||
// Should zero out StringEntry's too.
|
||||
for (i = 0; i < count; i++)
|
||||
table[i] = NULL;
|
||||
|
||||
mem.free(table);
|
||||
table = NULL;
|
||||
}
|
||||
|
||||
struct StringEntry
|
||||
{
|
||||
StringEntry *left;
|
||||
StringEntry *right;
|
||||
hash_t hash;
|
||||
|
||||
StringValue value;
|
||||
|
||||
static StringEntry *alloc(const dchar *s, unsigned len);
|
||||
};
|
||||
|
||||
StringEntry *StringEntry::alloc(const dchar *s, unsigned len)
|
||||
{
|
||||
StringEntry *se;
|
||||
|
||||
se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) - sizeof(Lstring) + Lstring::size(len));
|
||||
se->value.lstring.length = len;
|
||||
se->hash = Dchar::calcHash(s,len);
|
||||
memcpy(se->value.lstring.string, s, len * sizeof(dchar));
|
||||
return se;
|
||||
}
|
||||
|
||||
void **StringTable::search(const dchar *s, unsigned len)
|
||||
{
|
||||
hash_t hash;
|
||||
unsigned u;
|
||||
int cmp;
|
||||
StringEntry **se;
|
||||
|
||||
//printf("StringTable::search(%p,%d)\n",s,len);
|
||||
hash = Dchar::calcHash(s,len);
|
||||
u = hash % tabledim;
|
||||
se = (StringEntry **)&table[u];
|
||||
//printf("\thash = %d, u = %d\n",hash,u);
|
||||
while (*se)
|
||||
{
|
||||
cmp = (*se)->hash - hash;
|
||||
if (cmp == 0)
|
||||
{
|
||||
cmp = (*se)->value.lstring.len() - len;
|
||||
if (cmp == 0)
|
||||
{
|
||||
cmp = Dchar::memcmp(s,(*se)->value.lstring.toDchars(),len);
|
||||
if (cmp == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cmp < 0)
|
||||
se = &(*se)->left;
|
||||
else
|
||||
se = &(*se)->right;
|
||||
}
|
||||
//printf("\treturn %p, %p\n",se, (*se));
|
||||
return (void **)se;
|
||||
}
|
||||
|
||||
StringValue *StringTable::lookup(const dchar *s, unsigned len)
|
||||
{ StringEntry *se;
|
||||
|
||||
se = *(StringEntry **)search(s,len);
|
||||
if (se)
|
||||
return &se->value;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
StringValue *StringTable::update(const dchar *s, unsigned len)
|
||||
{ StringEntry **pse;
|
||||
StringEntry *se;
|
||||
|
||||
pse = (StringEntry **)search(s,len);
|
||||
se = *pse;
|
||||
if (!se) // not in table: so create new entry
|
||||
{
|
||||
se = StringEntry::alloc(s, len);
|
||||
*pse = se;
|
||||
}
|
||||
return &se->value;
|
||||
}
|
||||
|
||||
StringValue *StringTable::insert(const dchar *s, unsigned len)
|
||||
{ StringEntry **pse;
|
||||
StringEntry *se;
|
||||
|
||||
pse = (StringEntry **)search(s,len);
|
||||
se = *pse;
|
||||
if (se)
|
||||
return NULL; // error: already in table
|
||||
else
|
||||
{
|
||||
se = StringEntry::alloc(s, len);
|
||||
*pse = se;
|
||||
}
|
||||
return &se->value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
48
dmd2/root/stringtable.h
Normal file
48
dmd2/root/stringtable.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 1999-2011 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
|
||||
#ifndef STRINGTABLE_H
|
||||
#define STRINGTABLE_H
|
||||
|
||||
#if __SC__
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "root.h"
|
||||
#include "dchar.h"
|
||||
#include "lstring.h"
|
||||
|
||||
struct StringValue
|
||||
{
|
||||
union
|
||||
{ int intvalue;
|
||||
void *ptrvalue;
|
||||
dchar *string;
|
||||
};
|
||||
Lstring lstring;
|
||||
};
|
||||
|
||||
struct StringTable
|
||||
{
|
||||
void **table;
|
||||
unsigned count;
|
||||
unsigned tabledim;
|
||||
|
||||
void init(unsigned size = 37);
|
||||
~StringTable();
|
||||
|
||||
StringValue *lookup(const dchar *s, unsigned len);
|
||||
StringValue *insert(const dchar *s, unsigned len);
|
||||
StringValue *update(const dchar *s, unsigned len);
|
||||
|
||||
private:
|
||||
void **search(const dchar *s, unsigned len);
|
||||
};
|
||||
|
||||
#endif
|
||||
403
dmd2/scope.c
Normal file
403
dmd2/scope.c
Normal file
@@ -0,0 +1,403 @@
|
||||
|
||||
// Copyright (c) 1999-2010 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// http://www.digitalmars.com
|
||||
// License for redistribution is by either the Artistic License
|
||||
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||
// See the included readme.txt for details.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "root.h"
|
||||
#include "speller.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "init.h"
|
||||
#include "identifier.h"
|
||||
#include "attrib.h"
|
||||
#include "dsymbol.h"
|
||||
#include "scope.h"
|
||||
#include "declaration.h"
|
||||
#include "aggregate.h"
|
||||
#include "module.h"
|
||||
#include "id.h"
|
||||
#include "lexer.h"
|
||||
|
||||
Scope *Scope::freelist = NULL;
|
||||
|
||||
void *Scope::operator new(size_t size)
|
||||
{
|
||||
if (freelist)
|
||||
{
|
||||
Scope *s = freelist;
|
||||
freelist = s->enclosing;
|
||||
//printf("freelist %p\n", s);
|
||||
assert(s->flags & SCOPEfree);
|
||||
s->flags &= ~SCOPEfree;
|
||||
return s;
|
||||
}
|
||||
|
||||
void *p = ::operator new(size);
|
||||
//printf("new %p\n", p);
|
||||
return p;
|
||||
}
|
||||
|
||||
Scope::Scope()
|
||||
{ // Create root scope
|
||||
|
||||
//printf("Scope::Scope() %p\n", this);
|
||||
this->module = NULL;
|
||||
this->scopesym = NULL;
|
||||
this->sd = NULL;
|
||||
this->enclosing = NULL;
|
||||
this->parent = NULL;
|
||||
this->sw = NULL;
|
||||
this->enclosingFinally = NULL;
|
||||
this->enclosingScopeExit = NULL;
|
||||
this->tinst = NULL;
|
||||
this->sbreak = NULL;
|
||||
this->scontinue = NULL;
|
||||
this->fes = NULL;
|
||||
this->structalign = global.structalign;
|
||||
this->func = NULL;
|
||||
this->slabel = NULL;
|
||||
this->linkage = LINKd;
|
||||
this->protection = PROTpublic;
|
||||
this->explicitProtection = 0;
|
||||
this->stc = 0;
|
||||
this->offset = 0;
|
||||
this->inunion = 0;
|
||||
this->incontract = 0;
|
||||
this->nofree = 0;
|
||||
this->noctor = 0;
|
||||
this->noaccesscheck = 0;
|
||||
this->mustsemantic = 0;
|
||||
this->intypeof = 0;
|
||||
this->parameterSpecialization = 0;
|
||||
this->ignoreTemplates = 0;
|
||||
this->callSuper = 0;
|
||||
this->flags = 0;
|
||||
this->anonAgg = NULL;
|
||||
this->lastdc = NULL;
|
||||
this->lastoffset = 0;
|
||||
this->docbuf = NULL;
|
||||
}
|
||||
|
||||
Scope::Scope(Scope *enclosing)
|
||||
{
|
||||
//printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this);
|
||||
assert(!(enclosing->flags & SCOPEfree));
|
||||
this->module = enclosing->module;
|
||||
this->func = enclosing->func;
|
||||
this->parent = enclosing->parent;
|
||||
this->scopesym = NULL;
|
||||
this->sd = NULL;
|
||||
this->sw = enclosing->sw;
|
||||
this->enclosingFinally = enclosing->enclosingFinally;
|
||||
this->enclosingScopeExit = enclosing->enclosingScopeExit;
|
||||
this->tinst = enclosing->tinst;
|
||||
this->sbreak = enclosing->sbreak;
|
||||
this->scontinue = enclosing->scontinue;
|
||||
this->fes = enclosing->fes;
|
||||
this->structalign = enclosing->structalign;
|
||||
this->enclosing = enclosing;
|
||||
#ifdef DEBUG
|
||||
if (enclosing->enclosing)
|
||||
assert(!(enclosing->enclosing->flags & SCOPEfree));
|
||||
if (this == enclosing->enclosing)
|
||||
{
|
||||
printf("this = %p, enclosing = %p, enclosing->enclosing = %p\n", this, enclosing, enclosing->enclosing);
|
||||
}
|
||||
assert(this != enclosing->enclosing);
|
||||
#endif
|
||||
this->slabel = NULL;
|
||||
this->linkage = enclosing->linkage;
|
||||
this->protection = enclosing->protection;
|
||||
this->explicitProtection = enclosing->explicitProtection;
|
||||
this->stc = enclosing->stc;
|
||||
this->offset = 0;
|
||||
this->inunion = enclosing->inunion;
|
||||
this->incontract = enclosing->incontract;
|
||||
this->nofree = 0;
|
||||
this->noctor = enclosing->noctor;
|
||||
this->noaccesscheck = enclosing->noaccesscheck;
|
||||
this->mustsemantic = enclosing->mustsemantic;
|
||||
this->intypeof = enclosing->intypeof;
|
||||
this->parameterSpecialization = enclosing->parameterSpecialization;
|
||||
this->ignoreTemplates = enclosing->ignoreTemplates;
|
||||
this->callSuper = enclosing->callSuper;
|
||||
this->flags = 0;
|
||||
this->anonAgg = NULL;
|
||||
this->lastdc = NULL;
|
||||
this->lastoffset = 0;
|
||||
this->docbuf = enclosing->docbuf;
|
||||
assert(this != enclosing);
|
||||
}
|
||||
|
||||
Scope *Scope::createGlobal(Module *module)
|
||||
{
|
||||
Scope *sc;
|
||||
|
||||
sc = new Scope();
|
||||
sc->module = module;
|
||||
sc->scopesym = new ScopeDsymbol();
|
||||
sc->scopesym->symtab = new DsymbolTable();
|
||||
|
||||
// Add top level package as member of this global scope
|
||||
Dsymbol *m = module;
|
||||
while (m->parent)
|
||||
m = m->parent;
|
||||
m->addMember(NULL, sc->scopesym, 1);
|
||||
m->parent = NULL; // got changed by addMember()
|
||||
|
||||
// Create the module scope underneath the global scope
|
||||
sc = sc->push(module);
|
||||
sc->parent = module;
|
||||
return sc;
|
||||
}
|
||||
|
||||
Scope *Scope::push()
|
||||
{
|
||||
//printf("Scope::push()\n");
|
||||
Scope *s = new Scope(this);
|
||||
assert(this != s);
|
||||
return s;
|
||||
}
|
||||
|
||||
Scope *Scope::push(ScopeDsymbol *ss)
|
||||
{
|
||||
//printf("Scope::push(%s)\n", ss->toChars());
|
||||
Scope *s = push();
|
||||
s->scopesym = ss;
|
||||
return s;
|
||||
}
|
||||
|
||||
Scope *Scope::pop()
|
||||
{
|
||||
//printf("Scope::pop() %p nofree = %d\n", this, nofree);
|
||||
Scope *enc = enclosing;
|
||||
|
||||
if (enclosing)
|
||||
enclosing->callSuper |= callSuper;
|
||||
|
||||
if (!nofree)
|
||||
{ enclosing = freelist;
|
||||
freelist = this;
|
||||
flags |= SCOPEfree;
|
||||
}
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
||||
void Scope::mergeCallSuper(Loc loc, unsigned cs)
|
||||
{
|
||||
// This does a primitive flow analysis to support the restrictions
|
||||
// regarding when and how constructors can appear.
|
||||
// It merges the results of two paths.
|
||||
// The two paths are callSuper and cs; the result is merged into callSuper.
|
||||
|
||||
if (cs != callSuper)
|
||||
{ int a;
|
||||
int b;
|
||||
|
||||
callSuper |= cs & (CSXany_ctor | CSXlabel);
|
||||
if (cs & CSXreturn)
|
||||
{
|
||||
}
|
||||
else if (callSuper & CSXreturn)
|
||||
{
|
||||
callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel));
|
||||
}
|
||||
else
|
||||
{
|
||||
a = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0;
|
||||
b = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0;
|
||||
if (a != b)
|
||||
error(loc, "one path skips constructor");
|
||||
callSuper |= cs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym)
|
||||
{ Dsymbol *s;
|
||||
Scope *sc;
|
||||
|
||||
//printf("Scope::search(%p, '%s')\n", this, ident->toChars());
|
||||
if (ident == Id::empty)
|
||||
{
|
||||
// Look for module scope
|
||||
for (sc = this; sc; sc = sc->enclosing)
|
||||
{
|
||||
assert(sc != sc->enclosing);
|
||||
if (sc->scopesym)
|
||||
{
|
||||
s = sc->scopesym->isModule();
|
||||
if (s)
|
||||
{
|
||||
//printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars());
|
||||
if (pscopesym)
|
||||
*pscopesym = sc->scopesym;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (sc = this; sc; sc = sc->enclosing)
|
||||
{
|
||||
assert(sc != sc->enclosing);
|
||||
if (sc->scopesym)
|
||||
{
|
||||
//printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind());
|
||||
s = sc->scopesym->search(loc, ident, 0);
|
||||
if (s)
|
||||
{
|
||||
if ((global.params.warnings ||
|
||||
global.params.Dversion > 1) &&
|
||||
ident == Id::length &&
|
||||
sc->scopesym->isArrayScopeSymbol() &&
|
||||
sc->enclosing &&
|
||||
sc->enclosing->search(loc, ident, NULL))
|
||||
{
|
||||
warning(s->loc, "array 'length' hides other 'length' name in outer scope");
|
||||
}
|
||||
|
||||
//printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind());
|
||||
if (pscopesym)
|
||||
*pscopesym = sc->scopesym;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Dsymbol *Scope::insert(Dsymbol *s)
|
||||
{ Scope *sc;
|
||||
|
||||
for (sc = this; sc; sc = sc->enclosing)
|
||||
{
|
||||
//printf("\tsc = %p\n", sc);
|
||||
if (sc->scopesym)
|
||||
{
|
||||
//printf("\t\tsc->scopesym = %p\n", sc->scopesym);
|
||||
if (!sc->scopesym->symtab)
|
||||
sc->scopesym->symtab = new DsymbolTable();
|
||||
return sc->scopesym->symtabInsert(s);
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Search enclosing scopes for ClassDeclaration.
|
||||
*/
|
||||
|
||||
ClassDeclaration *Scope::getClassScope()
|
||||
{ Scope *sc;
|
||||
|
||||
for (sc = this; sc; sc = sc->enclosing)
|
||||
{
|
||||
ClassDeclaration *cd;
|
||||
|
||||
if (sc->scopesym)
|
||||
{
|
||||
cd = sc->scopesym->isClassDeclaration();
|
||||
if (cd)
|
||||
return cd;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Search enclosing scopes for ClassDeclaration.
|
||||
*/
|
||||
|
||||
AggregateDeclaration *Scope::getStructClassScope()
|
||||
{ Scope *sc;
|
||||
|
||||
for (sc = this; sc; sc = sc->enclosing)
|
||||
{
|
||||
AggregateDeclaration *ad;
|
||||
|
||||
if (sc->scopesym)
|
||||
{
|
||||
ad = sc->scopesym->isClassDeclaration();
|
||||
if (ad)
|
||||
return ad;
|
||||
else
|
||||
{ ad = sc->scopesym->isStructDeclaration();
|
||||
if (ad)
|
||||
return ad;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* For TemplateDeclarations, we need to remember the Scope
|
||||
* where it was declared. So mark the Scope as not
|
||||
* to be free'd.
|
||||
*/
|
||||
|
||||
void Scope::setNoFree()
|
||||
{ Scope *sc;
|
||||
//int i = 0;
|
||||
|
||||
//printf("Scope::setNoFree(this = %p)\n", this);
|
||||
for (sc = this; sc; sc = sc->enclosing)
|
||||
{
|
||||
//printf("\tsc = %p\n", sc);
|
||||
sc->nofree = 1;
|
||||
|
||||
assert(!(flags & SCOPEfree));
|
||||
//assert(sc != sc->enclosing);
|
||||
//assert(!sc->enclosing || sc != sc->enclosing->enclosing);
|
||||
//if (++i == 10)
|
||||
//assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
* Given the failed search attempt, try to find
|
||||
* one with a close spelling.
|
||||
*/
|
||||
|
||||
void *scope_search_fp(void *arg, const char *seed)
|
||||
{
|
||||
//printf("scope_search_fp('%s')\n", seed);
|
||||
|
||||
/* If not in the lexer's string table, it certainly isn't in the symbol table.
|
||||
* Doing this first is a lot faster.
|
||||
*/
|
||||
size_t len = strlen(seed);
|
||||
if (!len)
|
||||
return NULL;
|
||||
StringValue *sv = Lexer::stringtable.lookup(seed, len);
|
||||
if (!sv)
|
||||
return NULL;
|
||||
Identifier *id = (Identifier *)sv->ptrvalue;
|
||||
assert(id);
|
||||
|
||||
Scope *sc = (Scope *)arg;
|
||||
Module::clearCache();
|
||||
Dsymbol *s = sc->search(0, id, NULL);
|
||||
return s;
|
||||
}
|
||||
|
||||
Dsymbol *Scope::search_correct(Identifier *ident)
|
||||
{
|
||||
if (global.gag)
|
||||
return NULL; // don't do it for speculative compiles; too time consuming
|
||||
|
||||
return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user