📄 jsscan.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set sw=4 ts=8 et tw=78: * * ***** 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"#include "jsscript.h"#if JS_HAS_XML_SUPPORT#include "jsparse.h"#include "jsxml.h"#endif#define JS_KEYWORD(keyword, type, op, version) \ const char js_##keyword##_str[] = #keyword;#include "jskeyword.tbl"#undef JS_KEYWORDstruct keyword { const char *chars; /* C string with keyword text */ JSTokenType tokentype; /* JSTokenType */ JSOp op; /* JSOp */ JSVersion version; /* JSVersion */};static const struct keyword keyword_defs[] = {#define JS_KEYWORD(keyword, type, op, version) \ {js_##keyword##_str, type, op, version},#include "jskeyword.tbl"#undef JS_KEYWORD};#define KEYWORD_COUNT (sizeof keyword_defs / sizeof keyword_defs[0])static const struct keyword *FindKeyword(const jschar *s, size_t length){ register size_t i; const struct keyword *kw; const char *chars; JS_ASSERT(length != 0);#define JSKW_LENGTH() length#define JSKW_AT(column) s[column]#define JSKW_GOT_MATCH(index) i = (index); goto got_match;#define JSKW_TEST_GUESS(index) i = (index); goto test_guess;#define JSKW_NO_MATCH() goto no_match;#include "jsautokw.h"#undef JSKW_NO_MATCH#undef JSKW_TEST_GUESS#undef JSKW_GOT_MATCH#undef JSKW_AT#undef JSKW_LENGTH got_match: return &keyword_defs[i]; test_guess: kw = &keyword_defs[i]; chars = kw->chars; do { if (*s++ != (unsigned char)(*chars++)) goto no_match; } while (--length != 0); return kw; no_match: return NULL;}JSTokenTypejs_CheckKeyword(const jschar *str, size_t length){ const struct keyword *kw; JS_ASSERT(length != 0); kw = FindKeyword(str, length); return kw ? kw->tokentype : TOK_EOF;}JS_FRIEND_API(void)js_MapKeywords(void (*mapfun)(const char *)){ size_t i; for (i = 0; i != KEYWORD_COUNT; ++i) mapfun(keyword_defs[i].chars);}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;}#define TBMIN 64static JSBoolGrowTokenBuf(JSStringBuffer *sb, size_t newlength){ JSContext *cx; jschar *base; ptrdiff_t offset, length; size_t tbsize; JSArenaPool *pool; cx = sb->data; base = sb->base; offset = PTRDIFF(sb->ptr, base, jschar); pool = &cx->tempPool; if (!base) { tbsize = TBMIN * sizeof(jschar); length = TBMIN - 1; JS_ARENA_ALLOCATE_CAST(base, jschar *, pool, tbsize); } else { length = PTRDIFF(sb->limit, base, jschar); if ((size_t)length >= ~(size_t)0 / sizeof(jschar)) { base = NULL; } else { tbsize = (length + 1) * sizeof(jschar); length += length + 1; JS_ARENA_GROW_CAST(base, jschar *, pool, tbsize, tbsize); } } if (!base) { JS_ReportOutOfMemory(cx); sb->base = STRING_BUFFER_ERROR_BASE; return JS_FALSE; } sb->base = base; sb->limit = base + length; sb->ptr = base + offset; return JS_TRUE;}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->tokenbuf.grow = GrowTokenBuf; ts->tokenbuf.data = cx; 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->flags & TSF_OWNFILENAME) JS_free(cx, (void *) ts->filename); if (ts->principals) JSPRINCIPALS_DROP(cx, ts->principals); return !ts->file || fclose(ts->file) == 0;}JS_FRIEND_API(int)js_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 = js_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) { /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -