📄 parser.y
字号:
/* PARSER.Y
* C++ Grammar
* UnderC C++ interpreter
* Steve Donovan, 2001
* This is GPL'd software, and the usual disclaimers apply.
* See LICENCE
*/
%{
/* *SJD* essential prototypes for C++ compilation */
int yylex();
int yyerror(const char *s);
#include <stdlib.h>
#define xmalloc malloc
#define MSDOS
#include "common.h"
using namespace Parser;
using namespace Expressions;
#define YYERROR_VERBOSE 1
#define YYDEBUG 1
//#define YYPURE
/* some shortcuts */
typedef Stack<bool,40> BoolStack;
BoolStack als(false);
BoolStack dcl_stack;
BoolStack typedef_stack;
bool dump_it = false;
PEntry last_type_entry;
PExpr gFunInit = NULL; // used to flag pure virtual methods...
void dcl_set(bool yes, bool comma_flag) {
dcl_stack.push(state.in_declaration);
if (dcl_stack.depth() > 40) outln("runaway dcl stack");
state.in_declaration = yes;
als.push(comma_flag); /* force ',' _not_ to be COMMA */
}
void dcl_reset() {
state.in_declaration = dcl_stack.pop();
als.pop();
}
void force_comma_flag() {
als.clear();
dcl_stack.clear();
dcl_set(false,false);
}
bool in_arg_list() {
return als.TOS();
}
inline void enter_arglist() { dcl_set(false); }
void leave_arglist() { dcl_reset(); }
string tag_name; /* A fiddle */
bool IEF=false;
/*BoolStack ief_stack;*/
void IEF_set() { /*ief_stack.push(IEF);*/ IEF=true; }
void IEF_reset() { IEF=false; /*ief_stack.pop();*/ }
void ttpush(TType t) { tpush(AsType(t)); }
void raise_error(string msg)
{
int yyerror(const char *);
if (state.err != "") { msg = state.err; state.err = ""; }
state.reset();
als.clear(); als.push(false);
yyerror(msg.c_str());
}
bool check_error()
{
if (state.err != "") {
raise_error(state.err);
state.err = "";
return true;
}
return false;
}
%}
%union{
int val;
long ctype;
char* str;
Entry* entry;
Expr* expression;
ExprList *elist;
Class *classptr;
TypeList *typelist;
}
%token <str> TOKEN
%token <entry> IDEN,CONSTANT,TYPENAME,TYPENAME_FUNCTION,TEMPLATE_NAME, TEMPLATE_NAME_EXPR,
%token <classptr> THIS_CLASSNAME
%token FLOAT,DOUBLE,UNSIGNED,INT,SHORT,LONG,CHAR,VOID,BOOL
%token TYPEDEF,CLASS,STRUCT,ENUM,OPERATOR,GOTO,UNION
%token <val> STATIC_CAST,CONST_CAST,DYNAMIC_CAST,REINTERPRET_CAST, STRUCT_X, CLASS_X, STRUCT_Y, CLASS_Y, UNION_Y
%token IF,ELSE,WHILE,DO,FOR,SWITCH,CASE,RETURN,CONTINUE,BREAK,OPERATOR,DEFAULT
%token NAMESPACE,USING,TRY,CATCH,THROW,TEMPLATE,EXTERN
%token THREEDOT, TYPEOF, EXPLICIT, FRIEND, LAMBDA, FAKE_INIT_LIST
%token <val> CONST,STATIC,STDCALL,API,VIRTUAL,PRIVATE,PROTECTED,PUBLIC,CLASS,STRUCT,UNION
/* C++ operators, in increasing order of precedence */
%left COMMA
%right <val> ASSIGN,MUL_A,DIV_A,MOD_A,ADD_A,MINUS_A,SHL_A,SHR_A,BAND_A,BOR_A,XOR_A
%left ARITH_IF
%left LOG_OR
%left LOG_AND
%left BIN_OR
%left BIN_XOR
%left BIN_AND
%left EQUAL, NOT_EQUAL
%left LESS_THAN, LEQ, GREATER, GEQ
%left LSHIFT,RSHIFT
%left PLUS,MINUS
%left STAR,DIVIDE,MODULO
%left MEMBER_ARROW, MEMBER_DOT
%right NEW,DELETE,TYPECAST,DEREF,ADDR,UPLUS,UMINUS,LOG_NOT,BIN_NOT,INCR,DECR,SIZEOF
%left TYPE_CONSTRUCT,FUN_CALL,ARRAY,ARROW,DOT
%left BINARY_SCOPE
%right UNARY_SCOPE
%type <val> assign_op, poss_array
%type <ctype> tname_expr, tname_exp2, token, type_expr, type_expression,type_bracket,function_front
%type <ctype> typename_function, typename_class, typename_expr, template_class, template_expr, templ_item
%type <ctype> conversion_operator, class_parm, scope, pointer_expr
%type <val> poss_unsigned, poss_int,poss_const,typecast_type
%type <val> access_modifier,poss_access_modifier,class_or_struct,poss_derived, template_class_header, struct_or_class_x,
%type <val> class_or_struct_ex
%type <str> poss_tag, class_name, poss_class_name, class_id, class_item, template_class_name, token_or_typename
/* these should be 'expression'!! */
%type <expression> _expr,expr,poss_int_const,poss_initialization,poss_size,condition,poss_expr,brace_item
%type <expression> array_expr
%type <entry> scoped_name
%type <elist> expr_list,function_arg_list,poss_function_arg_list,init_list,brace_list, brace_expr
%type <classptr> this_classname
%type <typelist> template_type_list, templ_item_list
%%
program: statement_list ;
statement_list: /*empty*/
| statement {statement_end();}
| statement_list statement {statement_end();}
;
block:
'{' { state.init_block(PLAIN_BLOCK); IEF_set(); }
statement_list
'}' { state.finalize_block(); IEF_reset();}
;
statement: ';' /* empty statement */
| block
| declaration
| function_declaration
| function_definition
| friend_declaration
| expr ';' {expression_end($1);}
| typedef_stmt
| access_specifier
| if_stmt
| if_else_stmt
| while_stmt
| do_stmt
| for_stmt
| switch_stmt
| return_stmt
| case_label
| break_stmt
| continue_stmt
| goto_stmt
| goto_label
| template_class_declaration
| template_function_declaration
| try_catch_stmt
| throw_stmt
| namespace_declaration
| using_directive
| using_declaration
| extern_c_declaration
| error ';' { raise_error("Error in statement"); YYABORT; }
;
declaration:
mod_type_name tname_expr_list ';'
{
Type dt = tpop();
dcl_reset();
state.check_dcl_init(dt);
}
;
typedef_stmt:
TYPEDEF
{ state.in_typedef = true; }
declaration_stmt
{ state.in_typedef = false; }
;
declaration_stmt:
declaration
| function_declaration
;
/* constructor/destructors */
this_classname:
THIS_CLASSNAME
{
dcl_set();
state.token_stack.push($1->constructor_name());
tpush(t_void);
state.in_construct_destruct = IsConstructor;
$$ = $1;
}
;
construct_destruct:
this_classname {}
| BIN_NOT this_classname
{
state.token_stack.TOS() = $2->destructor_name();
state.in_construct_destruct = IsDestructor;
}
;
conversion_operator:
OPERATOR mod_type_name tname_exp2 arg_list
{
state.token_stack.push(CONVERSION_OPNAME);
ttpush($3); $$ = $3;
}
;
function_front:
mod_type_name tname_expr arg_list poss_const poss_initialization
{ $$=$2; stots($$); state.member_is_const = $4; gFunInit = $5; }
;
explicit_mod: EXPLICIT
{ state.modifier = Explicit; }
;
ctor_dtor_dcl:
construct_destruct arg_list ';'
{
state.declare_function(t_void,state.token_stack.pop());
tpop();
check_error();
}
;
function_declaration:
function_front ';'
{
state.declare_function(AsType($1),state.token_stack.pop(), gFunInit);
dcl_reset();
gFunInit = NULL;
tpop();
check_error();
}
| ctor_dtor_dcl
| explicit_mod ctor_dtor_dcl
| conversion_operator ';'
{
state.declare_function(AsType($1),state.token_stack.pop());
tpop();
check_error();
}
;
/***** extern "C" ******/
/* *fix 1.1.4
* - plain 'extern' is no longer confused with 'extern "C"'!
* - 'extern "C"' no longer has to be followed by a block
*/
extern_c_declaration:
extern_qualifier any_declaration { state.extern_flag = false; }
| extern_c '{' statement_list '}' { state.extern_flag_C = false; }
| extern_c any_declaration { state.extern_flag_C = false; }
;
any_declaration:
function_declaration
| declaration
;
extern_c:
EXTERN CONSTANT { state.extern_flag_C = true; }
;
extern_qualifier:
EXTERN { state.extern_flag = true; }
;
/***********************Function definitions ***/
function_definition:
function_front block
{ }
| ctor_dtor
{}
| explicit_mod ctor_dtor
{}
| conversion_operator block
{}
;
ctor_dtor:
construct_destruct arg_list poss_class_init_list block
;
/* w/ constructors and init lists, we construct the function first
(before the init list) and then initialize the function
*/
poss_class_init_list: /*EMPTY*/
| ':'
{ state.init_block(CONSTRUCTOR_BLOCK); }
class_init_list
{ check_error(); state.in_method = true; }
;
/*add 1.2.7 Fake syntax __init_list__ used to fool parser when grabbing init list + body */
class_init_list:
FAKE_INIT_LIST
| class_init_item
| class_init_item COMMA class_init_list
;
class_init_item:
typename_function function_arg_list
{
((Class*)state.context().parent_context())
->add_class_init_list(AsType($1).as_class()->entry(),$2);
/* fix 1.2.3a Can crash UC if we don't catch errors in the init list */
if (check_error()) YYABORT;
}
|
IDEN function_arg_list
{ ((Class*)state.context().parent_context())
->add_class_init_list($1,$2);
if (check_error()) YYABORT;
}
;
/***********************General type expressions***/
type_expr:
mod_type_name tname_expr
{ $$ = $2; }
;
poss_const: /*EMPTY*/ { $$=0; }
| CONST { $$=1; }
;
mod_type_name:
type_name {dcl_set();}
| modifiers type_name {dcl_set();}
| CONST type_name {dcl_set(); tots().make_const();}
| modifiers CONST type_name {dcl_set(); tots().make_const();}
;
modifiers:
STATIC {state.modifier = Static; }
| VIRTUAL {state.modifier = Virtual; }
| STDCALL {state.modifier = Stdcall; }
| API {state.modifier = Api; }
;
open_parens: '(' {dcl_set(false);}
;
close_parens: ')' {dcl_reset();}
;
type_name: typename_class { ttpush($1); }
| TYPEOF open_parens expr close_parens { tpush(typeof_op($3)); }
| integer { }
| UNSIGNED integer { tots().make_unsigned(); }
| UNSIGNED { tpush(t_int); tots().make_unsigned(); }
| FLOAT { tpush(t_float); }
| DOUBLE { tpush(t_double); }
| BOOL { tpush(t_bool); }
| VOID { tpush(t_void); }
| class_declaration { }
| enum_stmt { }
;
poss_unsigned: /*empty*/ { $$=0; }
| UNSIGNED { $$=1; }
;
poss_int: /*empty*/ { $$=0; }
| INT { $$=1; }
;
integer: INT { tpush(t_int); }
| SHORT { tpush(t_short); }
| LONG { tpush(t_long); }
/*
| SHORT INT { tpush(t_short); }
| LONG INT { tpush(t_long); }
*/
| CHAR { tpush(t_char); }
;
pointer_expr:
'(' STAR token ')' { $$ = incr_ptr($3); }
;
array_expr:
'[' {dcl_set(false);}
poss_int_const
']' %prec ARRAY { dcl_reset(); $$ = $3; }
;
tname_expr: /*empty*/ { $$=ttots(); state.token_stack.push(""); }
| token { $$=$1; }
| pointer_expr arg_list { Type t = AsType($1); t.decr_pointer(); $$ = AsTType(state.signature_type(t)); }
| '(' scope STAR token ')' end_scope arg_list
/* fix 1.2.3a Set the class type for this method ptr declaration first */
{ state.class_dcl = AsType($2); $$ = AsTType(state.signature_type(AsType($4))); }
| STAR poss_const tname_expr { $$ = incr_ptr($3); }
| ADDR tname_expr { $$ = make_ref($2); }
| scope token end_scope { $$ = $2; state.class_dcl = AsType($1); }
| scope conversion_operator
end_scope { $$ = $2; state.class_dcl = AsType($1); }
| tname_expr array_expr { $$ = make_array($1,$2); check_error(); }
| pointer_expr array_expr { $$ = make_array($1,$2); check_error(); }
| error { raise_error("Error in type expression"); YYABORT; }
;
/* conversion_operator requires special consideration! */
tname_exp2: /*empty*/ { $$ = ttots(); }
| STAR tname_exp2 { $$ = incr_ptr($2); }
| ADDR tname_exp2 { $$ = make_ref($2); }
;
token: TOKEN { $$=ttots(); state.token_stack.push($1); }
;
/**** Function prototype lists *******/
begin_list: '(' { dcl_set(false); state.begin_args(); }
;
end_list: ')' { dcl_reset(); }
;
arg_list:
begin_list type_list end_list /*%prec FUN_CALL */
;
type_list: /*empty*/
| type_expr_init
| type_expr_init ',' type_list
| THREEDOT
{
state.add_to_arg_list(t_void,"...",0);
}
;
type_expr_init:
type_expr poss_initialization
{
state.add_to_arg_list(AsType($1),state.token_stack.pop(),$2);
tpop();
dcl_reset();
}
;
/**** Declarative item ******/
init_tname_expr: tname_expr poss_initialization
{
string name = state.token_stack.pop();
Type t = AsType($1);
temp_context()->reserved_space(t.size());
state.add_variable(t,name,$2,state.modifier);
if (check_error()) YYABORT;
}
;
tname_expr_list: /*empty*/
| init_tname_expr
| init_tname_expr ',' tname_expr_list
;
poss_int_const: /*empty*/ { $$=NULL; }
| expr {$$=$1;}
/* Initializations occur in a declarative context, so it's
* important that they reset/set this state properly
*/
init_assign: ASSIGN { dcl_set(false); }
;
poss_initialization: /*empty*/ { $$=NULL; }
| init_assign
expr
{ dcl_reset(); $$=$2; }
| init_list
{ $$=expr_list_op($1,true); }
| init_assign '{' { enter_arglist();}
brace_list '}'
{leave_arglist(); dcl_reset(); $$=expr_list_op($4,false); }
| ':' CONSTANT
{ $$ = new Expr(ECONST,t_void,$2,NULL); }
;
/* ----array initialization------ */
brace_expr: '{' brace_list '}' { $$ = $2; }
;
brace_item: _expr { $$ = $1; }
| brace_expr { $$ = expr_list_op($1,false); }
;
brace_list: brace_item { $$ = new ExprList; $$->push_back($1); }
| brace_list ',' brace_item { $$ = $1; $$->push_back($3); }
;
/* brace_list: expr_list { $$=$1; }; simplified */
/****** CLASSES AND STRUCTS *******/
/* *change 1.1.4 this is now defined as a part of a declaration, as C intended */
access_modifier:
PUBLIC {$$=Public;}
| PRIVATE {$$=Private;}
| PROTECTED {$$=Protected;}
;
poss_access_modifier: /*EMPTY*/ { $$=Default; } | access_modifier
;
class_or_struct: CLASS | STRUCT | UNION
;
class_or_struct_ex: CLASS_Y { $$ = CLASS; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -