aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/LuaSL/src/LuaSL_lemon_yaccer.y
blob: 42b02c7c921b8b99989de9b4fb6cc396ad84a8aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
%include {
#include "LuaSL.h"
}

%extra_argument {LuaSL_compiler *compiler}

%stack_size 1024

%token_type {LSL_Leaf *}
%default_type  {LSL_Leaf *}
%token_destructor {burnLeaf($$);}
%default_destructor {burnLeaf($$);}

// The start symbol, just coz we need one.

// Lemon does not like the start symbol to be on the RHS, so give it a dummy start symbol.
program ::= script LSL_SCRIPT(A).						{ if (NULL != A) A->left = compiler->ast;  compiler->ast = A; }

// Various forms of "space".  The lexer takes care of them for us.

%nonassoc LSL_SPACE LSL_COMMENT LSL_COMMENT_LINE LSL_UNKNOWN.

// Basic script structure.

%nonassoc LSL_SCRIPT.
script ::= script state(A).							{ if (NULL != A) A->left = compiler->ast;  compiler->ast = A; }
script ::= script functionBody(A).						{ if (NULL != A) A->left = compiler->ast;  compiler->ast = A; }
script ::= script statement(A).							{ if (NULL != A) A->left = compiler->ast;  compiler->ast = A; }
script ::= .

// State definitions.

%nonassoc LSL_BLOCK_OPEN LSL_BLOCK_CLOSE LSL_STATE.
stateBlock(A) ::= LSL_BLOCK_OPEN functionList(B) LSL_BLOCK_CLOSE.		{ A = B; }
state(S) ::= LSL_DEFAULT(I) stateBlock(B).					{ S = addState(compiler, I, B); }
state(S) ::= LSL_STATE_CHANGE LSL_IDENTIFIER(I) stateBlock(B).			{ S = addState(compiler, I, B); }

// Function definitions.

%nonassoc LSL_PARAMETER LSL_PARAMETER_LIST LSL_FUNCTION.
functionList(A) ::= functionList(B) functionBody(C).				{ A = collectStatements(compiler, B, C); }
//functionList(A) ::= functionBody(C).						{ A = collectStatements(compiler, NULL, C); }
functionList(A) ::= .								{ A = collectStatements(compiler, NULL, NULL); }

functionBody(A) ::= function(B) funcBlock(C).					{ A = addFunctionBody(compiler, B, C); }

parameterList(A) ::= parameterList(B) LSL_COMMA(C) parameter(D).		{ A = collectParameters(compiler, B, C, D); }
parameterList(A) ::= parameter(D).						{ A = collectParameters(compiler, NULL, NULL, D); }
parameterList(A) ::= .								{ A = collectParameters(compiler, NULL, NULL, NULL); }
parameter(A) ::= type(B) LSL_IDENTIFIER(C).					{ A = addParameter(compiler, B, C); }
// Causes a conflict when it's an empty parameterList with calling the same type of function.
function(A) ::= LSL_IDENTIFIER(C) LSL_PARENTHESIS_OPEN(D) parameterList(E) LSL_PARENTHESIS_CLOSE(F).		{ A = addFunction(compiler, NULL, C, D, E, F); }
function(A) ::= type(B) LSL_IDENTIFIER(C) LSL_PARENTHESIS_OPEN(D) parameterList(E) LSL_PARENTHESIS_CLOSE(F).	{ A = addFunction(compiler, B, C, D, E, F); }

// Blocks.

block(A) ::= funcBlock(B).							{ A = B; }
block(A) ::= statement(B).							{ A = B; }
funcBlock(A) ::= LSL_BLOCK_OPEN statementList(B) LSL_BLOCK_CLOSE.		{ A = B; }

// Various forms of statement.

%nonassoc LSL_STATEMENT.
statementList(A) ::= statementList(B) statement(C).				{ A = collectStatements(compiler, B, C); }
//statementList(A) ::= statement(C).						{ A = collectStatements(compiler, NULL, C); }
statementList(A) ::= .								{ A = collectStatements(compiler, NULL, NULL); }

%nonassoc LSL_DO LSL_FOR LSL_ELSE_IF LSL_IF LSL_JUMP LSL_RETURN LSL_STATE_CHANGE LSL_WHILE.
%nonassoc LSL_ELSE.
statement ::= LSL_DO block LSL_WHILE LSL_PARENTHESIS_OPEN expr LSL_PARENTHESIS_CLOSE LSL_STATEMENT.
statement ::= LSL_FOR LSL_PARENTHESIS_OPEN expr LSL_STATEMENT expr LSL_STATEMENT expr LSL_PARENTHESIS_CLOSE block.

ifBlock ::= ifBlock LSL_ELSE block.
ifBlock ::= block.
// The [LSL_ELSE] part causes a conflict.
statement ::= LSL_IF LSL_PARENTHESIS_OPEN expr LSL_PARENTHESIS_CLOSE ifBlock.	[LSL_ELSE]

statement ::= LSL_JUMP LSL_IDENTIFIER LSL_STATEMENT.
statement ::= LSL_RETURN expr LSL_STATEMENT.
statement ::= LSL_RETURN LSL_STATEMENT.
statement ::= LSL_STATE_CHANGE LSL_DEFAULT LSL_STATEMENT.
statement ::= LSL_STATE_CHANGE LSL_IDENTIFIER LSL_STATEMENT.
statement ::= LSL_WHILE LSL_PARENTHESIS_OPEN expr LSL_PARENTHESIS_CLOSE block.

%nonassoc LSL_LABEL.
statement ::= LSL_LABEL LSL_IDENTIFIER LSL_STATEMENT.

// This might be bogus, or might be valid LSL, but it let us test the expression parser by evaluating them.
statement(A) ::= expr(B) LSL_STATEMENT(D).					{ A = addStatement(D, LSL_EXPRESSION, B); }

// Various forms of expression.

// Used for function call params, and list contents.
exprList ::= exprList LSL_COMMA expr.
exprList ::= expr.
exprList ::= .

%right  LSL_BOOL_AND.
expr(A) ::= expr(B) LSL_BOOL_AND(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }
%right  LSL_BOOL_OR.
expr(A) ::= expr(B) LSL_BOOL_OR(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }

%left  LSL_BIT_AND LSL_BIT_XOR LSL_BIT_OR.
expr(A) ::= expr(B) LSL_BIT_OR(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }
expr(A) ::= expr(B) LSL_BIT_XOR(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }
expr(A) ::= expr(B) LSL_BIT_AND(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }

%right  LSL_EQUAL LSL_NOT_EQUAL.
expr(A) ::= expr(B) LSL_NOT_EQUAL(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }
expr(A) ::= expr(B) LSL_EQUAL(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }
%right  LSL_LESS_THAN LSL_GREATER_THAN LSL_LESS_EQUAL LSL_GREATER_EQUAL.
expr(A) ::= expr(B) LSL_GREATER_EQUAL(C)	expr(D).			{ A = addOperation(compiler, B, C, D); }
expr(A) ::= expr(B) LSL_LESS_EQUAL(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }
expr(A) ::= expr(B) LSL_GREATER_THAN(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }
expr(A) ::= expr(B) LSL_LESS_THAN(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }

%left  LSL_LEFT_SHIFT LSL_RIGHT_SHIFT.
expr(A) ::= expr(B) LSL_RIGHT_SHIFT(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }
expr(A) ::= expr(B) LSL_LEFT_SHIFT(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }

%left  LSL_SUBTRACT LSL_ADD LSL_CONCATENATE.
expr(A) ::= expr(B) LSL_ADD(C)			expr(D).			{ A = addOperation(compiler, B, C, D); }
expr(A) ::= expr(B) LSL_SUBTRACT(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }
%left  LSL_DIVIDE LSL_MODULO LSL_MULTIPLY LSL_DOT_PRODUCT LSL_CROSS_PRODUCT.
expr(A) ::= expr(B) LSL_MULTIPLY(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }
expr(A) ::= expr(B) LSL_MODULO(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }
expr(A) ::= expr(B) LSL_DIVIDE(C)		expr(D).			{ A = addOperation(compiler, B, C, D); }

%right LSL_BIT_NOT LSL_BOOL_NOT LSL_NEGATION.
expr(A) ::= LSL_BIT_NOT(B)			expr(C).			{ A = addOperation(compiler, NULL, B, C); }
expr(A) ::= LSL_BOOL_NOT(B)			expr(C).			{ A = addOperation(compiler, NULL, B, C); }
expr(A) ::= LSL_SUBTRACT(B)			expr(C).	[LSL_NEGATION]	{ A = addOperation(compiler, NULL, B, C); }

// Types, typecasts, and expression reordering.

%right  LSL_TYPECAST_OPEN LSL_TYPECAST_CLOSE.
%nonassoc LSL_TYPE_FLOAT LSL_TYPE_INTEGER LSL_TYPE_KEY LSL_TYPE_LIST LSL_TYPE_ROTATION LSL_TYPE_STRING LSL_TYPE_VECTOR.
type(A) ::= LSL_TYPE_FLOAT(B).							{ B->basicType = OT_float;	A = B; }
type(A) ::= LSL_TYPE_INTEGER(B).						{ B->basicType = OT_integer;	A = B; }
type(A) ::= LSL_TYPE_KEY(B).							{ B->basicType = OT_key;	A = B; }
type(A) ::= LSL_TYPE_LIST(B).							{ B->basicType = OT_list;	A = B; }
type(A) ::= LSL_TYPE_ROTATION(B).						{ B->basicType = OT_rotation;	A = B; }
type(A) ::= LSL_TYPE_STRING(B).							{ B->basicType = OT_string;	A = B; }
type(A) ::= LSL_TYPE_VECTOR(B).							{ B->basicType = OT_vector;	A = B; }

%left  LSL_ANGLE_OPEN LSL_ANGLE_CLOSE.
%nonassoc LSL_BRACKET_OPEN LSL_BRACKET_CLOSE.
%nonassoc LSL_PARENTHESIS_OPEN LSL_PARENTHESIS_CLOSE LSL_EXPRESSION.

expr(A) ::= LSL_PARENTHESIS_OPEN(B)	expr(C) LSL_PARENTHESIS_CLOSE(D).		{ A = addParenthesis(B, C, LSL_EXPRESSION, D); }
expr(A) ::= LSL_PARENTHESIS_OPEN(B)	type(C)	LSL_PARENTHESIS_CLOSE(D) expr(E).	{ A = addTypecast(B, C, D, E); }

// Function call.

// Causes a conflict when exprList is empty with a function definition with no type and no parameters.
expr(A) ::= LSL_IDENTIFIER(B) LSL_PARENTHESIS_OPEN(C) exprList(D) LSL_PARENTHESIS_CLOSE(E).	{ A = addFunctionCall(compiler, B, C, D, E); }

// Variables and dealing with them.

expr(A) ::= identifier(B).							{ A = B; }

%right LSL_ASSIGNMENT_CONCATENATE LSL_ASSIGNMENT_ADD LSL_ASSIGNMENT_SUBTRACT LSL_ASSIGNMENT_MULTIPLY LSL_ASSIGNMENT_MODULO LSL_ASSIGNMENT_DIVIDE LSL_ASSIGNMENT_PLAIN.
// Yes, these can be expressions, and can happen in if statements and such.
expr(A) ::= identifier(B) LSL_ASSIGNMENT_CONCATENATE(C)	expr(D).		{ A = addOperation(compiler, B, C, D); }
expr(A) ::= identifier(B) LSL_ASSIGNMENT_ADD(C)		expr(D).		{ A = addOperation(compiler, B, C, D); }
expr(A) ::= identifier(B) LSL_ASSIGNMENT_SUBTRACT(C)	expr(D)	.		{ A = addOperation(compiler, B, C, D); }
expr(A) ::= identifier(B) LSL_ASSIGNMENT_MULTIPLY(C)	expr(D).		{ A = addOperation(compiler, B, C, D); }
expr(A) ::= identifier(B) LSL_ASSIGNMENT_MODULO(C)	expr(D).		{ A = addOperation(compiler, B, C, D); }
expr(A) ::= identifier(B) LSL_ASSIGNMENT_DIVIDE(C)	expr(D).		{ A = addOperation(compiler, B, C, D); }
expr(A) ::= identifier(B) LSL_ASSIGNMENT_PLAIN(C)	expr(D).		{ A = addOperation(compiler, B, C, D); }

// Hmm think this can have commas seperating the assignment parts, or is that only in C?.  If so, best to separate them when converting to Lua, as it uses that syntax for something else.
// Well, not in OpenSim at least, nor in SL.  So we are safe.  B-)
statement(A) ::= type(B) LSL_IDENTIFIER(C) LSL_ASSIGNMENT_PLAIN(D) expr(E) LSL_STATEMENT(F).	{ A = addStatement(F, LSL_IDENTIFIER, addVariable(compiler, B, C, D, E)); }
statement(A) ::= type(B) LSL_IDENTIFIER(C) LSL_STATEMENT(F).					{ A = addStatement(F, LSL_IDENTIFIER, addVariable(compiler, B, C, NULL, NULL)); }

%right LSL_DOT LSL_IDENTIFIER LSL_FUNCTION_CALL.
identifier(A) ::= identifier LSL_DOT LSL_IDENTIFIER(B).					{ A = checkVariable(compiler, B); A->basicType = OT_float; }	// Just a stub to get it to work for now.
identifier(A) ::= LSL_IDENTIFIER(B).							{ A = checkVariable(compiler, B); }

%right LSL_DECREMENT_PRE LSL_INCREMENT_PRE LSL_DECREMENT_POST LSL_INCREMENT_POST.
expr(A) ::= identifier(B) LSL_DECREMENT_PRE(C).						{ A = addCrement(compiler, B, C); }
expr(A) ::= identifier(B) LSL_INCREMENT_PRE(C).						{ A = addCrement(compiler, B, C); }
expr(A) ::= LSL_DECREMENT_PRE(C) identifier(B).						{ A = addCrement(compiler, B, C); }
expr(A) ::= LSL_INCREMENT_PRE(C) identifier(B).						{ A = addCrement(compiler, B, C); }

%nonassoc LSL_COMMA.

// Values.

%nonassoc  LSL_FLOAT.
expr(A) ::= LSL_FLOAT(B).							{ B->basicType = OT_float; A = B; }
%nonassoc LSL_INTEGER.
expr(A) ::= LSL_INTEGER(B).							{ B->basicType = OT_integer; A = B; }
%nonassoc  LSL_KEY.
expr(A) ::= LSL_KEY(B).								{ B->basicType = OT_key; A = B; }
%nonassoc  LSL_LIST.
expr(A) ::= LSL_BRACKET_OPEN(B) exprList LSL_BRACKET_CLOSE.	[LSL_BRACKET_OPEN]	{ B->basicType = OT_list; A = B; }	// Probably need a specific addList().
%nonassoc  LSL_ROTATION.
// Uses the same symbol for less than, greater than, and the rotation / vector delimiters.
expr ::= LSL_LESS_THAN expr LSL_COMMA expr LSL_COMMA expr LSL_COMMA expr LSL_GREATER_THAN.	[LSL_ANGLE_OPEN]
%nonassoc  LSL_STRING.
expr(A) ::= LSL_STRING(B).							{ B->basicType = OT_string; A = B; }
%nonassoc  LSL_VECTOR.
expr ::= LSL_VECTOR.
expr ::= LSL_LESS_THAN expr LSL_COMMA expr LSL_COMMA expr LSL_GREATER_THAN.			[LSL_ANGLE_OPEN]


// Parser callbacks.

%parse_accept
{
//    gameGlobals *game = compiler->game;

//    PI("Parsing complete.");
}

%parse_failure
{
    gameGlobals *game = compiler->game;

    PE("Giving up.  Parser is hopelessly lost!");
}

%stack_overflow
{
    gameGlobals *game = compiler->game;

    PE("Giving up.  Parser stack overflow @ line %d, column %d!", yypMinor->yy0->line, yypMinor->yy0->column);  // Gotta love consistancy, if it ever happens.
}

%syntax_error
{
    gameGlobals *game = compiler->game;

    PE("Syntax error @ line %d, column %d!", yyminor.yy0->line, yyminor.yy0->column);
}


/* Undocumented shit that might be useful later.  Pffft

** The next table maps tokens into fallback tokens.  If a construct
** like the following:
**.
**      %fallback ID X Y Z.
**
** appears in the grammar, then ID becomes a fallback token for X, Y,
** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
** but it does not parse, the type of the token is changed to ID and
** the parse is retried before an error is thrown.

%wildcard
%code

%ifdef
%endif
%ifndef
%endif

*/