I believe Kalinash did something like this before but here is a stripped copy of the grammar.pre.y taken from fluffos 2.27. The semantic actions have been taken out.
/* This is to make emacs edit this in C mode: -*-C-*- */
%{
extern char *outp;
#include "std.h"
#include "compiler.h"
#include "lex.h"
#include "scratchpad.h"
#include "lpc_incl.h"
#include "simul_efun.h"
#include "generate.h"
#include "master.h"
/* gross. Necessary? - Beek */
#ifdef WIN32
#define MSDOS
#endif
#define YYSTACK_USE_ALLOCA 0
%line
/*
* This is the grammar definition of LPC, and its parse tree generator.
*/
/* down to one global :)
bits:
SWITCH_CONTEXT - we're inside a switch
LOOP_CONTEXT - we're inside a loop
SWITCH_STRINGS - a string case has been found
SWITCH_NUMBERS - a non-zero numeric case has been found
SWITCH_RANGES - a range has been found
SWITCH_DEFAULT - a default has been found
*/
int context;
int num_refs;
int func_present;
/*
* bison & yacc don't prototype this in y.tab.h
*/
int yyparse (void);
%}
/*
* Token definitions.
*
* Appearing in the precedence declarations are:
* '+' '-' '/' '*' '%'
* '&' '|' '<' '>' '^'
* '~' '?'
*
* Other single character tokens recognized in this grammar:
* '{' '}' ',' ';' ':'
* '(' ')' '[' ']' '$'
*/
%token L_STRING L_NUMBER L_REAL
%token L_BASIC_TYPE L_TYPE_MODIFIER
%token L_DEFINED_NAME L_IDENTIFIER
%token L_EFUN
%token L_INC L_DEC
%token L_ASSIGN
%token L_LAND L_LOR
%token L_LSH L_RSH
%token L_ORDER
%token L_NOT
%token L_IF L_ELSE
%token L_SWITCH L_CASE L_DEFAULT L_RANGE L_DOT_DOT_DOT
%token L_WHILE L_DO L_FOR L_FOREACH L_IN
%token L_BREAK L_CONTINUE
%token L_RETURN
%token L_ARROW L_INHERIT L_COLON_COLON
%token L_ARRAY_OPEN L_MAPPING_OPEN L_FUNCTION_OPEN L_NEW_FUNCTION_OPEN
%token L_SSCANF L_CATCH
%ifdef DEBUG
%token L_TREE
%endif
%ifdef ARRAY_RESERVED_WORD
%token L_ARRAY
%endif
%ifdef REF_RESERVED_WORD
%token L_REF
%endif
%token L_PARSE_COMMAND L_TIME_EXPRESSION
%token L_CLASS L_NEW
%token L_PARAMETER
%ifdef COMPAT_32
%token L_LAMBDA
%endif
/*
* 'Dangling else' shift/reduce conflict is well known...
* define these precedences to shut yacc up.
*/
%nonassoc LOWER_THAN_ELSE
%nonassoc L_ELSE
/*
* Operator precedence and associativity...
* greatly simplify the grammar.
*/
%right L_ASSIGN
%right '?'
%left L_LOR
%left L_LAND
%left '|'
%left '^'
%left '&'
%left L_EQ L_NE
%left L_ORDER '<'
%left L_LSH L_RSH
%left '+' '-'
%left '*' '%' '/'
%right L_NOT '~'
%nonassoc L_INC L_DEC
/*
* YYTYPE
*
* Anything with size > 4 is commented. Sizes assume typical 32 bit
* architecture. This size of the largest element of this union should
* be kept as small as possible to optimize copying of compiler stack
* elements.
*/
%union
{
POINTER_INT pointer_int;
LPC_INT number; /* 4 or 8 */
LPC_FLOAT real; /* 8 */
char *string;
struct { short num_arg; char flags; } argument;
ident_hash_elem_t *ihe;
parse_node_t *node;
function_context_t *contextp;
struct {
parse_node_t *node;
char num;
} decl; /* 5 */
struct {
char num_local;
char max_num_locals;
short context;
short save_current_type;
short save_exact_types;
} func_block; /* 8 */
}
/*
* Type declarations.
*/
/* These hold opcodes */
%type <number> efun_override L_ASSIGN L_ORDER
/* Holds a variable index */
%type <number> L_PARAMETER single_new_local_def
/* These hold arbitrary numbers */
%type <number> L_NUMBER
/* These hold numbers that are going to be stuffed into pointers :)
* Don't ask :)
*/
%type <pointer_int> constant
/* These hold a real number */
%type <real> L_REAL
/* holds a string constant */
%type <string> L_STRING string_con1 string_con2
/* Holds the number of elements in a list and whether it must be a prototype */
%type <argument> argument_list argument
/* These hold a list of possible interpretations of an identifier */
%type <ihe> L_DEFINED_NAME
/* These hold a type */
%type <number> type optional_star type_modifier_list
%type <number> opt_basic_type L_TYPE_MODIFIER L_BASIC_TYPE basic_type atomic_type
%type <number> cast arg_type
%ifdef ARRAY_RESERVED_WORD
%type <number> opt_atomic_type
%endif
/* This holds compressed and less flexible def_name information */
%type <number> L_NEW_FUNCTION_OPEN l_new_function_open
%ifdef COMPAT_32
%type <number> simple_function_pointer
%endif
/* holds an identifier or some sort */
%type <string> L_IDENTIFIER L_EFUN function_name identifier
%type <string> new_local_name
/* The following return a parse node */
%type <node> number real string expr0 comma_expr for_expr sscanf catch
%type <node> parse_command time_expression expr_list expr_list2 expr_list3
%type <node> expr_list4 assoc_pair expr4 lvalue function_call lvalue_list
%type <node> new_local_def statement while cond do switch case
%type <node> return optional_else_part block_or_semi
%type <node> case_label statements switch_block
%type <node> expr_list_node expr_or_block
%type <node> single_new_local_def_with_init
%type <node> class_init opt_class_init all def
%type <node> program modifier_change inheritance type_decl
%ifdef DEBUG
%type <node> tree
%endif
/* The following hold information about blocks and local vars */
%type <decl> local_declarations local_name_list block decl_block
%type <decl> foreach_var foreach_vars first_for_expr foreach for
/* This holds a flag */
%type <number> new_arg
%%
%pragma auto_note_compiler_case_start
all:
program
;
program:
program def possible_semi_colon
| /* empty */
;
possible_semi_colon:
/* empty */
| ';'
;
inheritance:
type_modifier_list L_INHERIT string_con1 ';'
;
real:
L_REAL
;
number:
L_NUMBER
;
optional_star:
/* empty */
| '*'
;
block_or_semi:
block
| ';'
| error
;
identifier:
L_DEFINED_NAME
| L_IDENTIFIER
;
def:
type optional_star identifier '(' argument ')' block_or_semi
| type name_list ';'
| inheritance
| type_decl
| modifier_change
;
modifier_change: type_modifier_list ':'
;
member_name:
optional_star identifier
;
member_name_list:
member_name
| member_name ',' member_name_list
;
member_list:
/* empty */
| member_list basic_type
member_name_list ';'
;
type_decl:
type_modifier_list L_CLASS identifier '{'
member_list '}'
;
new_local_name:
L_IDENTIFIER
| L_DEFINED_NAME
;
atomic_type:
L_BASIC_TYPE
| L_CLASS L_DEFINED_NAME
| L_CLASS L_IDENTIFIER
;
%ifdef ARRAY_RESERVED_WORD
opt_atomic_type:
atomic_type
| /* empty */
;
%endif
basic_type:
atomic_type
%ifdef ARRAY_RESERVED_WORD
| opt_atomic_type L_ARRAY
%endif
;
arg_type:
basic_type
%ifdef REF_RESERVED_WORD
| basic_type ref
%endif
;
new_arg:
arg_type optional_star
| arg_type optional_star new_local_name
| new_local_name
;
argument:
/* empty */
| argument_list
| argument_list L_DOT_DOT_DOT
;
argument_list:
new_arg
| argument_list ',' new_arg
;
type_modifier_list:
/* empty */
| L_TYPE_MODIFIER type_modifier_list
;
type:
type_modifier_list opt_basic_type
;
cast:
'(' basic_type optional_star ')'
;
opt_basic_type:
basic_type
| /* empty */
;
name_list:
new_name
| new_name ',' name_list
;
new_name:
optional_star identifier
| optional_star identifier L_ASSIGN expr0
;
block:
'{' local_declarations statements '}'
;
decl_block: block | for | foreach ;
local_declarations:
/* empty */
| local_declarations basic_type
local_name_list ';'
;
new_local_def:
optional_star new_local_name
| optional_star new_local_name L_ASSIGN expr0
;
single_new_local_def:
arg_type optional_star new_local_name
;
single_new_local_def_with_init:
single_new_local_def L_ASSIGN expr0
;
local_name_list:
new_local_def
| new_local_def ',' local_name_list
;
statements:
/* empty */
| statement statements
| error ';'
;
statement:
comma_expr ';'
| cond
| while
| do
| switch
| return
| decl_block
| /* empty */ ';'
| L_BREAK ';'
| L_CONTINUE ';'
;
while:
L_WHILE '(' comma_expr ')'
statement
;
do:
L_DO
statement L_WHILE '(' comma_expr ')' ';'
;
for:
L_FOR '(' first_for_expr ';' for_expr ';' for_expr ')'
;
foreach_var: L_DEFINED_NAME
| single_new_local_def
| L_IDENTIFIER
;
foreach_vars:
foreach_var
| foreach_var ',' foreach_var
;
foreach:
L_FOREACH '(' foreach_vars L_IN expr0 ')'
statement
;
for_expr:
/* EMPTY */
| comma_expr
;
first_for_expr:
for_expr
| single_new_local_def_with_init
;
switch:
L_SWITCH '(' comma_expr ')'
'{' local_declarations case switch_block '}'
;
switch_block:
case switch_block
| statement switch_block
| /* empty */
;
case:
L_CASE case_label ':'
| L_CASE case_label L_RANGE case_label ':'
| L_CASE case_label L_RANGE ':'
| L_CASE L_RANGE case_label ':'
| L_DEFAULT ':'
;
case_label:
constant
| string_con1
;
constant:
constant '|' constant
| constant '^' constant
| constant '&' constant
| constant L_EQ constant
| constant L_NE constant
| constant L_ORDER constant
| constant '<' constant
| constant L_LSH constant
| constant L_RSH constant
| constant '+' constant
| constant '-' constant
| constant '*' constant
| constant '%' constant
| constant '/' constant
| '(' constant ')'
| L_NUMBER
| '-' L_NUMBER
| L_NOT L_NUMBER
| '~' L_NUMBER
;
comma_expr:
expr0
| comma_expr ',' expr0
;
%ifdef REF_RESERVED_WORD
ref:
L_REF
%ifdef COMPAT_32
| '&'
%endif
;
%endif
expr0:
%ifdef REF_RESERVED_WORD
ref lvalue
|
%endif
lvalue L_ASSIGN expr0
| error L_ASSIGN expr0
| expr0 '?' expr0 ':' expr0 %prec '?'
| expr0 L_LOR expr0
| expr0 L_LAND expr0
| expr0 '|' expr0
| expr0 '^' expr0
| expr0 '&' expr0
| expr0 L_EQ expr0
| expr0 L_NE expr0
| expr0 L_ORDER expr0
| expr0 '<' expr0
| expr0 L_LSH expr0
| expr0 L_RSH expr0
| expr0 '+' expr0
| expr0 '-' expr0
| expr0 '*' expr0
| expr0 '%' expr0
| expr0 '/' expr0
| cast expr0 %prec L_NOT
| L_INC lvalue %prec L_NOT /* note lower precedence here */
| L_DEC lvalue %prec L_NOT /* note lower precedence here */
| L_NOT expr0
| '~' expr0
| '-' expr0 %prec L_NOT
| lvalue L_INC /* normal precedence here */
| lvalue L_DEC
| expr4
| sscanf
| parse_command
| time_expression
| number
| real
;
return:
L_RETURN ';'
| L_RETURN comma_expr ';'
;
expr_list:
/* empty */
| expr_list2
| expr_list2 ','
;
expr_list_node:
expr0
| expr0 L_DOT_DOT_DOT
;
expr_list2:
expr_list_node
| expr_list2 ',' expr_list_node
;
expr_list3:
/* empty */
| expr_list4
| expr_list4 ','
;
expr_list4:
assoc_pair
| expr_list4 ',' assoc_pair
;
assoc_pair:
expr0 ':' expr0
;
lvalue:
expr4
;
l_new_function_open: L_NEW_FUNCTION_OPEN
| L_FUNCTION_OPEN efun_override
;
%ifdef COMPAT_32
simple_function_pointer: l_new_function_open ':' ')'
| L_LAMBDA L_DEFINED_NAME
;
%endif
expr4:
function_call
| L_DEFINED_NAME
| L_IDENTIFIER
| L_PARAMETER
| '$' '('
| expr4 L_ARROW identifier
| expr4 '[' comma_expr L_RANGE comma_expr ']'
| expr4 '[' '<' comma_expr L_RANGE comma_expr ']'
| expr4 '[' '<' comma_expr L_RANGE '<' comma_expr ']'
| expr4 '[' comma_expr L_RANGE '<' comma_expr ']'
| expr4 '[' comma_expr L_RANGE ']'
| expr4 '[' '<' comma_expr L_RANGE ']'
| expr4 '[' '<' comma_expr ']'
| expr4 '[' comma_expr ']'
| string
| '(' comma_expr ')'
| catch
%ifdef DEBUG
| tree
%endif
| L_BASIC_TYPE
%ifdef COMPAT_32
| simple_function_pointer
%else
| l_new_function_open ':' ')'
%endif
| l_new_function_open ',' expr_list2 ':' ')'
| L_FUNCTION_OPEN comma_expr ':' ')'
| L_MAPPING_OPEN expr_list3 ']' ')'
| L_ARRAY_OPEN expr_list '}' ')'
;
expr_or_block:
block
| '(' comma_expr ')'
;
catch:
L_CATCH
expr_or_block
;
%ifdef DEBUG
tree:
L_TREE block
|
L_TREE '(' comma_expr ')'
;
%endif
sscanf:
L_SSCANF '(' expr0 ',' expr0 lvalue_list ')'
;
parse_command:
L_PARSE_COMMAND '(' expr0 ',' expr0 ',' expr0 lvalue_list ')'
;
time_expression:
L_TIME_EXPRESSION
expr_or_block
;
lvalue_list:
/* empty */
| ',' lvalue lvalue_list
;
string:
string_con2
;
string_con1:
string_con2
| '(' string_con1 ')'
| string_con1 '+' string_con1
;
string_con2:
L_STRING
| string_con2 L_STRING
;
class_init: identifier ':' expr0
;
opt_class_init:
/* empty */
| opt_class_init ',' class_init
;
function_call:
efun_override '('
| L_NEW '('
| L_NEW '(' L_CLASS L_DEFINED_NAME opt_class_init ')'
| L_NEW '(' L_CLASS L_IDENTIFIER opt_class_init ')'
| L_DEFINED_NAME '(' expr_list ')'
| function_name '(' expr_list ')'
| expr4 L_ARROW identifier '(' expr_list ')'
| '(' '*' comma_expr ')' '(' expr_list ')'
;
efun_override: L_EFUN L_COLON_COLON identifier
| L_EFUN L_COLON_COLON L_NEW
;
function_name:
L_IDENTIFIER
| L_COLON_COLON identifier
| L_BASIC_TYPE L_COLON_COLON identifier
| identifier L_COLON_COLON identifier
;
cond:
L_IF '(' comma_expr ')' statement optional_else_part
;
optional_else_part:
/* empty */ %prec LOWER_THAN_ELSE
| L_ELSE statement
;
%%
%line