⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jsparse.c

📁 Swfdec still is development software, but has also followed a rigid no-crashes-allowed policy. I b
💻 C
📖 第 1 页 / 共 5 页
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** *//* * JS parser. * * This is a recursive-descent parser for the JavaScript language specified by * "The JavaScript 1.5 Language Specification".  It uses lexical and semantic * feedback to disambiguate non-LL(1) structures.  It generates trees of nodes * induced by the recursive parsing (not precise syntax trees, see jsparse.h). * After tree construction, it rewrites trees to fold constants and evaluate * compile-time expressions.  Finally, it calls js_EmitTree (see jsemit.h) to * generate bytecode. * * This parser attempts no error recovery.  The dense JSTokenType enumeration * was designed with error recovery built on 64-bit first and follow bitsets * in mind, however. */#include "jsstddef.h"#include <stdlib.h>#include <string.h>#include <math.h>#include "jstypes.h"#include "jsarena.h" /* Added by JSIFY */#include "jsutil.h" /* Added by JSIFY */#include "jsapi.h"#include "jsatom.h"#include "jscntxt.h"#include "jsconfig.h"#include "jsemit.h"#include "jsfun.h"#include "jsinterp.h"#include "jslock.h"#include "jsnum.h"#include "jsobj.h"#include "jsopcode.h"#include "jsparse.h"#include "jsscan.h"#include "jsscope.h"#include "jsscript.h"#include "jsstr.h"/* * JS parsers, from lowest to highest precedence. * * Each parser takes a context and a token stream, and emits bytecode using * a code generator. */typedef JSParseNode *JSParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc);typedef JSParseNode *JSMemberParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,               JSBool allowCallSyntax);static JSParser FunctionStmt;#if JS_HAS_LEXICAL_CLOSUREstatic JSParser FunctionExpr;#endifstatic JSParser Statements;static JSParser Statement;static JSParser Variables;static JSParser Expr;static JSParser AssignExpr;static JSParser CondExpr;static JSParser OrExpr;static JSParser AndExpr;static JSParser BitOrExpr;static JSParser BitXorExpr;static JSParser BitAndExpr;static JSParser EqExpr;static JSParser RelExpr;static JSParser ShiftExpr;static JSParser AddExpr;static JSParser MulExpr;static JSParser UnaryExpr;static JSMemberParser MemberExpr;static JSParser PrimaryExpr;/* * Insist that the next token be of type tt, or report errno and return null. * NB: this macro uses cx and ts from its lexical environment. */#define MUST_MATCH_TOKEN(tt, errno)                                           \    JS_BEGIN_MACRO                                                            \        if (js_GetToken(cx, ts) != tt) {                                      \            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, errno); \            return NULL;                                                      \        }                                                                     \    JS_END_MACRO#define CHECK_RECURSION()                                                     \    JS_BEGIN_MACRO                                                            \        int stackDummy;                                                       \        if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {                           \            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,         \                                        JSMSG_OVER_RECURSED);                 \            return NULL;                                                      \        }                                                                     \    JS_END_MACRO#ifdef METER_PARSENODESstatic uint32 parsenodes = 0;static uint32 maxparsenodes = 0;static uint32 recyclednodes = 0;#endifstatic voidRecycleTree(JSParseNode *pn, JSTreeContext *tc){    if (!pn)        return;    JS_ASSERT(pn != tc->nodeList);      /* catch back-to-back dup recycles */    pn->pn_next = tc->nodeList;    tc->nodeList = pn;#ifdef METER_PARSENODES    recyclednodes++;#endif}static JSParseNode *NewOrRecycledNode(JSContext *cx, JSTreeContext *tc){    JSParseNode *pn;    pn = tc->nodeList;    if (!pn) {        JS_ARENA_ALLOCATE_TYPE(pn, JSParseNode, &cx->tempPool);        if (!pn)            JS_ReportOutOfMemory(cx);    } else {        tc->nodeList = pn->pn_next;        /* Recycle immediate descendents only, to save work and working set. */        switch (pn->pn_arity) {          case PN_FUNC:            RecycleTree(pn->pn_body, tc);            break;          case PN_LIST:            if (pn->pn_head) {                /* XXX check for dup recycles in the list */                *pn->pn_tail = tc->nodeList;                tc->nodeList = pn->pn_head;#ifdef METER_PARSENODES                recyclednodes += pn->pn_count;#endif            }            break;          case PN_TERNARY:            RecycleTree(pn->pn_kid1, tc);            RecycleTree(pn->pn_kid2, tc);            RecycleTree(pn->pn_kid3, tc);            break;          case PN_BINARY:            RecycleTree(pn->pn_left, tc);            RecycleTree(pn->pn_right, tc);            break;          case PN_UNARY:            RecycleTree(pn->pn_kid, tc);            break;          case PN_NAME:            RecycleTree(pn->pn_expr, tc);            break;          case PN_NULLARY:            break;        }    }    return pn;}/* * Allocate a JSParseNode from cx's temporary arena. */static JSParseNode *NewParseNode(JSContext *cx, JSToken *tok, JSParseNodeArity arity,             JSTreeContext *tc){    JSParseNode *pn;    pn = NewOrRecycledNode(cx, tc);    if (!pn)        return NULL;    pn->pn_type = tok->type;    pn->pn_pos = tok->pos;    pn->pn_op = JSOP_NOP;    pn->pn_arity = arity;    pn->pn_next = NULL;#ifdef METER_PARSENODES    parsenodes++;    if (parsenodes - recyclednodes > maxparsenodes)        maxparsenodes = parsenodes - recyclednodes;#endif    return pn;}static JSParseNode *NewBinary(JSContext *cx, JSTokenType tt,          JSOp op, JSParseNode *left, JSParseNode *right,          JSTreeContext *tc){    JSParseNode *pn, *pn1, *pn2;    if (!left || !right)        return NULL;    /*     * Flatten a left-associative (left-heavy) tree of a given operator into     * a list, to reduce js_FoldConstants and js_EmitTree recursion.     */    if (left->pn_type == tt &&        left->pn_op == op &&        (js_CodeSpec[op].format & JOF_LEFTASSOC)) {        if (left->pn_arity != PN_LIST) {            pn1 = left->pn_left, pn2 = left->pn_right;            left->pn_arity = PN_LIST;            PN_INIT_LIST_1(left, pn1);            PN_APPEND(left, pn2);            left->pn_extra = 0;            if (tt == TOK_PLUS) {                if (pn1->pn_type == TOK_STRING)                    left->pn_extra |= PNX_STRCAT;                else if (pn1->pn_type != TOK_NUMBER)                    left->pn_extra |= PNX_CANTFOLD;                if (pn2->pn_type == TOK_STRING)                    left->pn_extra |= PNX_STRCAT;                else if (pn2->pn_type != TOK_NUMBER)                    left->pn_extra |= PNX_CANTFOLD;            }        }        PN_APPEND(left, right);        left->pn_pos.end = right->pn_pos.end;        if (tt == TOK_PLUS) {            if (right->pn_type == TOK_STRING)                left->pn_extra |= PNX_STRCAT;            else if (right->pn_type != TOK_NUMBER)                left->pn_extra |= PNX_CANTFOLD;        }        return left;    }    /*     * Fold constant addition immediately, to conserve node space and, what's     * more, so js_FoldConstants never sees mixed addition and concatenation     * operations with more than one leading non-string operand in a PN_LIST     * generated for expressions such as 1 + 2 + "pt" (which should evaluate     * to "3pt", not "12pt").     */    if (tt == TOK_PLUS &&        left->pn_type == TOK_NUMBER &&        right->pn_type == TOK_NUMBER) {        left->pn_dval += right->pn_dval;        RecycleTree(right, tc);        return left;    }    pn = NewOrRecycledNode(cx, tc);    if (!pn)        return NULL;    pn->pn_type = tt;    pn->pn_pos.begin = left->pn_pos.begin;    pn->pn_pos.end = right->pn_pos.end;    pn->pn_op = op;    pn->pn_arity = PN_BINARY;    pn->pn_left = left;    pn->pn_right = right;    pn->pn_next = NULL;#ifdef METER_PARSENODES    parsenodes++;    if (parsenodes - recyclednodes > maxparsenodes)        maxparsenodes = parsenodes - recyclednodes;#endif    return pn;}#if JS_HAS_GETTER_SETTERstatic JSTokenTypeCheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt){    JSAtom *atom;    JSRuntime *rt;    JSOp op;    const char *name;    JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_NAME);    atom = CURRENT_TOKEN(ts).t_atom;    rt = cx->runtime;    if (atom == rt->atomState.getterAtom)        op = JSOP_GETTER;    else if (atom == rt->atomState.setterAtom)        op = JSOP_SETTER;    else        return TOK_NAME;    if (js_PeekTokenSameLine(cx, ts) != tt)        return TOK_NAME;    (void) js_GetToken(cx, ts);    if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) {        js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,                                    JSMSG_BAD_GETTER_OR_SETTER,                                    (op == JSOP_GETTER)                                    ? js_getter_str                                    : js_setter_str);        return TOK_ERROR;    }    CURRENT_TOKEN(ts).t_op = op;    name = js_AtomToPrintableString(cx, atom);    if (!name ||        !js_ReportCompileErrorNumber(cx, ts, NULL,                                     JSREPORT_WARNING |                                     JSREPORT_STRICT,                                     JSMSG_DEPRECATED_USAGE,                                     name)) {        return TOK_ERROR;    }    return tt;}#endif/* * Parse a top-level JS script. */JS_FRIEND_API(JSParseNode *)js_ParseTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts){    JSStackFrame *fp, frame;    JSTreeContext tc;    JSParseNode *pn;    /*     * Push a compiler frame if we have no frames, or if the top frame is a     * lightweight function activation, or if its scope chain doesn't match     * the one passed to us.     */    fp = cx->fp;    if (!fp || !fp->varobj || fp->scopeChain != chain) {        memset(&frame, 0, sizeof frame);        frame.varobj = frame.scopeChain = chain;        if (cx->options & JSOPTION_VAROBJFIX) {            while ((chain = JS_GetParent(cx, chain)) != NULL)                frame.varobj = chain;        }        frame.down = fp;        cx->fp = &frame;    }    /*     * Protect atoms from being collected by a GC activation, which might     * - nest on this thread due to out of memory (the so-called "last ditch"     *   GC attempted within js_AllocGCThing), or     * - run for any reason on another thread if this thread is suspended on     *   an object lock before it finishes generating bytecode into a script     *   protected from the GC by a root or a stack frame reference.     */    JS_KEEP_ATOMS(cx->runtime);    TREE_CONTEXT_INIT(&tc);    pn = Statements(cx, ts, &tc);    if (pn) {        if (!js_MatchToken(cx, ts, TOK_EOF)) {            js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -