%{ /**************************************************************************** ** $Id$ ** ** Copyright (C) 2001-2002 Trolltech AS. All rights reserved. ** ** This file is part of the Qt Script for Applications framework (QSA). ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** ** Licensees holding a valid QSA Beta Evaluation Version license may use ** this file in accordance with the QSA Beta Evaluation Version License ** Agreement provided with the Software. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for ** information about QSA Commercial License Agreements. ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** *****************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include "qsengine.h" #include "qsnodes.h" #include "qslexer.h" /* default values for bison */ #define YYDEBUG 0 #define YYMAXDEPTH 0 #ifdef QSDEBUGGER #define YYERROR_VERBOSE #define DBG(l, s, e) { l->setLoc(s.first_line, e.last_line); } // location #else #undef YYLSP_NEEDED #define DBG(l, s, e) #endif extern int yylex(); int yyerror (const char *); bool automatic(); %} %union { int ival; double dval; QString *ustr; QSNode *node; QSStatementNode *stat; QSParameterNode *param; QSFunctionBodyNode *body; QSFuncDeclNode *func; QSClassDefNode *clss; QSProgramNode *prog; QSAssignExprNode *init; QSSourceElementNode *src; QSSourceElementsNode *srcs; QSStatListNode *slist; QSArgumentsNode *args; QSArgumentListNode *alist; QSCaseBlockNode *cblk; QSClauseListNode *clist; QSCaseClauseNode *ccl; QSElementNode *elm; QSElisionNode *eli; QSTypeNode *type; QSTypedVarNode *tvar; QSVarBindingNode *vbin; QSVarBindingListNode *blist; QSAttributeNode *attrs; QSAttribute attr; Operator op; } %start Program /* expect a shift/reduce conflict from the "dangling else" problem when using bison the warning can be supressed */ // %expect 1 /* literals */ %token NULLTOKEN TRUETOKEN FALSETOKEN %token STRING NUMBER /* keywords */ %token BREAK CASE DEFAULT FOR NEW VAR CONTINUE %token FUNCTION RETURN VOID DELETE %token IF THIS DO WHILE ELSE IN INSTANCEOF TYPEOF IS %token SWITCH WITH RESERVED %token THROW TRY CATCH FINALLY %token CLASS CONSTRUCTOR EXTENDS %token ABSTRACT FINAL PRIVATE PUBLIC STATIC CONST %token PACKAGE IMPORT /* punctuators */ %token EQEQ NE /* == and != */ %token STREQ STRNEQ /* === and !== */ %token LE GE /* < and > */ %token OR AND /* || and && */ %token PLUSPLUS MINUSMINUS /* ++ and -- */ %token LSHIFT /* << */ %token RSHIFT URSHIFT /* >> and >>> */ %token PLUSEQUAL MINUSEQUAL /* += and -= */ %token MULTEQUAL DIVEQUAL /* *= and /= */ %token LSHIFTEQUAL /* <<= */ %token RSHIFTEQUAL URSHIFTEQUAL /* >>= and >>>= */ %token ANDEQUAL MODEQUAL /* &= and %= */ %token XOREQUAL OREQUAL /* ^= and |= */ /* terminal types */ %token NUMBER %token STRING %token IDENT /* non-terminal types */ %type Literal PrimaryExpr Expr MemberExpr FunctionExpr NewExpr CallExpr %type ArrayLiteral PropertyName PropertyNameAndValueList %type LeftHandSideExpr PostfixExpr UnaryExpr %type MultiplicativeExpr AdditiveExpr %type ShiftExpr RelationalExpr EqualityExpr %type BitwiseANDExpr BitwiseXORExpr BitwiseORExpr %type LogicalANDExpr LogicalORExpr %type ConditionalExpr AssignmentExpr %type ExprOpt %type CallExpr %type Catch Finally %type Statement Block %type VariableDefinition EmptyStatement ExprStatement %type IfStatement IterationStatement ContinueStatement %type BreakStatement ReturnStatement WithStatement %type SwitchStatement LabelledStatement %type ThrowStatement TryStatement %type PackageDefinition ImportStatement %type ClassDefinition %type StatementList %type FunctionDeclaration %type FunctionBody %type SourceElement %type SourceElements %type FormalParameterList %type AssignmentOperator %type Program %type Arguments %type ArgumentList %type CaseBlock %type CaseClause DefaultClause %type CaseClauses CaseClausesOpt %type Elision ElisionOpt %type ElementList %type VariableDefinitionKind %type Attribute %type Attributes %type TypeExpression ResultSignature %type TypedVariable %type VariableBinding %type VariableBindingList %type PackageName %% Literal: NULLTOKEN { $$ = new QSNullNode(); } | TRUETOKEN { $$ = new QSBooleanNode(true); } | FALSETOKEN { $$ = new QSBooleanNode(false); } | NUMBER { $$ = new QSNumberNode($1); } | STRING { $$ = new QSStringNode($1); delete $1; } | '/' /* a RegExp ? */ { QSLexer *l = QSLexer::curr(); if (!l->scanRegExp()) YYABORT; $$ = new QSRegExpNode(l->pattern,l->flags);} ; PrimaryExpr: THIS { $$ = new QSThisNode(); } | IDENT { $$ = new QSResolveNode($1); delete $1; } | Literal | ArrayLiteral | '(' Expr ')' { $$ = new QSGroupNode($2); } | '{' '}' { $$ = new QSObjectLiteralNode(0L); } | '{' PropertyNameAndValueList '}' { $$ = new QSObjectLiteralNode($2); } ; ArrayLiteral: '[' ElisionOpt ']' { $$ = new QSArrayNode($2); } | '[' ElementList ']' { $$ = new QSArrayNode($2); } | '[' ElementList ',' ElisionOpt ']' { $$ = new QSArrayNode($4, $2); } ; ElementList: ElisionOpt AssignmentExpr { $$ = new QSElementNode($1, $2); } | ElementList ',' ElisionOpt AssignmentExpr { $$ = new QSElementNode($1, $3, $4); } ; ElisionOpt: /* nothing */ { $$ = 0L; } | Elision ; Elision: ',' { $$ = new QSElisionNode(0L); } | Elision ',' { $$ = new QSElisionNode($1); } ; PropertyNameAndValueList: PropertyName ':' AssignmentExpr { $$ = new QSPropertyValueNode($1, $3); } | PropertyNameAndValueList ',' PropertyName ':' AssignmentExpr { $$ = new QSPropertyValueNode($3, $5, $1); } ; PropertyName: IDENT { $$ = new QSPropertyNode($1); delete $1; } | STRING { $$ = new QSPropertyNode($1); delete $1; } | NUMBER { $$ = new QSPropertyNode($1); } ; MemberExpr: PrimaryExpr | FunctionExpr | MemberExpr '[' Expr ']' { $$ = new QSAccessorNode1($1, $3); } | MemberExpr '.' IDENT { $$ = new QSAccessorNode2($1, $3); delete $3; } | NEW MemberExpr Arguments { $$ = new QSNewExprNode($2, $3); } ; NewExpr: MemberExpr | NEW NewExpr { $$ = new QSNewExprNode($2); } ; CallExpr: MemberExpr Arguments { $$ = new QSFunctionCallNode($1, $2); } | CallExpr Arguments { $$ = new QSFunctionCallNode($1, $2); } | CallExpr '[' Expr ']' { $$ = new QSAccessorNode1($1, $3); } | CallExpr '.' IDENT { $$ = new QSAccessorNode2($1, $3); delete $3; } ; Arguments: '(' ')' { $$ = new QSArgumentsNode(0L); } | '(' ArgumentList ')' { $$ = new QSArgumentsNode($2); } ; ArgumentList: AssignmentExpr { $$ = new QSArgumentListNode($1); } | ArgumentList ',' AssignmentExpr { $$ = new QSArgumentListNode($1, $3); } ; LeftHandSideExpr: NewExpr | CallExpr ; PostfixExpr: /* TODO: no line terminator here */ LeftHandSideExpr | LeftHandSideExpr PLUSPLUS { $$ = new QSPostfixNode($1, OpPlusPlus); } | LeftHandSideExpr MINUSMINUS { $$ = new QSPostfixNode($1, OpMinusMinus); } ; UnaryExpr: PostfixExpr | DELETE UnaryExpr { $$ = new QSDeleteNode($2); } | VOID UnaryExpr { $$ = new QSVoidNode($2); } | TYPEOF UnaryExpr { $$ = new QSTypeOfNode($2); } | PLUSPLUS UnaryExpr { $$ = new QSPrefixNode(OpPlusPlus, $2); } | MINUSMINUS UnaryExpr { $$ = new QSPrefixNode(OpMinusMinus, $2); } | '+' UnaryExpr { $$ = new QSUnaryPlusNode($2); } | '-' UnaryExpr { $$ = new QSNegateNode($2); } | '~' UnaryExpr { $$ = new QSBitwiseNotNode($2); } | '!' UnaryExpr { $$ = new QSLogicalNotNode($2); } ; MultiplicativeExpr: UnaryExpr | MultiplicativeExpr '*' UnaryExpr { $$ = new QSMultNode($1, $3, '*'); } | MultiplicativeExpr '/' UnaryExpr { $$ = new QSMultNode($1, $3, '/'); } | MultiplicativeExpr '%' UnaryExpr { $$ = new QSMultNode($1,$3,'%'); } ; AdditiveExpr: MultiplicativeExpr | AdditiveExpr '+' MultiplicativeExpr { $$ = new QSAddNode($1, $3, '+'); } | AdditiveExpr '-' MultiplicativeExpr { $$ = new QSAddNode($1, $3, '-'); } ; ShiftExpr: AdditiveExpr | ShiftExpr LSHIFT AdditiveExpr { $$ = new QSShiftNode($1, OpLShift, $3); } | ShiftExpr RSHIFT AdditiveExpr { $$ = new QSShiftNode($1, OpRShift, $3); } | ShiftExpr URSHIFT AdditiveExpr { $$ = new QSShiftNode($1, OpURShift, $3); } ; RelationalExpr: ShiftExpr | RelationalExpr '<' ShiftExpr { $$ = new QSRelationalNode($1, OpLess, $3); } | RelationalExpr '>' ShiftExpr { $$ = new QSRelationalNode($1, OpGreater, $3); } | RelationalExpr LE ShiftExpr { $$ = new QSRelationalNode($1, OpLessEq, $3); } | RelationalExpr GE ShiftExpr { $$ = new QSRelationalNode($1, OpGreaterEq, $3); } | RelationalExpr IS ShiftExpr { $$ = new QSRelationalNode($1, OpIs, $3); } | RelationalExpr INSTANCEOF ShiftExpr { $$ = new QSRelationalNode($1, OpInstanceOf, $3); } | RelationalExpr IN ShiftExpr { $$ = new QSRelationalNode($1, OpIn, $3); } ; EqualityExpr: RelationalExpr | EqualityExpr EQEQ RelationalExpr { $$ = new QSEqualNode($1, OpEqEq, $3); } | EqualityExpr NE RelationalExpr { $$ = new QSEqualNode($1, OpNotEq, $3); } | EqualityExpr STREQ RelationalExpr { $$ = new QSEqualNode($1, OpStrEq, $3); } | EqualityExpr STRNEQ RelationalExpr { $$ = new QSEqualNode($1, OpStrNEq, $3);} ; BitwiseANDExpr: EqualityExpr | BitwiseANDExpr '&' EqualityExpr { $$ = new QSBitOperNode($1, OpBitAnd, $3); } ; BitwiseXORExpr: BitwiseANDExpr | BitwiseXORExpr '^' EqualityExpr { $$ = new QSBitOperNode($1, OpBitXOr, $3); } ; BitwiseORExpr: BitwiseXORExpr | BitwiseORExpr '|' EqualityExpr { $$ = new QSBitOperNode($1, OpBitOr, $3); } ; LogicalANDExpr: BitwiseORExpr | LogicalANDExpr AND BitwiseORExpr { $$ = new QSBinaryLogicalNode($1, OpAnd, $3); } ; LogicalORExpr: LogicalANDExpr | LogicalORExpr OR LogicalANDExpr { $$ = new QSBinaryLogicalNode($1, OpOr, $3); } ; ConditionalExpr: LogicalORExpr | LogicalORExpr '?' AssignmentExpr ':' AssignmentExpr { $$ = new QSConditionalNode($1, $3, $5); } ; AssignmentExpr: ConditionalExpr | LeftHandSideExpr AssignmentOperator AssignmentExpr { $$ = new QSAssignNode($1, $2, $3);} ; AssignmentOperator: '=' { $$ = OpEqual; } | PLUSEQUAL { $$ = OpPlusEq; } | MINUSEQUAL { $$ = OpMinusEq; } | MULTEQUAL { $$ = OpMultEq; } | DIVEQUAL { $$ = OpDivEq; } | LSHIFTEQUAL { $$ = OpLShift; } | RSHIFTEQUAL { $$ = OpRShift; } | URSHIFTEQUAL { $$ = OpURShift; } | ANDEQUAL { $$ = OpAndEq; } | XOREQUAL { $$ = OpXOrEq; } | OREQUAL { $$ = OpOrEq; } | MODEQUAL { $$ = OpModEq; } ; Expr: AssignmentExpr | Expr ',' AssignmentExpr { $$ = new QSCommaNode($1, $3); } ; Statement: Block | VariableDefinition | ClassDefinition { $$ = $1; } | Attributes ClassDefinition { $2->setAttributes( $1 ); $$ = $2; } | PackageDefinition | EmptyStatement | ExprStatement | IfStatement | IterationStatement | ContinueStatement | BreakStatement | ReturnStatement | WithStatement | SwitchStatement | LabelledStatement | ThrowStatement | TryStatement | ImportStatement ; Block: '{' '}' { $$ = new QSBlockNode(0L); DBG($$, @2, @2); } | '{' StatementList '}' { $$ = new QSBlockNode($2); DBG($$, @3, @3); } ; StatementList: Statement { $$ = new QSStatListNode($1); } | StatementList Statement { $$ = new QSStatListNode($1, $2); } ; EmptyStatement: ';' { $$ = new QSEmptyStatementNode(); } ; ExprStatement: Expr ';' { $$ = new QSExprStatementNode($1); DBG($$, @1, @2); } | Expr error { if (automatic()) { $$ = new QSExprStatementNode($1); DBG($$, @1, @1); } else YYABORT; } ; IfStatement: /* shift/reduce conflict due to dangling else */ IF '(' Expr ')' Statement { $$ = new QSIfNode($3,$5,0L);DBG($$,@1,@4); } | IF '(' Expr ')' Statement ELSE Statement { $$ = new QSIfNode($3,$5,$7);DBG($$,@1,@4); } ; IterationStatement: DO Statement WHILE '(' Expr ')' { $$=new QSDoWhileNode($2,$5);DBG($$,@1,@3);} | WHILE '(' Expr ')' Statement { $$ = new QSWhileNode($3,$5);DBG($$,@1,@4); } | FOR '(' ExprOpt ';' ExprOpt ';' ExprOpt ')' Statement { $$ = new QSForNode($3,$5,$7,$9); DBG($$,@1,@8); } | FOR '(' VAR VariableBindingList ';' ExprOpt ';' ExprOpt ')' Statement { $$ = new QSForNode($4,$6,$8,$10); DBG($$,@1,@9); } | FOR '(' LeftHandSideExpr IN Expr ')' Statement { $$ = new QSForInNode($3, $5, $7); DBG($$,@1,@6); } | FOR '(' VAR VariableBinding IN Expr ')' Statement { $$ = new QSForInNode($4,$6,$8); DBG($$,@1,@7); } ; ExprOpt: /* nothing */ { $$ = 0L; } | Expr ; ContinueStatement: CONTINUE ';' { $$ = new QSContinueNode(); DBG($$,@1,@2); } | CONTINUE error { if (automatic()) { $$ = new QSContinueNode(); DBG($$,@1,@2); } else YYABORT; } | CONTINUE IDENT ';' { $$ = new QSContinueNode($2); DBG($$,@1,@3); delete $2; } | CONTINUE IDENT error { if (automatic()) { $$ = new QSContinueNode($2);DBG($$,@1,@2); delete $2; } else YYABORT; } ; BreakStatement: BREAK ';' { $$ = new QSBreakNode();DBG($$,@1,@2); } | BREAK error { if (automatic()) { $$ = new QSBreakNode(); DBG($$,@1,@1); } else YYABORT; } | BREAK IDENT ';' { $$ = new QSBreakNode($2); DBG($$,@1,@3); delete $2; } | BREAK IDENT error { if (automatic()) { $$ = new QSBreakNode($2); DBG($$,@1,@2); delete $2; } else YYABORT; } ; ReturnStatement: RETURN ';' { $$ = new QSReturnNode(0L); DBG($$,@1,@2); } | RETURN error { if (automatic()) { $$ = new QSReturnNode(0L); DBG($$,@1,@1); } else YYABORT; } | RETURN Expr ';' { $$ = new QSReturnNode($2); DBG($$,@1,@2); } | RETURN Expr error { if (automatic()) { $$ = new QSReturnNode($2); DBG($$,@1,@2); } else { YYABORT; } } ; WithStatement: WITH '(' Expr ')' Statement { $$ = new QSWithNode($3,$5); DBG($$, @1, @4); } ; SwitchStatement: SWITCH '(' Expr ')' CaseBlock { $$ = new QSSwitchNode($3, $5); DBG($$, @1, @4); } ; CaseBlock: '{' CaseClausesOpt '}' { $$ = new QSCaseBlockNode($2, 0L, 0L); } | '{' CaseClausesOpt DefaultClause CaseClausesOpt '}' { $$ = new QSCaseBlockNode($2, $3, $4); } ; CaseClausesOpt: /* nothing */ { $$ = 0L; } | CaseClauses ; CaseClauses: CaseClause { $$ = new QSClauseListNode($1); } | CaseClauses CaseClause { $$ = $1->append($2); } ; CaseClause: CASE Expr ':' { $$ = new QSCaseClauseNode($2, 0L); } | CASE Expr ':' StatementList { $$ = new QSCaseClauseNode($2, $4); } ; DefaultClause: DEFAULT ':' { $$ = new QSCaseClauseNode(0L, 0L);; } | DEFAULT ':' StatementList { $$ = new QSCaseClauseNode(0L, $3); } ; LabelledStatement: IDENT ':' Statement { $3->pushLabel($1); $$ = new QSLabelNode($1, $3); delete $1; } ; ThrowStatement: THROW Expr ';' { $$ = new QSThrowNode($2); } ; TryStatement: TRY Block Catch { $$ = new QSTryNode($2, $3); } | TRY Block Finally { $$ = new QSTryNode($2, 0L, $3); } | TRY Block Catch Finally { $$ = new QSTryNode($2, $3, $4); } ; Catch: CATCH '(' IDENT ')' Block { $$ = new QSCatchNode($3, $5); delete $3; } ; Finally: FINALLY Block { $$ = new QSFinallyNode($2); } ; PackageDefinition: PACKAGE PackageName FunctionBody { $$ = new QSPackageNode($2, $3); delete $2; } ; ImportStatement: IMPORT PackageName ';' { $$ = new QSImportNode($2); delete $2; } ; PackageName: IDENT { $$ = $1; delete $1; } | PackageName '.' IDENT { *$$ += "." + *$3; delete $3; } ; FunctionDeclaration: FUNCTION IDENT '(' ')' ResultSignature FunctionBody { $$ = new QSFuncDeclNode($2, 0L, $5, $6); delete $2; } | FUNCTION IDENT '(' FormalParameterList ')' ResultSignature FunctionBody { $$ = new QSFuncDeclNode($2, $4, $6, $7); delete $2; } | Attributes FUNCTION IDENT '(' ')' ResultSignature FunctionBody { $$ = new QSFuncDeclNode($3, 0L, $6, $7); $$->setAttributes( $1 ); delete $3; } | Attributes FUNCTION IDENT '(' FormalParameterList ')' ResultSignature FunctionBody { $$ = new QSFuncDeclNode($3, $5, $7, $8); $$->setAttributes( $1 ); delete $3; } ; ResultSignature: { $$ = 0L; } | ':' TypeExpression { $$ = $2; } ; FunctionExpr: FUNCTION '(' ')' FunctionBody { $$ = new QSFuncExprNode(0L, $4); } | FUNCTION '(' FormalParameterList ')' FunctionBody { $$ = new QSFuncExprNode($3, $5); } ; FormalParameterList: IDENT { $$ = new QSParameterNode($1, 0L); delete $1; } | IDENT ':' TypeExpression { $$ = new QSParameterNode($1, $3); delete $1; } | FormalParameterList ',' IDENT { $$ = $1->append($3, 0L); delete $3; } | FormalParameterList ',' IDENT ':' TypeExpression { $$ = $1->append($3, $5); delete $3; } ; FunctionBody: '{' '}' /* TODO: spec ??? */ { $$ = new QSFunctionBodyNode(0L); } | '{' SourceElements '}' { $$ = new QSFunctionBodyNode($2); } ; ClassDefinition: CLASS IDENT ';' { $$ = new QSClassDefNode($2, 0L, 0L); delete $2; } | CLASS IDENT FunctionBody { $$ = new QSClassDefNode($2, 0L, $3); delete $2; } | CLASS IDENT EXTENDS TypeExpression FunctionBody { $$ = new QSClassDefNode($2, $4, $5); delete $2; } ; Program: /* empty */ { $$ = new QSProgramNode(0L); QSEngineImp::current()->setProgNode($$); } | SourceElements { $$ = new QSProgramNode($1); QSEngineImp::current()->setProgNode($$); } ; SourceElements: SourceElement { $$ = new QSSourceElementsNode($1); } | SourceElements SourceElement { $$ = new QSSourceElementsNode($1, $2); } ; SourceElement: Statement { $$ = new QSSourceElementNode($1); } | FunctionDeclaration { $$ = new QSSourceElementNode($1); } ; Attributes: Attribute { $$ = new QSAttributeNode($1); } | Attributes Attribute { $1->add($2); $$ = $1; } ; Attribute: ABSTRACT { $$ = AttributeAbstract; } | FINAL { $$ = AttributeFinal; } | PRIVATE { $$ = AttributePrivate; } | PUBLIC { $$ = AttributePublic; } | STATIC { $$ = AttributeStatic; } | TRUETOKEN { $$ = AttributeTrue; } | FALSETOKEN { $$ = AttributeFalse; } | CONSTRUCTOR { $$ = AttributeConstructor; } ; /************************* Variable Definition ******************************/ VariableDefinition: VariableDefinitionKind VariableBindingList { $$ = new QSVarDefNode($1, $2); DBG($$, @1, @2); } | Attributes VariableDefinitionKind VariableBindingList { $$ = new QSVarDefNode($2, $3); DBG($$, @1, @3); ((QSVarDefNode*)$$)->setAttributes( $1 ); } ; VariableDefinitionKind: VAR { $$ = 0; } | CONST { $$ = 1; } ; VariableBindingList: VariableBinding { $$ = new QSVarBindingListNode(0L, $1); } | VariableBindingList ',' VariableBinding { $$ = new QSVarBindingListNode($1, $3); } ; VariableBinding: TypedVariable { $$ = new QSVarBindingNode($1, 0L); } | TypedVariable '=' AssignmentExpr { $$ = new QSVarBindingNode($1, $3); } ; TypedVariable: IDENT { $$ = new QSTypedVarNode($1, 0L); delete $1; } | IDENT ':' TypeExpression { $$ = new QSTypedVarNode($1, $3); delete $1; } ; /************************* Type Expressions *********************************/ TypeExpression: IDENT { $$ = new QSTypeNode($1); delete $1; } ; %% int yyerror ( const char * ) /* Called by yyparse on error */ { return 1; } /* may we automatically insert a semicolon ? */ bool automatic() { if ( yychar == '}' || yychar == 0 ) return true; else if ( QSLexer::curr()->prevTerminator() ) return true; return false; }