📄 jsscan.c
字号:
/* -*- 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 lexical scanner. */#include "jsstddef.h"#include <stdio.h> /* first to avoid trouble on some systems */#include <errno.h>#include <limits.h>#include <math.h>#ifdef HAVE_MEMORY_H#include <memory.h>#endif#include <stdarg.h>#include <stdlib.h>#include <string.h>#include "jstypes.h"#include "jsarena.h" /* Added by JSIFY */#include "jsutil.h" /* Added by JSIFY */#include "jsdtoa.h"#include "jsprf.h"#include "jsapi.h"#include "jsatom.h"#include "jscntxt.h"#include "jsconfig.h"#include "jsemit.h"#include "jsexn.h"#include "jsnum.h"#include "jsopcode.h"#include "jsregexp.h"#include "jsscan.h"#define RESERVE_JAVA_KEYWORDS#define RESERVE_ECMA_KEYWORDSstatic struct keyword { const char *name; JSTokenType tokentype; /* JSTokenType */ JSOp op; /* JSOp */ JSVersion version; /* JSVersion */} keywords[] = { {"break", TOK_BREAK, JSOP_NOP, JSVERSION_DEFAULT}, {"case", TOK_CASE, JSOP_NOP, JSVERSION_DEFAULT}, {"continue", TOK_CONTINUE, JSOP_NOP, JSVERSION_DEFAULT}, {"default", TOK_DEFAULT, JSOP_NOP, JSVERSION_DEFAULT}, {js_delete_str, TOK_DELETE, JSOP_NOP, JSVERSION_DEFAULT}, {"do", TOK_DO, JSOP_NOP, JSVERSION_DEFAULT}, {"else", TOK_ELSE, JSOP_NOP, JSVERSION_DEFAULT}, {"export", TOK_EXPORT, JSOP_NOP, JSVERSION_1_2}, {js_false_str, TOK_PRIMARY, JSOP_FALSE, JSVERSION_DEFAULT}, {"for", TOK_FOR, JSOP_NOP, JSVERSION_DEFAULT}, {js_function_str, TOK_FUNCTION, JSOP_NOP, JSVERSION_DEFAULT}, {"if", TOK_IF, JSOP_NOP, JSVERSION_DEFAULT}, {js_in_str, TOK_IN, JSOP_IN, JSVERSION_DEFAULT}, {js_new_str, TOK_NEW, JSOP_NEW, JSVERSION_DEFAULT}, {js_null_str, TOK_PRIMARY, JSOP_NULL, JSVERSION_DEFAULT}, {"return", TOK_RETURN, JSOP_NOP, JSVERSION_DEFAULT}, {"switch", TOK_SWITCH, JSOP_NOP, JSVERSION_DEFAULT}, {js_this_str, TOK_PRIMARY, JSOP_THIS, JSVERSION_DEFAULT}, {js_true_str, TOK_PRIMARY, JSOP_TRUE, JSVERSION_DEFAULT}, {js_typeof_str, TOK_UNARYOP, JSOP_TYPEOF,JSVERSION_DEFAULT}, {"var", TOK_VAR, JSOP_DEFVAR,JSVERSION_DEFAULT}, {js_void_str, TOK_UNARYOP, JSOP_VOID, JSVERSION_DEFAULT}, {"while", TOK_WHILE, JSOP_NOP, JSVERSION_DEFAULT}, {"with", TOK_WITH, JSOP_NOP, JSVERSION_DEFAULT},#if JS_HAS_CONST {js_const_str, TOK_VAR, JSOP_DEFCONST,JSVERSION_DEFAULT},#else {js_const_str, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},#endif#if JS_HAS_EXCEPTIONS {"try", TOK_TRY, JSOP_NOP, JSVERSION_DEFAULT}, {"catch", TOK_CATCH, JSOP_NOP, JSVERSION_DEFAULT}, {"finally", TOK_FINALLY, JSOP_NOP, JSVERSION_DEFAULT}, {"throw", TOK_THROW, JSOP_NOP, JSVERSION_DEFAULT},#else {"try", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"catch", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"finally", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"throw", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},#endif#if JS_HAS_INSTANCEOF {js_instanceof_str, TOK_INSTANCEOF, JSOP_INSTANCEOF,JSVERSION_1_4},#else {js_instanceof_str, TOK_RESERVED, JSOP_NOP, JSVERSION_1_4},#endif#ifdef RESERVE_JAVA_KEYWORDS {"abstract", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"boolean", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"byte", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"char", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"class", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"double", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"extends", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"final", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"float", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"goto", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"implements", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"import", TOK_IMPORT, JSOP_NOP, JSVERSION_DEFAULT}, {"int", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"interface", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"long", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"native", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"package", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"private", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"protected", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"public", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"short", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"static", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"super", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"synchronized", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"throws", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"transient", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"volatile", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT},#endif#ifdef RESERVE_ECMA_KEYWORDS {"enum", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3},#endif#if JS_HAS_DEBUGGER_KEYWORD {"debugger", TOK_DEBUGGER, JSOP_NOP, JSVERSION_1_3},#elif defined(RESERVE_ECMA_KEYWORDS) {"debugger", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3},#endif {0, TOK_EOF, JSOP_NOP, JSVERSION_DEFAULT}};JSBooljs_InitScanner(JSContext *cx){ struct keyword *kw; JSAtom *atom; for (kw = keywords; kw->name; kw++) { atom = js_Atomize(cx, kw->name, strlen(kw->name), ATOM_PINNED); if (!atom) return JS_FALSE; ATOM_SET_KEYWORD(atom, kw); } return JS_TRUE;}JS_FRIEND_API(void)js_MapKeywords(void (*mapfun)(const char *)){ struct keyword *kw; for (kw = keywords; kw->name; kw++) mapfun(kw->name);}JSTokenStream *js_NewTokenStream(JSContext *cx, const jschar *base, size_t length, const char *filename, uintN lineno, JSPrincipals *principals){ JSTokenStream *ts; ts = js_NewBufferTokenStream(cx, base, length); if (!ts) return NULL; ts->filename = filename; ts->lineno = lineno; if (principals) JSPRINCIPALS_HOLD(cx, principals); ts->principals = principals; return ts;}JS_FRIEND_API(JSTokenStream *)js_NewBufferTokenStream(JSContext *cx, const jschar *base, size_t length){ size_t nb; JSTokenStream *ts; nb = sizeof(JSTokenStream) + JS_LINE_LIMIT * sizeof(jschar); JS_ARENA_ALLOCATE_CAST(ts, JSTokenStream *, &cx->tempPool, nb); if (!ts) { JS_ReportOutOfMemory(cx); return NULL; } memset(ts, 0, nb); ts->lineno = 1; ts->linebuf.base = ts->linebuf.limit = ts->linebuf.ptr = (jschar *)(ts + 1); ts->userbuf.base = (jschar *)base; ts->userbuf.limit = (jschar *)base + length; ts->userbuf.ptr = (jschar *)base; ts->listener = cx->runtime->sourceHandler; ts->listenerData = cx->runtime->sourceHandlerData; return ts;}JS_FRIEND_API(JSTokenStream *)js_NewFileTokenStream(JSContext *cx, const char *filename, FILE *defaultfp){ jschar *base; JSTokenStream *ts; FILE *file; JS_ARENA_ALLOCATE_CAST(base, jschar *, &cx->tempPool, JS_LINE_LIMIT * sizeof(jschar)); if (!base) return NULL; ts = js_NewBufferTokenStream(cx, base, JS_LINE_LIMIT); if (!ts) return NULL; if (!filename || strcmp(filename, "-") == 0) { file = defaultfp; } else { file = fopen(filename, "r"); if (!file) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN, filename, "No such file or directory"); return NULL; } } ts->userbuf.ptr = ts->userbuf.limit; ts->file = file; ts->filename = filename; return ts;}JS_FRIEND_API(JSBool)js_CloseTokenStream(JSContext *cx, JSTokenStream *ts){ if (ts->principals) JSPRINCIPALS_DROP(cx, ts->principals); return !ts->file || fclose(ts->file) == 0;}static intmy_fgets(char *buf, int size, FILE *file){ int n, i, c; JSBool crflag; n = size - 1; if (n < 0) return -1; crflag = JS_FALSE; for (i = 0; i < n && (c = getc(file)) != EOF; i++) { buf[i] = c; if (c == '\n') { /* any \n ends a line */ i++; /* keep the \n; we know there is room for \0 */ break; } if (crflag) { /* \r not followed by \n ends line at the \r */ ungetc(c, file); break; /* and overwrite c in buf with \0 */ } crflag = (c == '\r'); } buf[i] = '\0'; return i;}static int32GetChar(JSTokenStream *ts){ int32 c; ptrdiff_t i, j, len, olen; JSBool crflag; char cbuf[JS_LINE_LIMIT]; jschar *ubuf, *nl; if (ts->ungetpos != 0) { c = ts->ungetbuf[--ts->ungetpos]; } else { do { if (ts->linebuf.ptr == ts->linebuf.limit) { len = PTRDIFF(ts->userbuf.limit, ts->userbuf.ptr, jschar); if (len <= 0) { if (!ts->file) { ts->flags |= TSF_EOF; return EOF; } /* Fill ts->userbuf so that \r and \r\n convert to \n. */ crflag = (ts->flags & TSF_CRFLAG) != 0; len = my_fgets(cbuf, JS_LINE_LIMIT - crflag, ts->file); if (len <= 0) { ts->flags |= TSF_EOF; return EOF; } olen = len; ubuf = ts->userbuf.base; i = 0; if (crflag) { ts->flags &= ~TSF_CRFLAG; if (cbuf[0] != '\n') { ubuf[i++] = '\n'; len++; ts->linepos--; } } for (j = 0; i < len; i++, j++) ubuf[i] = (jschar) (unsigned char) cbuf[j]; ts->userbuf.limit = ubuf + len; ts->userbuf.ptr = ubuf; } if (ts->listener) { ts->listener(ts->filename, ts->lineno, ts->userbuf.ptr, len, &ts->listenerTSData, ts->listenerData); } nl = ts->saveEOL; if (!nl) { /* * Any one of \n, \r, or \r\n ends a line (the longest * match wins). Also allow the Unicode line and paragraph * separators. */ for (nl = ts->userbuf.ptr; nl < ts->userbuf.limit; nl++) { /* * Try to prevent value-testing on most characters by * filtering out characters that aren't 000x or 202x. */ if ((*nl & 0xDFD0) == 0) { if (*nl == '\n') break; if (*nl == '\r') { if (nl + 1 < ts->userbuf.limit && nl[1] == '\n') nl++; break; } if (*nl == LINE_SEPARATOR || *nl == PARA_SEPARATOR) break; } } } /* * If there was a line terminator, copy thru it into linebuf. * Else copy JS_LINE_LIMIT-1 bytes into linebuf. */ if (nl < ts->userbuf.limit) len = PTRDIFF(nl, ts->userbuf.ptr, jschar) + 1; if (len >= JS_LINE_LIMIT) { len = JS_LINE_LIMIT - 1; ts->saveEOL = nl; } else { ts->saveEOL = NULL; } js_strncpy(ts->linebuf.base, ts->userbuf.ptr, len); ts->userbuf.ptr += len; olen = len; /* * Make sure linebuf contains \n for EOL (don't do this in * userbuf because the user's string might be readonly). */ if (nl < ts->userbuf.limit) { if (*nl == '\r') { if (ts->linebuf.base[len-1] == '\r') { /* * Does the line segment end in \r? We must check * for a \n at the front of the next segment before * storing a \n into linebuf. This case matters * only when we're reading from a file. */ if (nl + 1 == ts->userbuf.limit && ts->file) { len--; ts->flags |= TSF_CRFLAG; /* clear NLFLAG? */ if (len == 0) { /* * This can happen when a segment ends in * \r\r. Start over. ptr == limit in this * case, so we'll fall into buffer-filling * code. */ return GetChar(ts); } } else { ts->linebuf.base[len-1] = '\n'; } } } else if (*nl == '\n') { if (nl > ts->userbuf.base && nl[-1] == '\r' && ts->linebuf.base[len-2] == '\r') { len--; JS_ASSERT(ts->linebuf.base[len] == '\n'); ts->linebuf.base[len-1] = '\n'; } } else if (*nl == LINE_SEPARATOR || *nl == PARA_SEPARATOR) { ts->linebuf.base[len-1] = '\n'; } } /* Reset linebuf based on adjusted segment length. */ ts->linebuf.limit = ts->linebuf.base + len; ts->linebuf.ptr = ts->linebuf.base; /* Update position of linebuf within physical userbuf line. */ if (!(ts->flags & TSF_NLFLAG)) ts->linepos += ts->linelen; else ts->linepos = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -