2011-09-06 13:18:40 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2011 Jacek Caban for CodeWeavers
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library 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
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
%{
|
|
|
|
|
|
|
|
#include "vbscript.h"
|
|
|
|
#include "parse.h"
|
|
|
|
|
|
|
|
#include "wine/debug.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
|
|
|
|
|
|
|
|
|
|
|
|
#define YYLEX_PARAM ctx
|
|
|
|
#define YYPARSE_PARAM ctx
|
|
|
|
|
|
|
|
static int parser_error(const char*);
|
|
|
|
|
|
|
|
static void parse_complete(parser_ctx_t*);
|
|
|
|
|
2011-09-07 12:08:21 +00:00
|
|
|
static void source_add_statement(parser_ctx_t*,statement_t*);
|
|
|
|
|
2011-09-08 12:56:36 +00:00
|
|
|
static expression_t *new_bool_expression(parser_ctx_t*,VARIANT_BOOL);
|
|
|
|
|
2011-09-07 12:08:21 +00:00
|
|
|
static member_expression_t *new_member_expression(parser_ctx_t*,expression_t*,const WCHAR*);
|
|
|
|
|
|
|
|
static statement_t *new_call_statement(parser_ctx_t*,member_expression_t*);
|
|
|
|
|
2011-09-08 12:55:35 +00:00
|
|
|
#define CHECK_ERROR if(((parser_ctx_t*)ctx)->hres != S_OK) YYABORT
|
|
|
|
|
2011-09-06 13:18:40 +00:00
|
|
|
%}
|
|
|
|
|
|
|
|
%pure_parser
|
|
|
|
%start Program
|
|
|
|
|
|
|
|
%union {
|
|
|
|
const WCHAR *string;
|
2011-09-07 12:08:21 +00:00
|
|
|
statement_t *statement;
|
2011-09-08 12:55:35 +00:00
|
|
|
expression_t *expression;
|
2011-09-07 12:08:21 +00:00
|
|
|
member_expression_t *member;
|
2011-09-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2011-09-08 12:56:18 +00:00
|
|
|
%token tEOF tNL tREM
|
|
|
|
%token tTRUE tFALSE
|
|
|
|
%token tNOT tAND tOR tXOR tEQV tIMP tNEQ
|
|
|
|
%token tIS tLTEQ tGTEQ tMOD
|
|
|
|
%token tCALL tDIM tSUB tFUNCTION tPROPERTY tGET tLET
|
|
|
|
%token tIF tELSE tELSEIF tEND tTHEN tEXIT
|
|
|
|
%token tWHILE tWEND tDO tLOOP tUNTIL
|
|
|
|
%token tBYREF tBYVAL
|
|
|
|
%token tOPTION tEXPLICIT
|
|
|
|
%token tSTOP
|
|
|
|
%token tNOTHING tEMPTY tNULL
|
|
|
|
%token tCLASS tSET tNEW tPUBLIC tPRIVATE tDEFAULT tME
|
|
|
|
%token tERROR tNEXT tON tRESUME tGOTO
|
2011-09-08 12:56:48 +00:00
|
|
|
%token <string> tIdentifier tString
|
2011-09-06 13:18:55 +00:00
|
|
|
|
2011-09-07 12:08:21 +00:00
|
|
|
%type <statement> Statement StatementNl
|
2011-09-08 12:56:36 +00:00
|
|
|
%type <expression> Expression LiteralExpression
|
2011-09-07 12:08:21 +00:00
|
|
|
%type <member> MemberExpression
|
2011-09-08 12:56:36 +00:00
|
|
|
%type <expression> Arguments_opt ArgumentList_opt ArgumentList
|
2011-09-07 12:08:21 +00:00
|
|
|
|
2011-09-06 13:18:40 +00:00
|
|
|
%%
|
|
|
|
|
2011-09-07 12:08:21 +00:00
|
|
|
Program
|
|
|
|
: SourceElements tEOF { parse_complete(ctx); }
|
|
|
|
|
|
|
|
SourceElements
|
|
|
|
: /* empty */
|
|
|
|
| SourceElements StatementNl { source_add_statement(ctx, $2); }
|
|
|
|
|
|
|
|
StatementNl
|
|
|
|
: Statement tNL { $$ = $1; }
|
|
|
|
|
|
|
|
Statement
|
2011-09-08 12:56:05 +00:00
|
|
|
: MemberExpression Arguments_opt { $1->args = $2; $$ = new_call_statement(ctx, $1); CHECK_ERROR; }
|
|
|
|
| tCALL MemberExpression Arguments_opt { $2->args = $3; $$ = new_call_statement(ctx, $2); CHECK_ERROR; }
|
2011-09-07 12:08:21 +00:00
|
|
|
|
|
|
|
MemberExpression
|
2011-09-08 12:55:35 +00:00
|
|
|
: tIdentifier { $$ = new_member_expression(ctx, NULL, $1); CHECK_ERROR; }
|
2011-09-07 12:08:21 +00:00
|
|
|
/* FIXME: MemberExpressionArgs '.' tIdentifier */
|
2011-09-06 13:18:40 +00:00
|
|
|
|
2011-09-08 12:55:35 +00:00
|
|
|
Arguments_opt
|
|
|
|
: /* empty */ { $$ = NULL; }
|
|
|
|
| '(' ArgumentList_opt ')' { $$ = $2; }
|
|
|
|
|
|
|
|
ArgumentList_opt
|
|
|
|
: /* empty */ { $$ = NULL; }
|
2011-09-08 12:56:36 +00:00
|
|
|
| ArgumentList { $$ = $1; }
|
|
|
|
|
|
|
|
ArgumentList
|
|
|
|
: Expression { $$ = $1; }
|
|
|
|
| Expression ',' ArgumentList { $1->next = $3; $$ = $1; }
|
|
|
|
|
|
|
|
Expression
|
|
|
|
: LiteralExpression /* FIXME */ { $$ = $1; }
|
|
|
|
|
|
|
|
LiteralExpression
|
|
|
|
: tTRUE { $$ = new_bool_expression(ctx, VARIANT_TRUE); CHECK_ERROR; }
|
|
|
|
| tFALSE { $$ = new_bool_expression(ctx, VARIANT_FALSE); CHECK_ERROR; }
|
2011-09-08 12:55:35 +00:00
|
|
|
|
2011-09-06 13:18:40 +00:00
|
|
|
%%
|
|
|
|
|
|
|
|
static int parser_error(const char *str)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-07 12:08:21 +00:00
|
|
|
static void source_add_statement(parser_ctx_t *ctx, statement_t *stat)
|
|
|
|
{
|
|
|
|
if(ctx->stats) {
|
|
|
|
ctx->stats_tail->next = stat;
|
|
|
|
ctx->stats_tail = stat;
|
|
|
|
}else {
|
|
|
|
ctx->stats = ctx->stats_tail = stat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-06 13:18:40 +00:00
|
|
|
static void parse_complete(parser_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
ctx->parse_complete = TRUE;
|
|
|
|
}
|
|
|
|
|
2011-09-07 12:08:21 +00:00
|
|
|
static void *new_expression(parser_ctx_t *ctx, expression_type_t type, unsigned size)
|
|
|
|
{
|
|
|
|
expression_t *expr;
|
|
|
|
|
|
|
|
expr = parser_alloc(ctx, size ? size : sizeof(*expr));
|
|
|
|
if(expr) {
|
|
|
|
expr->type = type;
|
|
|
|
expr->next = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return expr;
|
|
|
|
}
|
|
|
|
|
2011-09-08 12:56:36 +00:00
|
|
|
static expression_t *new_bool_expression(parser_ctx_t *ctx, VARIANT_BOOL value)
|
|
|
|
{
|
|
|
|
bool_expression_t *expr;
|
|
|
|
|
|
|
|
expr = new_expression(ctx, EXPR_BOOL, sizeof(*expr));
|
|
|
|
if(!expr)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
expr->value = value;
|
|
|
|
return &expr->expr;
|
|
|
|
}
|
|
|
|
|
2011-09-07 12:08:21 +00:00
|
|
|
static member_expression_t *new_member_expression(parser_ctx_t *ctx, expression_t *obj_expr, const WCHAR *identifier)
|
|
|
|
{
|
|
|
|
member_expression_t *expr;
|
|
|
|
|
|
|
|
expr = new_expression(ctx, EXPR_MEMBER, sizeof(*expr));
|
|
|
|
if(!expr)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
expr->obj_expr = obj_expr;
|
|
|
|
expr->identifier = identifier;
|
|
|
|
expr->args = NULL;
|
|
|
|
return expr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *new_statement(parser_ctx_t *ctx, statement_type_t type, unsigned size)
|
|
|
|
{
|
|
|
|
statement_t *stat;
|
|
|
|
|
|
|
|
stat = parser_alloc(ctx, size);
|
|
|
|
if(stat) {
|
|
|
|
stat->type = type;
|
|
|
|
stat->next = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
static statement_t *new_call_statement(parser_ctx_t *ctx, member_expression_t *expr)
|
|
|
|
{
|
|
|
|
call_statement_t *stat;
|
|
|
|
|
|
|
|
stat = new_statement(ctx, STAT_CALL, sizeof(*stat));
|
|
|
|
if(!stat)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
stat->expr = expr;
|
|
|
|
return &stat->stat;
|
|
|
|
}
|
|
|
|
|
2011-09-07 12:08:07 +00:00
|
|
|
void *parser_alloc(parser_ctx_t *ctx, size_t size)
|
|
|
|
{
|
|
|
|
void *ret;
|
|
|
|
|
|
|
|
/* FIXME: leaks! */
|
|
|
|
ret = heap_alloc(size);
|
|
|
|
if(!ret)
|
|
|
|
ctx->hres = E_OUTOFMEMORY;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-09-06 13:18:40 +00:00
|
|
|
HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code)
|
|
|
|
{
|
|
|
|
ctx->code = ctx->ptr = code;
|
|
|
|
ctx->end = ctx->code + strlenW(ctx->code);
|
|
|
|
|
|
|
|
ctx->parse_complete = FALSE;
|
|
|
|
ctx->hres = S_OK;
|
|
|
|
|
2011-09-06 13:18:55 +00:00
|
|
|
ctx->last_token = tNL;
|
|
|
|
ctx->last_nl = 0;
|
2011-09-07 12:08:21 +00:00
|
|
|
ctx->stats = ctx->stats_tail = NULL;
|
2011-09-06 13:18:55 +00:00
|
|
|
|
2011-09-06 13:18:40 +00:00
|
|
|
parser_parse(ctx);
|
|
|
|
|
|
|
|
if(FAILED(ctx->hres))
|
|
|
|
return ctx->hres;
|
|
|
|
if(!ctx->parse_complete) {
|
|
|
|
FIXME("parser failed on parsing %s\n", debugstr_w(ctx->ptr));
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|