SIP4 python bindings generator for TQt
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sip4-tqt/sipgen/parser.y

6386 lines
167 KiB

/*
* The SIP parser.
*
* Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com>
*
* This file is part of SIP.
*
* This copy of SIP is licensed for use under the terms of the SIP License
* Agreement. See the file LICENSE for more details.
*
* This copy of SIP may also used under the terms of the GNU General Public
* License v2 or v3 as published by the Free Software Foundation which can be
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
*
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
%{
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "sip.h"
#define MAX_NESTED_IF 10
#define MAX_NESTED_SCOPE 10
#define inMainModule() (currentSpec->module == currentModule || currentModule->container != NULL)
static sipSpec *currentSpec; /* The current spec being parsed. */
static stringList *neededQualifiers; /* The list of required qualifiers. */
static stringList *excludedQualifiers; /* The list of excluded qualifiers. */
static moduleDef *currentModule; /* The current module being parsed. */
static mappedTypeDef *currentMappedType; /* The current mapped type. */
static enumDef *currentEnum; /* The current enum being parsed. */
static int sectionFlags; /* The current section flags. */
static int currentOverIsVirt; /* Set if the overload is virtual. */
static int currentCtorIsExplicit; /* Set if the ctor is explicit. */
static int currentIsStatic; /* Set if the current is static. */
static int currentIsSignal; /* Set if the current is Q_SIGNAL. */
static int currentIsSlot; /* Set if the current is Q_SLOT. */
static int currentIsTemplate; /* Set if the current is a template. */
static char *previousFile; /* The file just parsed. */
static parserContext currentContext; /* The current context. */
static int skipStackPtr; /* The skip stack pointer. */
static int skipStack[MAX_NESTED_IF]; /* Stack of skip flags. */
static classDef *scopeStack[MAX_NESTED_SCOPE]; /* The scope stack. */
static int sectFlagsStack[MAX_NESTED_SCOPE]; /* The section flags stack. */
static int currentScopeIdx; /* The scope stack index. */
static int currentTimelineOrder; /* The current timeline order. */
static classList *currentSupers; /* The current super-class list. */
static int defaultKwdArgs; /* Support keyword arguments by default. */
static int makeProtPublic; /* Treat protected items as public. */
static const char *getPythonName(optFlags *optflgs, const char *cname);
static classDef *findClass(sipSpec *pt, ifaceFileType iftype,
apiVersionRangeDef *api_range, scopedNameDef *fqname);
static classDef *findClassWithInterface(sipSpec *pt, ifaceFileDef *iff);
static classDef *newClass(sipSpec *pt, ifaceFileType iftype,
apiVersionRangeDef *api_range, scopedNameDef *snd);
static void finishClass(sipSpec *, moduleDef *, classDef *, optFlags *);
static exceptionDef *findException(sipSpec *pt, scopedNameDef *fqname, int new);
static mappedTypeDef *newMappedType(sipSpec *,argDef *, optFlags *);
static enumDef *newEnum(sipSpec *pt, moduleDef *mod, mappedTypeDef *mt_scope,
char *name, optFlags *of, int flags);
static void instantiateClassTemplate(sipSpec *pt, moduleDef *mod, classDef *scope, scopedNameDef *fqname, classTmplDef *tcd, templateDef *td);
static void newTypedef(sipSpec *, moduleDef *, char *, argDef *, optFlags *);
static void newVar(sipSpec *, moduleDef *, char *, int, argDef *, optFlags *,
codeBlock *, codeBlock *, codeBlock *);
static void newCtor(char *, int, signatureDef *, optFlags *, codeBlock *,
throwArgs *, signatureDef *, int, codeBlock *);
static void newFunction(sipSpec *, moduleDef *, classDef *, mappedTypeDef *,
int, int, int, int, int, char *, signatureDef *, int, int, optFlags *,
codeBlock *, codeBlock *, throwArgs *, signatureDef *, codeBlock *);
static optFlag *findOptFlag(optFlags *,char *,flagType);
static memberDef *findFunction(sipSpec *, moduleDef *, classDef *,
mappedTypeDef *, const char *, int, int, int);
static void checkAttributes(sipSpec *, moduleDef *, classDef *,
mappedTypeDef *, const char *, int);
static void newModule(FILE *fp, char *filename);
static moduleDef *allocModule();
static void parseFile(FILE *fp, char *name, moduleDef *prevmod, int optional);
static void handleEOF(void);
static void handleEOM(void);
static qualDef *findQualifier(const char *name);
static scopedNameDef *text2scopedName(ifaceFileDef *scope, char *text);
static scopedNameDef *scopeScopedName(ifaceFileDef *scope,
scopedNameDef *name);
static void pushScope(classDef *);
static void popScope(void);
static classDef *currentScope(void);
static void newQualifier(moduleDef *,int,int,char *,qualType);
static void newImport(char *filename);
static int timePeriod(char *,char *);
static int platOrFeature(char *,int);
static int isNeeded(qualDef *);
static int notSkipping(void);
static void getHooks(optFlags *,char **,char **);
static int getTransfer(optFlags *optflgs);
static int getReleaseGIL(optFlags *optflgs);
static int getHoldGIL(optFlags *optflgs);
static int getDeprecated(optFlags *optflgs);
static int getAllowNone(optFlags *optflgs);
static const char *getDocType(optFlags *optflgs);
static const char *getDocValue(optFlags *optflgs);
static void templateSignature(signatureDef *sd, int result, classTmplDef *tcd, templateDef *td, classDef *ncd);
static void templateType(argDef *ad, classTmplDef *tcd, templateDef *td, classDef *ncd);
static int search_back(const char *end, const char *start, const char *target);
static char *type2string(argDef *ad);
static char *scopedNameToString(scopedNameDef *name);
static void addUsedFromCode(sipSpec *pt, ifaceFileList **used, const char *sname);
static int sameName(scopedNameDef *snd, const char *sname);
static int stringFind(stringList *sl, const char *s);
static void setModuleName(sipSpec *pt, moduleDef *mod, const char *fullname);
static int foundInScope(scopedNameDef *fq_name, scopedNameDef *rel_name);
static void defineClass(scopedNameDef *snd, classList *supers, optFlags *of);
static classDef *completeClass(scopedNameDef *snd, optFlags *of, int has_def);
static memberDef *instantiateTemplateMethods(memberDef *tmd, moduleDef *mod);
static void instantiateTemplateEnums(sipSpec *pt, classTmplDef *tcd,
templateDef *td, classDef *cd, ifaceFileList **used,
scopedNameDef *type_names, scopedNameDef *type_values);
static void instantiateTemplateVars(sipSpec *pt, classTmplDef *tcd,
templateDef *td, classDef *cd, ifaceFileList **used,
scopedNameDef *type_names, scopedNameDef *type_values);
static overDef *instantiateTemplateOverloads(sipSpec *pt, overDef *tod,
memberDef *tmethods, memberDef *methods, classTmplDef *tcd,
templateDef *td, classDef *cd, ifaceFileList **used,
scopedNameDef *type_names, scopedNameDef *type_values);
static void resolveAnyTypedef(sipSpec *pt, argDef *ad);
static void addVariable(sipSpec *pt, varDef *vd);
static void applyTypeFlags(moduleDef *mod, argDef *ad, optFlags *flags);
static argType convertEncoding(const char *encoding);
static apiVersionRangeDef *getAPIRange(optFlags *optflgs);
static apiVersionRangeDef *convertAPIRange(moduleDef *mod, nameDef *name,
int from, int to);
static char *convertFeaturedString(char *fs);
static scopedNameDef *text2scopePart(char *text);
static int usesKeywordArgs(optFlags *optflgs, signatureDef *sd);
static char *strip(char *s);
static int isEnabledFeature(const char *name);
%}
%union {
char qchar;
char *text;
long number;
double real;
argDef memArg;
signatureDef signature;
signatureDef *optsignature;
throwArgs *throwlist;
codeBlock *codeb;
valueDef value;
valueDef *valp;
optFlags optflags;
optFlag flag;
scopedNameDef *scpvalp;
fcallDef fcall;
int boolean;
exceptionDef exceptionbase;
classDef *klass;
}
%token TK_API
%token TK_DEFENCODING
%token TK_PLUGIN
%token TK_DOCSTRING
%token TK_DOC
%token TK_EXPORTEDDOC
%token TK_MAKEFILE
%token TK_ACCESSCODE
%token TK_GETCODE
%token TK_SETCODE
%token TK_PREINITCODE
%token TK_INITCODE
%token TK_POSTINITCODE
%token TK_UNITCODE
%token TK_MODCODE
%token TK_TYPECODE
%token TK_PREPYCODE
%token TK_COPYING
%token TK_MAPPEDTYPE
%token <codeb> TK_CODELINE
%token TK_IF
%token TK_END
%token <text> TK_NAME
%token <text> TK_PATHNAME
%token <text> TK_STRING
%token TK_VIRTUALCATCHERCODE
%token TK_TRAVERSECODE
%token TK_CLEARCODE
%token TK_GETBUFFERCODE
%token TK_RELEASEBUFFERCODE
%token TK_READBUFFERCODE
%token TK_WRITEBUFFERCODE
%token TK_SEGCOUNTCODE
%token TK_CHARBUFFERCODE
%token TK_PICKLECODE
%token TK_METHODCODE
%token TK_FROMTYPE
%token TK_TOTYPE
%token TK_TOSUBCLASS
%token TK_INCLUDE
%token TK_OPTINCLUDE
%token TK_IMPORT
%token TK_EXPHEADERCODE
%token TK_MODHEADERCODE
%token TK_TYPEHEADERCODE
%token TK_MODULE
%token TK_CMODULE
%token TK_CONSMODULE
%token TK_COMPOMODULE
%token TK_CLASS
%token TK_STRUCT
%token TK_PUBLIC
%token TK_PROTECTED
%token TK_PRIVATE
%token TK_SIGNALS
%token TK_SIGNAL_METHOD
%token TK_SLOTS
%token TK_SLOT_METHOD
%token TK_BOOL
%token TK_SHORT
%token TK_INT
%token TK_LONG
%token TK_FLOAT
%token TK_DOUBLE
%token TK_CHAR
%token TK_WCHAR_T
%token TK_VOID
%token TK_PYOBJECT
%token TK_PYTUPLE
%token TK_PYLIST
%token TK_PYDICT
%token TK_PYCALLABLE
%token TK_PYSLICE
%token TK_PYTYPE
%token TK_VIRTUAL
%token TK_ENUM
%token TK_SIGNED
%token TK_UNSIGNED
%token TK_SCOPE
%token TK_LOGICAL_OR
%token TK_CONST
%token TK_STATIC
%token TK_SIPSIGNAL
%token TK_SIPSLOT
%token TK_SIPANYSLOT
%token TK_SIPRXCON
%token TK_SIPRXDIS
%token TK_SIPSLOTCON
%token TK_SIPSLOTDIS
%token <number> TK_NUMBER
%token <real> TK_REAL
%token TK_TYPEDEF
%token TK_NAMESPACE
%token TK_TIMELINE
%token TK_PLATFORMS
%token TK_FEATURE
%token TK_LICENSE
%token <qchar> TK_QCHAR
%token TK_TRUE
%token TK_FALSE
%token TK_NULL
%token TK_OPERATOR
%token TK_THROW
%token TK_QOBJECT
%token TK_EXCEPTION
%token TK_RAISECODE
%token TK_EXPLICIT
%token TK_TEMPLATE
%token TK_ELLIPSIS
%token TK_DEFMETATYPE
%token TK_DEFSUPERTYPE
%type <memArg> argvalue
%type <memArg> argtype
%type <memArg> cpptype
%type <memArg> basetype
%type <signature> template
%type <signature> arglist
%type <signature> rawarglist
%type <signature> cpptypelist
%type <optsignature> optsig
%type <optsignature> optctorsig
%type <throwlist> optexceptions
%type <throwlist> exceptionlist
%type <number> optslot
%type <number> optref
%type <number> optconst
%type <number> optvirtual
%type <number> optabstract
%type <number> deref
%type <number> optnumber
%type <value> simplevalue
%type <valp> value
%type <valp> expr
%type <valp> optassign
%type <codeb> optaccesscode
%type <codeb> optgetcode
%type <codeb> optsetcode
%type <codeb> exphdrcode
%type <codeb> modhdrcode
%type <codeb> typehdrcode
%type <codeb> opttypehdrcode
%type <codeb> travcode
%type <codeb> clearcode
%type <codeb> getbufcode
%type <codeb> releasebufcode
%type <codeb> readbufcode
%type <codeb> writebufcode
%type <codeb> segcountcode
%type <codeb> charbufcode
%type <codeb> picklecode
%type <codeb> modcode
%type <codeb> typecode
%type <codeb> codeblock
%type <codeb> codelines
%type <codeb> virtualcatchercode
%type <codeb> methodcode
%type <codeb> raisecode
%type <codeb> docstring
%type <codeb> optdocstring
%type <text> operatorname
%type <text> optfilename
%type <text> optname
%type <text> dottedname
%type <optflags> optflags
%type <optflags> flaglist
%type <flag> flag
%type <flag> flagvalue
%type <qchar> optunop
%type <qchar> binop
%type <scpvalp> scopepart
%type <scpvalp> scopedname
%type <fcall> exprlist
%type <boolean> qualifiers
%type <boolean> oredqualifiers
%type <boolean> modlang
%type <boolean> optclassbody
%type <exceptionbase> baseexception
%type <klass> class
%%
specification: statement
| specification statement
;
statement: {
/*
* We don't do these in parserEOF() because the parser is reading
* ahead and that would be too early.
*/
if (previousFile != NULL)
{
handleEOF();
if (currentContext.prevmod != NULL)
handleEOM();
free(previousFile);
previousFile = NULL;
}
} modstatement
;
modstatement: module
| consmodule
| compmodule
| plugin
| copying
| include
| optinclude
| import
| api
| timeline
| platforms
| feature
| license
| defencoding
| defmetatype
| defsupertype
| exphdrcode {
if (notSkipping())
appendCodeBlock(&currentSpec->exphdrcode, $1);
}
| modhdrcode {
if (notSkipping())
appendCodeBlock(&currentModule->hdrcode, $1);
}
| modcode {
if (notSkipping())
appendCodeBlock(&currentModule->cppcode, $1);
}
| preinitcode
| initcode
| postinitcode
| unitcode
| prepycode
| doc
| exporteddoc
| makefile
| mappedtype
| mappedtypetmpl
| nsstatement
;
nsstatement: ifstart
| ifend
| namespace
| struct
| class
| classtmpl
| exception
| typedef
| enum
| function
| variable
| typehdrcode {
if (notSkipping())
{
classDef *scope = currentScope();
if (scope == NULL)
yyerror("%TypeHeaderCode can only be used in a namespace, class or mapped type");
appendCodeBlock(&scope->iff->hdrcode, $1);
}
}
;
defencoding: TK_DEFENCODING TK_STRING {
if (notSkipping())
{
if ((currentModule->encoding = convertEncoding($2)) == no_type)
yyerror("The value of %DefaultEncoding must be one of \"ASCII\", \"Latin-1\", \"UTF-8\" or \"None\"");
}
}
;
plugin: TK_PLUGIN TK_NAME {
appendString(&currentSpec->plugins, $2);
}
;
api: TK_API TK_NAME TK_NUMBER {
if (notSkipping())
{
apiVersionRangeDef *avd;
if (findAPI(currentSpec, $2) != NULL)
yyerror("The API name in the %API directive has already been defined");
if ($3 < 1)
yyerror("The version number in the %API directive must be greater than or equal to 1");
avd = sipMalloc(sizeof (apiVersionRangeDef));
avd->api_name = cacheName(currentSpec, $2);
avd->from = $3;
avd->to = -1;
avd->next = currentModule->api_versions;
currentModule->api_versions = avd;
if (inMainModule())
setIsUsedName(avd->api_name);
}
}
;
exception: TK_EXCEPTION scopedname baseexception optflags '{' opttypehdrcode raisecode '}' ';' {
if (notSkipping())
{
exceptionDef *xd;
const char *pyname;
if (currentSpec->genc)
yyerror("%Exception not allowed in a C module");
pyname = getPythonName(&$4, scopedNameTail($2));
checkAttributes(currentSpec, currentModule, NULL, NULL,
pyname, FALSE);
xd = findException(currentSpec, $2, TRUE);
if (xd->cd != NULL)
yyerror("%Exception name has already been seen as a class name - it must be defined before being used");
if (xd->iff->module != NULL)
yyerror("The %Exception has already been defined");
/* Complete the definition. */
xd->iff->module = currentModule;
xd->iff->hdrcode = $6;
xd->pyname = pyname;
xd->bibase = $3.bibase;
xd->base = $3.base;
xd->raisecode = $7;
if (findOptFlag(&$4, "Default", bool_flag) != NULL)
currentModule->defexception = xd;
if (xd->bibase != NULL || xd->base != NULL)
xd->exceptionnr = currentModule->nrexceptions++;
}
}
;
baseexception: {
$$.bibase = NULL;
$$.base = NULL;
}
| '(' scopedname ')' {
exceptionDef *xd;
$$.bibase = NULL;
$$.base = NULL;
/* See if it is a defined exception. */
for (xd = currentSpec->exceptions; xd != NULL; xd = xd->next)
if (compareScopedNames(xd->iff->fqcname, $2) == 0)
{
$$.base = xd;
break;
}
if (xd == NULL && $2->next == NULL && strncmp($2->name, "SIP_", 4) == 0)
{
/* See if it is a builtin exception. */
static char *builtins[] = {
"Exception",
"StopIteration",
"StandardError",
"ArithmeticError",
"LookupError",
"AssertionError",
"AttributeError",
"EOFError",
"FloatingPointError",
"EnvironmentError",
"IOError",
"OSError",
"ImportError",
"IndexError",
"KeyError",
"KeyboardInterrupt",
"MemoryError",
"NameError",
"OverflowError",
"RuntimeError",
"NotImplementedError",
"SyntaxError",
"IndentationError",
"TabError",
"ReferenceError",
"SystemError",
"SystemExit",
"TypeError",
"UnboundLocalError",
"UnicodeError",
"UnicodeEncodeError",
"UnicodeDecodeError",
"UnicodeTranslateError",
"ValueError",
"ZeroDivisionError",
"WindowsError",
"VMSError",
NULL
};
char **cp;
for (cp = builtins; *cp != NULL; ++cp)
if (strcmp($2->name + 4, *cp) == 0)
{
$$.bibase = *cp;
break;
}
}
if ($$.bibase == NULL && $$.base == NULL)
yyerror("Unknown exception base type");
}
;
raisecode: TK_RAISECODE codeblock {
$$ = $2;
}
;
mappedtype: TK_MAPPEDTYPE basetype optflags {
if (notSkipping())
currentMappedType = newMappedType(currentSpec, &$2, &$3);
} mtdefinition
;
mappedtypetmpl: template TK_MAPPEDTYPE basetype optflags {
int a;
if (currentSpec->genc)
yyerror("%MappedType templates not allowed in a C module");
/* Check the template arguments are basic types or simple names. */
for (a = 0; a < $1.nrArgs; ++a)
{
argDef *ad = &$1.args[a];
if (ad->atype == defined_type && ad->u.snd->next != NULL)
yyerror("%MappedType template arguments must be simple names");
}
if ($3.atype != template_type)
yyerror("%MappedType template must map a template type");
if (notSkipping())
{
mappedTypeTmplDef *mtt;
ifaceFileDef *iff;
/* Check a template hasn't already been provided. */
for (mtt = currentSpec->mappedtypetemplates; mtt != NULL; mtt = mtt->next)
if (compareScopedNames(mtt->mt->type.u.td->fqname, $3.u.td->fqname) == 0 && sameTemplateSignature(&mtt->mt->type.u.td->types, &$3.u.td->types, TRUE))
yyerror("%MappedType template for this type has already been defined");
$3.nrderefs = 0;
$3.argflags = 0;
mtt = sipMalloc(sizeof (mappedTypeTmplDef));
mtt->sig = $1;
mtt->mt = allocMappedType(currentSpec, &$3);
mtt->mt->doctype = getDocType(&$4);
mtt->next = currentSpec->mappedtypetemplates;
currentSpec->mappedtypetemplates = mtt;
currentMappedType = mtt->mt;
/* Create a dummy interface file. */
iff = sipMalloc(sizeof (ifaceFileDef));
iff->hdrcode = NULL;
mtt->mt->iff = iff;
}
} mtdefinition
;
mtdefinition: '{' mtbody '}' ';' {
if (notSkipping())
{
if (currentMappedType->convfromcode == NULL)
yyerror("%MappedType must have a %ConvertFromTypeCode directive");
if (currentMappedType->convtocode == NULL)
yyerror("%MappedType must have a %ConvertToTypeCode directive");
currentMappedType = NULL;
}
}
;
mtbody: mtline
| mtbody mtline
;
mtline: typehdrcode {
if (notSkipping())
appendCodeBlock(&currentMappedType->iff->hdrcode, $1);
}
| TK_FROMTYPE codeblock {
if (notSkipping())
{
if (currentMappedType -> convfromcode != NULL)
yyerror("%MappedType has more than one %ConvertFromTypeCode directive");
currentMappedType -> convfromcode = $2;
}
}
| TK_TOTYPE codeblock {
if (notSkipping())
{
if (currentMappedType -> convtocode != NULL)
yyerror("%MappedType has more than one %ConvertToTypeCode directive");
currentMappedType -> convtocode = $2;
}
}
| enum
| mtfunction
;
mtfunction: TK_STATIC cpptype TK_NAME '(' arglist ')' optconst optexceptions optflags optsig ';' optdocstring methodcode {
if (notSkipping())
{
applyTypeFlags(currentModule, &$2, &$9);
$5.result = $2;
newFunction(currentSpec, currentModule, NULL,
currentMappedType, 0, TRUE, FALSE, FALSE, FALSE, $3,
&$5, $7, FALSE, &$9, $13, NULL, $8, $10, $12);
}
}
;
namespace: TK_NAMESPACE TK_NAME {
if (currentSpec -> genc)
yyerror("namespace definition not allowed in a C module");
if (notSkipping())
{
classDef *ns, *c_scope;
ifaceFileDef *scope;
if ((c_scope = currentScope()) != NULL)
scope = c_scope->iff;
else
scope = NULL;
ns = newClass(currentSpec, namespace_iface, NULL,
text2scopedName(scope, $2));
pushScope(ns);
sectionFlags = 0;
}
} '{' nsbody '}' ';' {
if (notSkipping())
{
if (inMainModule())
{
classDef *ns = currentScope();
setIsUsedName(ns->iff->name);
setIsUsedName(ns->pyname);
}
popScope();
}
}
;
nsbody: nsstatement
| nsbody nsstatement
;
platforms: TK_PLATFORMS {
qualDef *qd;
for (qd = currentModule -> qualifiers; qd != NULL; qd = qd -> next)
if (qd -> qtype == platform_qualifier)
yyerror("%Platforms has already been defined for this module");
}
'{' platformlist '}' {
qualDef *qd;
int nrneeded;
/*
* Check that exactly one platform in the set was
* requested.
*/
nrneeded = 0;
for (qd = currentModule -> qualifiers; qd != NULL; qd = qd -> next)
if (qd -> qtype == platform_qualifier && isNeeded(qd))
++nrneeded;
if (nrneeded > 1)
yyerror("No more than one of these %Platforms must be specified with the -t flag");
}
;
platformlist: platform
| platformlist platform
;
platform: TK_NAME {
newQualifier(currentModule,-1,-1,$1,platform_qualifier);
}
;
feature: TK_FEATURE TK_NAME {
newQualifier(currentModule,-1,-1,$2,feature_qualifier);
}
;
timeline: TK_TIMELINE {
currentTimelineOrder = 0;
}
'{' qualifierlist '}' {
qualDef *qd;
int nrneeded;
/*
* Check that exactly one time slot in the set was
* requested.
*/
nrneeded = 0;
for (qd = currentModule -> qualifiers; qd != NULL; qd = qd -> next)
if (qd -> qtype == time_qualifier && isNeeded(qd))
++nrneeded;
if (nrneeded > 1)
yyerror("At most one of this %Timeline must be specified with the -t flag");
currentModule -> nrtimelines++;
}
;
qualifierlist: qualifiername
| qualifierlist qualifiername
;
qualifiername: TK_NAME {
newQualifier(currentModule,currentModule -> nrtimelines,currentTimelineOrder++,$1,time_qualifier);
}
;
ifstart: TK_IF '(' qualifiers ')' {
if (skipStackPtr >= MAX_NESTED_IF)
yyerror("Internal error: increase the value of MAX_NESTED_IF");
/* Nested %Ifs are implicit logical ands. */
if (skipStackPtr > 0)
$3 = ($3 && skipStack[skipStackPtr - 1]);
skipStack[skipStackPtr++] = $3;
}
;
oredqualifiers: TK_NAME {
$$ = platOrFeature($1,FALSE);
}
| '!' TK_NAME {
$$ = platOrFeature($2,TRUE);
}
| oredqualifiers TK_LOGICAL_OR TK_NAME {
$$ = (platOrFeature($3,FALSE) || $1);
}
| oredqualifiers TK_LOGICAL_OR '!' TK_NAME {
$$ = (platOrFeature($4,TRUE) || $1);
}
;
qualifiers: oredqualifiers
| optname '-' optname {
$$ = timePeriod($1,$3);
}
;
ifend: TK_END {
if (skipStackPtr-- <= 0)
yyerror("Too many %End directives");
}
;
license: TK_LICENSE optflags {
optFlag *of;
if ($2.nrFlags == 0)
yyerror("%License details not specified");
if ((of = findOptFlag(&$2,"Type",string_flag)) == NULL)
yyerror("%License type not specified");
currentModule -> license = sipMalloc(sizeof (licenseDef));
currentModule -> license -> type = of -> fvalue.sval;
currentModule -> license -> licensee =
((of = findOptFlag(&$2,"Licensee",string_flag)) != NULL)
? of -> fvalue.sval : NULL;
currentModule -> license -> timestamp =
((of = findOptFlag(&$2,"Timestamp",string_flag)) != NULL)
? of -> fvalue.sval : NULL;
currentModule -> license -> sig =
((of = findOptFlag(&$2,"Signature",string_flag)) != NULL)
? of -> fvalue.sval : NULL;
}
;
defmetatype:TK_DEFMETATYPE dottedname {
if (notSkipping())
{
if (currentModule->defmetatype != NULL)
yyerror("%DefaultMetatype has already been defined for this module");
currentModule->defmetatype = cacheName(currentSpec, $2);
}
}
;
defsupertype: TK_DEFSUPERTYPE dottedname {
if (notSkipping())
{
if (currentModule->defsupertype != NULL)
yyerror("%DefaultSupertype has already been defined for this module");
currentModule->defsupertype = cacheName(currentSpec, $2);
}
}
;
consmodule: TK_CONSMODULE dottedname {
/* Make sure this is the first mention of a module. */
if (currentSpec->module != currentModule)
yyerror("A %ConsolidatedModule cannot be %Imported");
if (currentModule->fullname != NULL)
yyerror("%ConsolidatedModule must appear before any %Module or %CModule directive");
setModuleName(currentSpec, currentModule, $2);
setIsConsolidated(currentModule);
}
;
compmodule: TK_COMPOMODULE dottedname {
/* Make sure this is the first mention of a module. */
if (currentSpec->module != currentModule)
yyerror("A %CompositeModule cannot be %Imported");
if (currentModule->fullname != NULL)
yyerror("%CompositeModule must appear before any %Module or %CModule directive");
setModuleName(currentSpec, currentModule, $2);
setIsComposite(currentModule);
}
;
module: modlang dottedname optnumber {
/* Check the module hasn't already been defined. */
moduleDef *mod;
for (mod = currentSpec->modules; mod != NULL; mod = mod->next)
if (mod->fullname != NULL && strcmp(mod->fullname->text, $2) == 0)
yyerror("Module is already defined");
/*
* If we are in a container module then create a component module
* and make it current.
*/
if (isContainer(currentModule) || currentModule->container != NULL)
{
mod = allocModule();
mod->file = currentContext.filename;
mod->container = (isContainer(currentModule) ? currentModule : currentModule->container);
currentModule = mod;
}
setModuleName(currentSpec, currentModule, $2);
currentModule->version = $3;
if (currentSpec->genc < 0)
currentSpec->genc = $1;
else if (currentSpec->genc != $1)
yyerror("Cannot mix C and C++ modules");
}
;
modlang: TK_MODULE {
$$ = FALSE;
}
| TK_CMODULE {
$$ = TRUE;
}
;
dottedname: TK_NAME
| TK_PATHNAME {
/*
* The grammar design is a bit broken and this is the easiest way
* to allow periods in names.
*/
char *cp;
for (cp = $1; *cp != '\0'; ++cp)
if (*cp != '.' && *cp != '_' && !isalnum(*cp))
yyerror("Invalid character in name");
$$ = $1;
}
;
optnumber: {
$$ = -1;
}
| TK_NUMBER
;
include: TK_INCLUDE TK_PATHNAME {
parseFile(NULL, $2, NULL, FALSE);
}
;
optinclude: TK_OPTINCLUDE TK_PATHNAME {
parseFile(NULL, $2, NULL, TRUE);
}
;
import: TK_IMPORT TK_PATHNAME {
newImport($2);
}
;
optaccesscode: {
$$ = NULL;
}
| TK_ACCESSCODE codeblock {
$$ = $2;
}
;
optgetcode: {
$$ = NULL;
}
| TK_GETCODE codeblock {
$$ = $2;
}
;
optsetcode: {
$$ = NULL;
}
| TK_SETCODE codeblock {
$$ = $2;
}
;
copying: TK_COPYING codeblock {
appendCodeBlock(&currentModule->copying, $2);
}
;
exphdrcode: TK_EXPHEADERCODE codeblock {
$$ = $2;
}
;
modhdrcode: TK_MODHEADERCODE codeblock {
$$ = $2;
}
;
typehdrcode: TK_TYPEHEADERCODE codeblock {
$$ = $2;
}
;
opttypehdrcode: {
$$ = NULL;
}
| typehdrcode
;
travcode: TK_TRAVERSECODE codeblock {
$$ = $2;
}
;
clearcode: TK_CLEARCODE codeblock {
$$ = $2;
}
;
getbufcode: TK_GETBUFFERCODE codeblock {
$$ = $2;
}
;
releasebufcode: TK_RELEASEBUFFERCODE codeblock {
$$ = $2;
}
;
readbufcode: TK_READBUFFERCODE codeblock {
$$ = $2;
}
;
writebufcode: TK_WRITEBUFFERCODE codeblock {
$$ = $2;
}
;
segcountcode: TK_SEGCOUNTCODE codeblock {
$$ = $2;
}
;
charbufcode: TK_CHARBUFFERCODE codeblock {
$$ = $2;
}
;
picklecode: TK_PICKLECODE codeblock {
$$ = $2;
}
;
modcode: TK_MODCODE codeblock {
$$ = $2;
}
;
typecode: TK_TYPECODE codeblock {
$$ = $2;
}
;
preinitcode: TK_PREINITCODE codeblock {
if (notSkipping())
appendCodeBlock(&currentModule->preinitcode, $2);
}
;
initcode: TK_INITCODE codeblock {
if (notSkipping())
appendCodeBlock(&currentModule->initcode, $2);
}
;
postinitcode: TK_POSTINITCODE codeblock {
if (notSkipping())
appendCodeBlock(&currentModule->postinitcode, $2);
}
;
unitcode: TK_UNITCODE codeblock {
if (notSkipping())
appendCodeBlock(&currentModule->unitcode, $2);
}
;
prepycode: TK_PREPYCODE codeblock {
/*
* This is a no-op and is retained for compatibility
* until the last use of it (by SIP v3) can be removed
* from PyQt.
*/
}
;
doc: TK_DOC codeblock {
if (inMainModule())
appendCodeBlock(&currentSpec -> docs,$2);
}
;
exporteddoc: TK_EXPORTEDDOC codeblock {
appendCodeBlock(&currentSpec -> docs,$2);
}
;
makefile: TK_MAKEFILE TK_PATHNAME optfilename codeblock {
if (inMainModule())
yywarning("%Makefile is ignored, please use the -b flag instead");
}
;
codeblock: codelines TK_END
;
codelines: TK_CODELINE
| codelines TK_CODELINE {
$$ = $1;
append(&$$->frag, $2->frag);
free($2->frag);
free((char *)$2->filename);
free($2);
}
;
enum: TK_ENUM optname optflags {
if (notSkipping())
{
if (sectionFlags != 0 && (sectionFlags & ~(SECT_IS_PUBLIC | SECT_IS_PROT)) != 0)
yyerror("Class enums must be in the public or protected sections");
currentEnum = newEnum(currentSpec, currentModule,
currentMappedType, $2, &$3, sectionFlags);
}
} '{' optenumbody '}' ';'
;
optfilename: {
$$ = NULL;
}
| TK_PATHNAME {
$$ = $1;
}
;
optname: {
$$ = NULL;
}
| TK_NAME {
$$ = $1;
}
;
optenumbody:
| enumbody
;
enumbody: enumline
| enumbody enumline
;
enumline: ifstart
| ifend
| TK_NAME optenumassign optflags optcomma {
if (notSkipping())
{
enumMemberDef *emd, **tail;
/* Note that we don't use the assigned value. */
emd = sipMalloc(sizeof (enumMemberDef));
emd -> pyname = cacheName(currentSpec, getPythonName(&$3, $1));
emd -> cname = $1;
emd -> ed = currentEnum;
emd -> next = NULL;
checkAttributes(currentSpec, currentModule, emd->ed->ecd,
emd->ed->emtd, emd->pyname->text, FALSE);
/* Append to preserve the order. */
for (tail = &currentEnum->members; *tail != NULL; tail = &(*tail)->next)
;
*tail = emd;
if (inMainModule())
setIsUsedName(emd -> pyname);
}
}
;
optcomma:
| ','
;
optenumassign:
| '=' value
;
optassign: {
$$ = NULL;
}
| '=' expr {
$$ = $2;
}
;
expr: value
| expr binop value {
valueDef *vd;
if ($1 -> vtype == string_value || $3 -> vtype == string_value)
yyerror("Invalid binary operator for string");