Skip to content

Commit

Permalink
Adds productions for most of the remaining syntax.
Browse files Browse the repository at this point in the history
- throw, instanceof, regular expressions, switch statements
- 'in' operator is present but commented out due to shift/reduce conflicts.
  Many of the productions will need a -NoIn doppelgänger to differentiate
  from the for-in form.
- Named function expressions are currently a syntax error. This will
  also need to be fixed.
  • Loading branch information
ndreynolds committed Oct 16, 2012
1 parent 71a8f3e commit d970cce
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 93 deletions.
77 changes: 63 additions & 14 deletions src/grammar.y
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@
#define NEW_NUM(x) NEW_NODE(NODE_NUM,0,0,0,x,0)
#define NEW_BOOL(x) NEW_NODE(NODE_BOOL,0,0,0,x,0)
#define NEW_STR(x) NEW_NODE(NODE_STR,0,0,0,0,x)
#define NEW_REGEXP(x) NEW_NODE(NODE_REGEXP,0,0,0,0,x)
#define NEW_NULL() NEW_NODE(NODE_NULL,0,0,0,0,0)
#define NEW_RETURN(exp) NEW_NODE(NODE_RETURN,exp,0,0,0,0)
#define NEW_THROW(exp) NEW_NODE(NODE_THROW,exp,0,0,0,0)
#define NEW_CONT() NEW_NODE(NODE_CONT,0,0,0,0,0)
#define NEW_BREAK() NEW_NODE(NODE_BREAK,0,0,0,0,0)
#define NEW_THIS() NEW_NODE(NODE_THIS,0,0,0,0,0)
Expand All @@ -72,6 +74,10 @@
#define NEW_VARSTMT(declst) NEW_NODE(NODE_VAR_STMT,declst,0,0,0,0)
#define NEW_VARDEC(id,exp) NEW_NODE(NODE_VAR_DEC,id,exp,0,0,0)
#define NEW_VARDECLST(head,tail) NEW_NODE(NODE_VAR_DEC_LST,head,tail,0,0,0)
#define NEW_SWITCH(exp,cases) NEW_NODE(NODE_SWITCH_STMT,exp,cases,0,0,0)
#define NEW_CASEBLOCK(c1,def,c2) NEW_NODE(NODE_CASE_BLOCK,c1,def,c2,0,0)
#define NEW_CLAUSELST(head,tail) NEW_NODE(NODE_CLAUSE_LST,head,tail,0,0,0)
#define NEW_CLAUSE(exp,stmtlst) NEW_NODE(NODE_CLAUSE,exp,stmtlst,0,0,0)

void yyerror(const char *);
int yylex(void);
Expand All @@ -91,33 +97,25 @@

%token<floatval> FLOAT
%token<intval> INTEGER
%token<val> IDENT STRING TRUE FALSE
%token<val> IDENT STRING REGEXP TRUE FALSE


/* OPERATORS */

/* Boolean */
%token<val> AND OR
/* Unary */
%token<val> PLUSPLUS MINUSMINUS VOID DELETE TYPEOF
/* Relational */
%token<val> EQEQ GTE LTE NE STEQ STNE
/* Bitwise */
%token<val> PLUSPLUS MINUSMINUS VOID DELETE TYPEOF
%token<val> EQEQ GTE LTE NE STEQ STNE INSTANCEOF
%token<val> LSHIFT RSHIFT
/* Assignment */
%token<val> PLUSEQ MINUSEQ MULTEQ DIVEQ MODEQ


/* KEYWORDS */

/* Iteration */
%token<val> WHILE DO FOR
/* Branch */
%token<val> IF ELSE
/* Control */
%token<val> BREAK CONTINUE RETURN
/* Misc */
%token<val> BREAK CONTINUE RETURN THROW
%token<val> VAR IN THIS NULLT FUNCTION NEW
%token<val> SWITCH CASE DEFAULT


/* ASSOCIATIVITY */
Expand All @@ -144,10 +142,12 @@
%type<node> BitwiseXORExpression LogicalORExpression LogicalANDExpression
%type<node> MultiplicativeExpression ConditionalExpression StatementList
%type<node> AssignmentExpression ElementList PropertyName PropertyAssignment
%type<node> PropertyNameAndValueList Function FunctionBody FunctionExpression
%type<node> PropertyNameAndValueList Function FunctionExpression FunctionBody
%type<node> FormalParameterList CallExpression MemberExpression NewExpression
%type<node> Arguments ArgumentList Elision VariableDeclarationList
%type<node> VariableDeclaration Initializer ExponentPart ExponentIndicator
%type<node> ThrowStatement SwitchStatement CaseBlock CaseClauses CaseClause
%type<node> DefaultClause RegularExpressionLiteral

%%

Expand Down Expand Up @@ -185,6 +185,10 @@ Statement : Block
{ $$ = $1; }
| ReturnStatement
{ $$ = $1; }
| ThrowStatement
{ $$ = $1; }
| SwitchStatement
{ $$ = $1; }
;

Block : '{' StatementList '}'
Expand Down Expand Up @@ -285,6 +289,39 @@ ReturnStatement : RETURN ';'
{ $$ = NEW_RETURN($2); }
;

ThrowStatement : THROW Expression ';'
{ $$ = NEW_THROW($2); }
;

SwitchStatement : SWITCH '(' Expression ')' CaseBlock
{ $$ = NEW_SWITCH($3, $5); }
;

CaseBlock : '{' CaseClauses '}'
{ $$ = NEW_CASEBLOCK($2, NULL, NULL); }
| '{' CaseClauses DefaultClause '}'
{ $$ = NEW_CASEBLOCK($2, $3, NULL); }
| '{' CaseClauses DefaultClause CaseClauses '}'
{ $$ = NEW_CASEBLOCK($2, $3, $4); }
;

CaseClauses : CaseClause
{ $$ = NEW_CLAUSELST($1, NULL); }
| CaseClauses CaseClause
{ $$ = NEW_CLAUSELST($2, $1); }

CaseClause : CASE Expression ':' StatementList
{ $$ = NEW_CLAUSE($2, $4); }
| CASE Expression ':'
{ $$ = NEW_CLAUSE($2, NULL); }
;

DefaultClause : DEFAULT ':' StatementList
{ $$ = NEW_CLAUSE(NULL, $3); }
| DEFAULT ':'
{ $$ = NEW_CLAUSE(NULL, NULL); }
;

Literal : NullLiteral
{ $$ = $1; }
| BooleanLiteral
Expand All @@ -295,6 +332,8 @@ Literal : NullLiteral
{ $$ = $1; }
| ObjectLiteral
{ $$ = $1; }
| RegularExpressionLiteral
{ $$ = $1; }
;

ArrayLiteral : '[' ']'
Expand Down Expand Up @@ -387,6 +426,10 @@ PropertyName : Identifier
| NumericLiteral
{ $$ = $1; }
;

RegularExpressionLiteral : REGEXP
{ $$ = NEW_REGEXP(NULL); }
;

/* Whether a named function is a declaration or expression is ambiguous
here. We'll decide that on evaluation. */
Expand Down Expand Up @@ -489,6 +532,12 @@ RelationalExpression : ShiftExpression
{ $$ = NEW_EXP($1, $3, "<="); }
| RelationalExpression GTE ShiftExpression
{ $$ = NEW_EXP($1, $3, ">="); }
| RelationalExpression INSTANCEOF ShiftExpression
{ $$ = NEW_EXP($1, $3, "instanceof"); }
/*
| RelationalExpression IN ShiftExpression
{ $$ = NEW_EXP($1, $3, "in"); }
*/
;

ShiftExpression : AdditiveExpression
Expand Down
98 changes: 53 additions & 45 deletions src/lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
int print_tokens;
char * fh_extract_string(char *);
int fh_get_input(char *, int);
int fh_token(char *, int, int);
#define TOKEN(name,tok) fh_token((name),(tok),0)
#define TOKEN2(name,tok) fh_token((name),(tok),1)
int fh_token(char *, int);
#define TOKEN(name,tok) fh_token((name),(tok))
#define YY_USER_ACTION yyuseraction();
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) result = fh_get_input(buf, max_size);
Expand All @@ -25,62 +24,71 @@
%%

/* KEYWORDS */
"while" return TOKEN("WHILE", WHILE);
"do" return TOKEN("DO", DO);
"for" return TOKEN("FOR", FOR);
"if" return TOKEN("IF", IF);
"in" return TOKEN("IN", IN);
"else" return TOKEN("ELSE", ELSE);
"break" return TOKEN("BREAK", BREAK);
"continue" return TOKEN("CONTINUE", CONTINUE);
"return" return TOKEN("RETURN", RETURN);
"function" return TOKEN("FUNCTION", FUNCTION);
"delete" return TOKEN("DELETE", DELETE);
"void" return TOKEN("VOID", VOID);
"typeof" return TOKEN("TYPEOF", TYPEOF);
"new" return TOKEN("NEW", NEW);
"var" return TOKEN("VAR", VAR);
"null" return TOKEN("NULL", NULLT);
"true" return TOKEN("TRUE", TRUE);
"false" return TOKEN("FALSE", FALSE);
"while" return TOKEN("LITERAL", WHILE);
"do" return TOKEN("LITERAL", DO);
"for" return TOKEN("LITERAL", FOR);
"if" return TOKEN("LITERAL", IF);
"in" return TOKEN("LITERAL", IN);
"else" return TOKEN("LITERAL", ELSE);
"break" return TOKEN("LITERAL", BREAK);
"continue" return TOKEN("LITERAL", CONTINUE);
"return" return TOKEN("LITERAL", RETURN);
"throw" return TOKEN("LITERAL", THROW);
"function" return TOKEN("LITERAL", FUNCTION);
"delete" return TOKEN("LITERAL", DELETE);
"void" return TOKEN("LITERAL", VOID);
"typeof" return TOKEN("LITERAL", TYPEOF);
"instanceof" return TOKEN("LITERAL", INSTANCEOF);
"switch" return TOKEN("LITERAL", SWITCH);
"case" return TOKEN("LITERAL", CASE);
"default" return TOKEN("LITERAL", DEFAULT);
"new" return TOKEN("LITERAL", NEW);
"var" return TOKEN("LITERAL", VAR);
"null" return TOKEN("LITERAL", NULLT);
"true" return TOKEN("LITERAL", TRUE);
"false" return TOKEN("LITERAL", FALSE);

/* LITERALS */
L?\"(\\.|[^\\"])*\" { yylval.val = fh_extract_string(yytext);
return TOKEN2("STR", STRING); }
return TOKEN("STR", STRING); }
L?'(\\.|[^\\'])*' { yylval.val = fh_extract_string(yytext);
return TOKEN2("STR", STRING); }
return TOKEN("STR", STRING); }
[_\$A-Za-z][_\$0-9A-Za-z]* { yylval.val = yytext;
return TOKEN2("IDENT", IDENT); }
return TOKEN("IDENT", IDENT); }
[0-9]+ { yylval.intval = atoi(yytext);
return TOKEN2("INT", INTEGER); }
return TOKEN("INT", INTEGER); }
[0-9]+\.[0-9]+ { yylval.floatval = atof(yytext);
return TOKEN2("FLOAT", FLOAT); }
return TOKEN("FLOAT", FLOAT); }
/* TODO: This is very incomplete */
\/[^\ ]+\/([imgy]{0,4}) { yylval.val = yytext;
return TOKEN("REGEXP", REGEXP); }

/* COMMENTS */
[/][/].* ; /* ignore comments */

/* OPERATORS */
"||" return TOKEN2("OP", OR);
"&&" return TOKEN2("OP", AND);
"++" return TOKEN2("OP", PLUSPLUS);
"--" return TOKEN2("OP", MINUSMINUS);
"==" return TOKEN2("OP", EQEQ);
"!=" return TOKEN2("OP", NE);
"<=" return TOKEN2("OP", LTE);
">=" return TOKEN2("OP", GTE);
"+=" return TOKEN2("OP", PLUSEQ);
"-=" return TOKEN2("OP", MINUSEQ);
"*=" return TOKEN2("OP", MULTEQ);
"/=" return TOKEN2("OP", DIVEQ);
"%=" return TOKEN2("OP", MODEQ);
"<<" return TOKEN2("OP", LSHIFT);
">>" return TOKEN2("OP", RSHIFT);
"===" return TOKEN2("OP", STEQ);
"!==" return TOKEN2("OP", STNE);
"||" return TOKEN("OP", OR);
"&&" return TOKEN("OP", AND);
"++" return TOKEN("OP", PLUSPLUS);
"--" return TOKEN("OP", MINUSMINUS);
"==" return TOKEN("OP", EQEQ);
"!=" return TOKEN("OP", NE);
"<=" return TOKEN("OP", LTE);
">=" return TOKEN("OP", GTE);
"+=" return TOKEN("OP", PLUSEQ);
"-=" return TOKEN("OP", MINUSEQ);
"*=" return TOKEN("OP", MULTEQ);
"/=" return TOKEN("OP", DIVEQ);
"%=" return TOKEN("OP", MODEQ);
"<<" return TOKEN("OP", LSHIFT);
">>" return TOKEN("OP", RSHIFT);
"===" return TOKEN("OP", STEQ);
"!==" return TOKEN("OP", STNE);

[-+()\[\]=*/%<>,.:;?!{}] return *yytext;
[ \t\v\f] ;
\n { yycolumn = 0;
yytext = NULL;
TOKEN("NEWLINE", 0);
if (interactive) return EOF; }
<<EOF>> { yycolumn = 0;
Expand Down Expand Up @@ -116,10 +124,10 @@ yyuseraction(void)

// Wrap token returns for debugging.
int
fh_token(char *name, int token, int show_text)
fh_token(char *name, int token)
{
if (print_tokens) {
if (show_text)
if (yytext)
printf("(%s %s)\n", name, yytext);
else
printf("(%s)\n", name);
Expand Down
6 changes: 6 additions & 0 deletions src/nodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ print_node(Node *node, bool rec, int depth)
case NODE_NUM: printf("number (%f)\n", node->val); return;
case NODE_BOOL: printf("bool (%d)\n", (int)node->val); return;
case NODE_STR: printf("string (%s)\n", node->sval); return;
case NODE_REGEXP: printf("regexp (%s)\n", node->sval); return;
case NODE_NULL: printf("null (NULL)\n"); return;
case NODE_VAR_STMT: printf("variable statement"); break;
case NODE_VAR_DEC: printf("variable declaration"); break;
Expand All @@ -121,6 +122,7 @@ print_node(Node *node, bool rec, int depth)
case NODE_CONT: printf("continue"); break;
case NODE_THIS: printf("this"); break;
case NODE_RETURN: printf("return"); break;
case NODE_THROW: printf("throw"); break;
case NODE_BLOCK: printf("block"); break;
case NODE_OBJ: printf("object"); break;
case NODE_PROP: printf("property"); break;
Expand All @@ -136,6 +138,10 @@ print_node(Node *node, bool rec, int depth)
case NODE_EL_LST: printf("element list"); break;
case NODE_ELISION: printf("elision"); break;
case NODE_SRC_LST: printf("source list"); break;
case NODE_SWITCH_STMT: printf("switch statement"); break;
case NODE_CASE_BLOCK: printf("case block"); break;
case NODE_CLAUSE_LST: printf("case clause list"); break;
case NODE_CLAUSE: printf("case clause"); break;
case NODE_EXP:
printf("expression ");
if (node->sub_type == NODE_UNARY_PRE) printf("(unary prefix)");
Expand Down
Loading

0 comments on commit d970cce

Please sign in to comment.