mirror of
https://github.com/ccxvii/mujs.git
synced 2026-09-20 22:23:44 +08:00
Clean up interface between lexer and parser.
This commit is contained in:
@@ -6,7 +6,7 @@ js_Ast *jsP_newnode(js_State *J, int type, js_Ast *a, js_Ast *b, js_Ast *c, js_A
|
||||
js_Ast *node = malloc(sizeof(js_Ast));
|
||||
|
||||
node->type = type;
|
||||
node->line = J->yyline;
|
||||
node->line = J->line;
|
||||
node->a = a;
|
||||
node->b = b;
|
||||
node->c = c;
|
||||
@@ -20,14 +20,14 @@ js_Ast *jsP_newnode(js_State *J, int type, js_Ast *a, js_Ast *b, js_Ast *c, js_A
|
||||
return node;
|
||||
}
|
||||
|
||||
js_Ast *jsP_newsnode(js_State *J, int type, const char *s)
|
||||
js_Ast *jsP_newstrnode(js_State *J, int type, const char *s)
|
||||
{
|
||||
js_Ast *node = jsP_newnode(J, type, 0, 0, 0, 0);
|
||||
node->s = js_intern(J, s);
|
||||
node->s = s;
|
||||
return node;
|
||||
}
|
||||
|
||||
js_Ast *jsP_newnnode(js_State *J, int type, double n)
|
||||
js_Ast *jsP_newnumnode(js_State *J, int type, double n)
|
||||
{
|
||||
js_Ast *node = jsP_newnode(J, type, 0, 0, 0, 0);
|
||||
node->n = n;
|
||||
|
||||
@@ -117,8 +117,8 @@ enum
|
||||
};
|
||||
|
||||
js_Ast *jsP_newnode(js_State *J, int type, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d);
|
||||
js_Ast *jsP_newsnode(js_State *J, int type, const char *s);
|
||||
js_Ast *jsP_newnnode(js_State *J, int type, double n);
|
||||
js_Ast *jsP_newstrnode(js_State *J, int type, const char *s);
|
||||
js_Ast *jsP_newnumnode(js_State *J, int type, double n);
|
||||
void jsP_freeast(js_State *J);
|
||||
|
||||
void printast(js_Ast *n, int level);
|
||||
|
||||
@@ -39,14 +39,17 @@ static inline int findword(const char *s, const char **list, int num)
|
||||
static inline int findkeyword(js_State *J, const char *s)
|
||||
{
|
||||
int i = findword(s, keywords, nelem(keywords));
|
||||
if (i >= 0)
|
||||
if (i >= 0) {
|
||||
J->text = keywords[i];
|
||||
return TK_BREAK + i; /* first keyword + i */
|
||||
}
|
||||
|
||||
if (findword(s, futurewords, nelem(futurewords)) >= 0)
|
||||
return jsP_error(J, "'%s' is a future reserved word", s);
|
||||
if (J->strict && findword(s, strictfuturewords, nelem(strictfuturewords)) >= 0)
|
||||
return jsP_error(J, "'%s' is a strict mode future reserved word", s);
|
||||
|
||||
J->text = js_intern(J, s);
|
||||
return TK_IDENTIFIER;
|
||||
}
|
||||
|
||||
@@ -59,25 +62,26 @@ static inline int findkeyword(js_State *J, const char *s)
|
||||
|
||||
static void textinit(js_State *J)
|
||||
{
|
||||
if (!J->yytext) {
|
||||
J->yycap = 4096;
|
||||
J->yytext = malloc(J->yycap);
|
||||
if (!J->buf.text) {
|
||||
J->buf.cap = 4096;
|
||||
J->buf.text = malloc(J->buf.cap);
|
||||
}
|
||||
J->yylen = 0;
|
||||
J->buf.len = 0;
|
||||
}
|
||||
|
||||
static inline void textpush(js_State *J, int c)
|
||||
{
|
||||
if (J->yylen >= J->yycap) {
|
||||
J->yycap = J->yycap * 2;
|
||||
J->yytext = realloc(J->yytext, J->yycap);
|
||||
if (J->buf.len >= J->buf.cap) {
|
||||
J->buf.cap = J->buf.cap * 2;
|
||||
J->buf.text = realloc(J->buf.text, J->buf.cap);
|
||||
}
|
||||
J->yytext[J->yylen++] = c;
|
||||
J->buf.text[J->buf.len++] = c;
|
||||
}
|
||||
|
||||
static inline void textend(js_State *J)
|
||||
static inline char *textend(js_State *J)
|
||||
{
|
||||
textpush(J, 0);
|
||||
return J->buf.text;
|
||||
}
|
||||
|
||||
static inline int iswhite(int c)
|
||||
@@ -200,7 +204,7 @@ static inline int lexnumber(js_State *J, const char **sp)
|
||||
*sp += 2;
|
||||
if (!ishex(PEEK()))
|
||||
return jsP_error(J, "0x not followed by hexademical digit");
|
||||
J->yynumber = lexhex(sp);
|
||||
J->number = lexhex(sp);
|
||||
return TK_NUMBER;
|
||||
}
|
||||
|
||||
@@ -215,7 +219,7 @@ static inline int lexnumber(js_State *J, const char **sp)
|
||||
if (isidentifierstart(PEEK()))
|
||||
return jsP_error(J, "number with letter suffix");
|
||||
|
||||
J->yynumber = n;
|
||||
J->number = n;
|
||||
return TK_NUMBER;
|
||||
}
|
||||
|
||||
@@ -260,6 +264,7 @@ static inline int lexescape(js_State *J, const char **sp)
|
||||
|
||||
static inline int lexstring(js_State *J, const char **sp, int q)
|
||||
{
|
||||
const char *s;
|
||||
int c = GET();
|
||||
|
||||
textinit(J);
|
||||
@@ -276,8 +281,9 @@ static inline int lexstring(js_State *J, const char **sp, int q)
|
||||
c = GET();
|
||||
}
|
||||
|
||||
textend(J);
|
||||
s = textend(J);
|
||||
|
||||
J->text = js_intern(J, s);
|
||||
return TK_STRING;
|
||||
}
|
||||
|
||||
@@ -302,6 +308,7 @@ static int isregexpcontext(int last)
|
||||
|
||||
static int lexregexp(js_State *J, const char **sp)
|
||||
{
|
||||
const char *s;
|
||||
int c;
|
||||
|
||||
textinit(J);
|
||||
@@ -324,23 +331,24 @@ static int lexregexp(js_State *J, const char **sp)
|
||||
}
|
||||
}
|
||||
|
||||
textend(J);
|
||||
s = textend(J);
|
||||
|
||||
/* regexp flags */
|
||||
J->yyflags.g = J->yyflags.i = J->yyflags.m = 0;
|
||||
J->flags.g = J->flags.i = J->flags.m = 0;
|
||||
|
||||
c = PEEK();
|
||||
while (isidentifierpart(c)) {
|
||||
if (c == 'g') J->yyflags.g ++;
|
||||
else if (c == 'i') J->yyflags.i ++;
|
||||
else if (c == 'm') J->yyflags.m ++;
|
||||
if (c == 'g') J->flags.g ++;
|
||||
else if (c == 'i') J->flags.i ++;
|
||||
else if (c == 'm') J->flags.m ++;
|
||||
else return jsP_error(J, "illegal flag in regular expression: %c", c);
|
||||
c = NEXTPEEK();
|
||||
}
|
||||
|
||||
if (J->yyflags.g > 1 || J->yyflags.i > 1 || J->yyflags.m > 1)
|
||||
if (J->flags.g > 1 || J->flags.i > 1 || J->flags.m > 1)
|
||||
return jsP_error(J, "duplicated flag in regular expression");
|
||||
|
||||
J->text = js_intern(J, s);
|
||||
return TK_REGEXP;
|
||||
}
|
||||
|
||||
@@ -372,7 +380,7 @@ static int lex(js_State *J, const char **sp)
|
||||
/* consume CR LF as one unit */
|
||||
if (c == '\r' && PEEK() == '\n')
|
||||
NEXT();
|
||||
J->yyline++;
|
||||
J->line++;
|
||||
J->newline = 1;
|
||||
if (isnlthcontext(J->lasttoken))
|
||||
return ';';
|
||||
@@ -408,7 +416,7 @@ static int lex(js_State *J, const char **sp)
|
||||
|
||||
textend(J);
|
||||
|
||||
return findkeyword(J, J->yytext);
|
||||
return findkeyword(J, J->buf.text);
|
||||
}
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
@@ -535,17 +543,15 @@ static int lex(js_State *J, const char **sp)
|
||||
}
|
||||
}
|
||||
|
||||
void jsP_initlex(js_State *J, const char *source)
|
||||
void jsP_initlex(js_State *J, const char *filename, const char *source)
|
||||
{
|
||||
J->yysource = source;
|
||||
J->yyline = 1;
|
||||
J->filename = filename;
|
||||
J->source = source;
|
||||
J->line = 1;
|
||||
J->lasttoken = 0;
|
||||
}
|
||||
|
||||
int jsP_lex(js_State *J)
|
||||
{
|
||||
int t = lex(J, &J->yysource);
|
||||
// TODO: move yytext/yynumber into jsP_lval
|
||||
J->lasttoken = t;
|
||||
return t;
|
||||
return J->lasttoken = lex(J, &J->source);
|
||||
}
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
#include "js.h"
|
||||
#include "js-parse.h"
|
||||
|
||||
static int jsP_loadstring(js_State *J, const char *source)
|
||||
static int jsP_loadstring(js_State *J, const char *filename, const char *source)
|
||||
{
|
||||
int t;
|
||||
|
||||
jsP_initlex(J, source);
|
||||
t = jsP_parse(J);
|
||||
printf("parse result = %d\n", t);
|
||||
|
||||
return 0;
|
||||
return jsP_parse(J, filename, source);
|
||||
}
|
||||
|
||||
|
||||
int js_loadstring(js_State *J, const char *source)
|
||||
{
|
||||
J->yyfilename = "(string)";
|
||||
return jsP_loadstring(J, source);
|
||||
return jsP_loadstring(J, "(string)", source);
|
||||
}
|
||||
|
||||
int js_loadfile(js_State *J, const char *filename)
|
||||
@@ -48,8 +40,7 @@ int js_loadfile(js_State *J, const char *filename)
|
||||
|
||||
s[n] = 0; /* zero-terminate string containing file data */
|
||||
|
||||
J->yyfilename = filename;
|
||||
t = jsP_loadstring(J, s);
|
||||
t = jsP_loadstring(J, filename, s);
|
||||
|
||||
free(s);
|
||||
fclose(f);
|
||||
|
||||
+16
-14
@@ -68,12 +68,12 @@ static const char *tokenstring[] = {
|
||||
"'void'", "'while'", "'with'",
|
||||
};
|
||||
|
||||
static void next(js_State *J)
|
||||
static inline void next(js_State *J)
|
||||
{
|
||||
J->lookahead = jsP_lex(J);
|
||||
}
|
||||
|
||||
static int accept(js_State *J, int t)
|
||||
static inline int accept(js_State *J, int t)
|
||||
{
|
||||
if (J->lookahead == t) {
|
||||
next(J);
|
||||
@@ -82,7 +82,7 @@ static int accept(js_State *J, int t)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void expect(js_State *J, int t)
|
||||
static inline void expect(js_State *J, int t)
|
||||
{
|
||||
if (accept(J, t))
|
||||
return;
|
||||
@@ -103,7 +103,7 @@ static void semicolon(js_State *J)
|
||||
static js_Ast *identifier(js_State *J)
|
||||
{
|
||||
if (J->lookahead == TK_IDENTIFIER) {
|
||||
js_Ast *a = jsP_newsnode(J, AST_IDENTIFIER, J->yytext);
|
||||
js_Ast *a = jsP_newstrnode(J, AST_IDENTIFIER, J->text);
|
||||
next(J);
|
||||
return a;
|
||||
}
|
||||
@@ -121,7 +121,7 @@ static js_Ast *identifieropt(js_State *J)
|
||||
static js_Ast *identifiername(js_State *J)
|
||||
{
|
||||
if (J->lookahead == TK_IDENTIFIER || J->lookahead >= TK_BREAK) {
|
||||
js_Ast *a = jsP_newsnode(J, AST_IDENTIFIER, J->yytext);
|
||||
js_Ast *a = jsP_newstrnode(J, AST_IDENTIFIER, J->text);
|
||||
next(J);
|
||||
return a;
|
||||
}
|
||||
@@ -172,10 +172,10 @@ static js_Ast *propname(js_State *J)
|
||||
{
|
||||
js_Ast *name;
|
||||
if (J->lookahead == TK_NUMBER) {
|
||||
name = jsP_newnnode(J, AST_NUMBER, J->yynumber);
|
||||
name = jsP_newnumnode(J, AST_NUMBER, J->number);
|
||||
next(J);
|
||||
} else if (J->lookahead == TK_STRING) {
|
||||
name = jsP_newsnode(J, AST_STRING, J->yytext);
|
||||
name = jsP_newstrnode(J, AST_STRING, J->text);
|
||||
next(J);
|
||||
} else {
|
||||
name = identifiername(J);
|
||||
@@ -187,7 +187,7 @@ static js_Ast *propassign(js_State *J)
|
||||
{
|
||||
js_Ast *name, *value, *arg, *body;
|
||||
|
||||
if (J->lookahead == TK_IDENTIFIER && !strcmp(J->yytext, "get")) {
|
||||
if (J->lookahead == TK_IDENTIFIER && !strcmp(J->text, "get")) {
|
||||
next(J);
|
||||
name = propname(J);
|
||||
expect(J, '(');
|
||||
@@ -196,7 +196,7 @@ static js_Ast *propassign(js_State *J)
|
||||
return EXP2(PROP_GET, name, body);
|
||||
}
|
||||
|
||||
if (J->lookahead == TK_IDENTIFIER && !strcmp(J->yytext, "set")) {
|
||||
if (J->lookahead == TK_IDENTIFIER && !strcmp(J->text, "set")) {
|
||||
next(J);
|
||||
name = propname(J);
|
||||
expect(J, '(');
|
||||
@@ -234,17 +234,17 @@ static js_Ast *primary(js_State *J)
|
||||
{
|
||||
js_Ast *a;
|
||||
if (J->lookahead == TK_IDENTIFIER) {
|
||||
a = jsP_newsnode(J, AST_IDENTIFIER, J->yytext);
|
||||
a = jsP_newstrnode(J, AST_IDENTIFIER, J->text);
|
||||
next(J);
|
||||
return a;
|
||||
}
|
||||
if (J->lookahead == TK_STRING) {
|
||||
a = jsP_newsnode(J, AST_STRING, J->yytext);
|
||||
a = jsP_newstrnode(J, AST_STRING, J->text);
|
||||
next(J);
|
||||
return a;
|
||||
}
|
||||
if (J->lookahead == TK_NUMBER) {
|
||||
a = jsP_newnnode(J, AST_NUMBER, J->yynumber);
|
||||
a = jsP_newnumnode(J, AST_NUMBER, J->number);
|
||||
next(J);
|
||||
return a;
|
||||
}
|
||||
@@ -808,7 +808,7 @@ int jsP_error(js_State *J, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "syntax error: %s:%d: ", J->yyfilename, J->yyline);
|
||||
fprintf(stderr, "syntax error: %s:%d: ", J->filename, J->line);
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
@@ -820,8 +820,10 @@ int jsP_error(js_State *J, const char *fmt, ...)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int jsP_parse(js_State *J)
|
||||
int jsP_parse(js_State *J, const char *filename, const char *source)
|
||||
{
|
||||
jsP_initlex(J, filename, source);
|
||||
|
||||
if (setjmp(J->jb)) {
|
||||
jsP_freeast(J);
|
||||
return 1;
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ js_State *js_newstate(void)
|
||||
|
||||
void js_close(js_State *J)
|
||||
{
|
||||
free(J->yytext);
|
||||
free(J->buf.text);
|
||||
free(J);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,33 +28,37 @@ const char *js_intern(js_State *J, const char *s);
|
||||
|
||||
typedef struct js_Ast js_Ast;
|
||||
|
||||
void jsP_initlex(js_State *J, const char *source);
|
||||
void jsP_initlex(js_State *J, const char *filename, const char *source);
|
||||
int jsP_lex(js_State *J);
|
||||
int jsP_parse(js_State *J);
|
||||
int jsP_parse(js_State *J, const char *filename, const char *source);
|
||||
int jsP_error(js_State *J, const char *fmt, ...);
|
||||
|
||||
void js_printstringtree(js_State *J);
|
||||
|
||||
struct js_State
|
||||
{
|
||||
const char *yyfilename;
|
||||
const char *yysource;
|
||||
int yyline;
|
||||
jmp_buf jb; /* setjmp buffer for error handling in parser */
|
||||
|
||||
char *yytext;
|
||||
size_t yylen, yycap;
|
||||
double yynumber;
|
||||
struct { int g, i, m; } yyflags;
|
||||
js_StringNode *strings;
|
||||
|
||||
/* input */
|
||||
const char *filename;
|
||||
const char *source;
|
||||
int line;
|
||||
|
||||
/* lexer */
|
||||
struct { char *text; size_t len, cap; } buf;
|
||||
int lasttoken;
|
||||
int newline;
|
||||
|
||||
int strict;
|
||||
|
||||
/* parser */
|
||||
int lookahead;
|
||||
jmp_buf jb; /* setjmp buffer for error handling in parser */
|
||||
const char *text;
|
||||
double number;
|
||||
struct { char g, i, m; } flags;
|
||||
js_Ast *ast; /* list of allocated nodes to free after parsing */
|
||||
|
||||
js_StringNode *strings;
|
||||
int strict;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user