/[svn]/linuxsampler/trunk/src/scriptvm/parser.y
ViewVC logotype

Annotation of /linuxsampler/trunk/src/scriptvm/parser.y

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3573 - (hide annotations) (download)
Tue Aug 27 21:36:53 2019 UTC (4 years, 8 months ago) by schoenebeck
File size: 61253 byte(s)
NKSP: Introducing floating point support.

* NKSP language: Added support for NKSP real number literals and
  arithmetic operations on them (e.g. "(3.9 + 2.9) / 12.3 - 42.0").

* NKSP language: Added support for NKSP real number (floating point)
  script variables (declare ~foo := 3.4).

* NKSP language: Added support for NKSP real number (floating point)
  array script variables (declare ?foo[3] := ( 1.1, 2.7, 49.0 )).

* NKSP built-in script function "message()" accepts now real number
  argument as well.

* Added built-in NKSP script function "real_to_int()" and its short
  hand form "int()" for casting from real number to integer in NKSP
  scripts.

* Added built-in NKSP script function "int_to_real()" and its short
  hand form "real()" for casting from integer to real number in NKSP
  scripts.

* Bumped version (2.1.1.svn6).

1 schoenebeck 2581 /*
2 schoenebeck 3253 * Copyright (c) 2014-2017 Christian Schoenebeck and Andreas Persson
3 schoenebeck 2581 *
4     * http://www.linuxsampler.org
5     *
6     * This file is part of LinuxSampler and released under the same terms.
7     * See README file for details.
8     */
9 schoenebeck 2888
10     /* Parser for NKSP real-time instrument script language. */
11 schoenebeck 2581
12     %{
13     #define YYERROR_VERBOSE 1
14     #include "parser_shared.h"
15     #include <string>
16     #include <map>
17     using namespace LinuxSampler;
18    
19     void InstrScript_error(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* err);
20     void InstrScript_warning(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* txt);
21 schoenebeck 3008 int InstrScript_tnamerr(char* yyres, const char* yystr);
22 schoenebeck 2581 int InstrScript_lex(YYSTYPE* lvalp, YYLTYPE* llocp, void* scanner);
23     #define scanner context->scanner
24 schoenebeck 2888 #define PARSE_ERR(loc,txt) yyerror(&loc, context, txt)
25     #define PARSE_WRN(loc,txt) InstrScript_warning(&loc, context, txt)
26 schoenebeck 3311 #define PARSE_DROP(loc) context->addPreprocessorComment(loc.first_line, loc.last_line, loc.first_column+1, loc.last_column+1);
27 schoenebeck 3008 #define yytnamerr(res,str) InstrScript_tnamerr(res, str)
28 schoenebeck 2581 %}
29    
30     // generate reentrant safe parser
31     %pure-parser
32     %parse-param { LinuxSampler::ParserContext* context }
33     %lex-param { void* scanner }
34     // avoid symbol collision with other (i.e. future) auto generated (f)lex scanners
35 schoenebeck 3052 // (NOTE: "=" is deprecated here with Bison 3.x, however removing it would cause an error with Bison 2.x)
36     %name-prefix="InstrScript_"
37 schoenebeck 2581 %locations
38     %defines
39     %error-verbose
40    
41 schoenebeck 3008 %token <iValue> INTEGER "integer literal"
42 schoenebeck 3573 %token <fValue> REAL "real number literal"
43 schoenebeck 3561 %token <iUnitValue> INTEGER_UNIT "integer literal with unit"
44 schoenebeck 3573 %token <fUnitValue> REAL_UNIT "real number literal with unit"
45 schoenebeck 3008 %token <sValue> STRING "string literal"
46     %token <sValue> IDENTIFIER "function name"
47     %token <sValue> VARIABLE "variable name"
48     %token ON "keyword 'on'"
49     %token END "keyword 'end'"
50     %token INIT "keyword 'init'"
51     %token NOTE "keyword 'note'"
52     %token RELEASE "keyword 'release'"
53     %token CONTROLLER "keyword 'controller'"
54     %token DECLARE "keyword 'declare'"
55     %token ASSIGNMENT "operator ':='"
56     %token CONST_ "keyword 'const'"
57     %token POLYPHONIC "keyword 'polyphonic'"
58     %token WHILE "keyword 'while'"
59 schoenebeck 3260 %token SYNCHRONIZED "keyword 'synchronized'"
60 schoenebeck 3008 %token IF "keyword 'if'"
61     %token ELSE "keyword 'else'"
62     %token SELECT "keyword 'select'"
63     %token CASE "keyword 'case'"
64     %token TO "keyword 'to'"
65     %token OR "operator 'or'"
66     %token AND "operator 'and'"
67     %token NOT "operator 'not'"
68     %token BITWISE_OR "bitwise operator '.or.'"
69     %token BITWISE_AND "bitwise operator '.and.'"
70     %token BITWISE_NOT "bitwise operator '.not.'"
71     %token FUNCTION "keyword 'function'"
72     %token CALL "keyword 'call'"
73     %token MOD "operator 'mod'"
74     %token LE "operator '<='"
75     %token GE "operator '>='"
76     %token END_OF_FILE 0 "end of file"
77 schoenebeck 3259 %token UNKNOWN_CHAR "unknown character"
78 schoenebeck 2581
79 schoenebeck 2951 %type <nEventHandlers> script sections
80     %type <nEventHandler> section eventhandler
81     %type <nStatements> statements opt_statements userfunctioncall
82 schoenebeck 2581 %type <nStatement> statement assignment
83     %type <nFunctionCall> functioncall
84     %type <nArgs> args
85 schoenebeck 2935 %type <nExpression> arg expr logical_or_expr logical_and_expr bitwise_or_expr bitwise_and_expr rel_expr add_expr mul_expr unary_expr concat_expr
86 schoenebeck 2581 %type <nCaseBranch> caseclause
87     %type <nCaseBranches> caseclauses
88    
89     %start script
90    
91     %%
92    
93     script:
94 schoenebeck 2951 sections {
95 schoenebeck 2581 $$ = context->handlers = $1;
96     }
97    
98 schoenebeck 2951 sections:
99     section {
100 schoenebeck 2581 $$ = new EventHandlers();
101 schoenebeck 2951 if ($1) $$->add($1);
102 schoenebeck 2581 }
103 schoenebeck 2951 | sections section {
104 schoenebeck 2581 $$ = $1;
105 schoenebeck 2951 if ($2) $$->add($2);
106 schoenebeck 2581 }
107    
108 schoenebeck 2951 section:
109     function_declaration {
110     $$ = EventHandlerRef();
111     }
112     | eventhandler {
113     $$ = $1;
114     }
115    
116 schoenebeck 2581 eventhandler:
117 schoenebeck 2947 ON NOTE opt_statements END ON {
118 schoenebeck 2581 if (context->onNote)
119 schoenebeck 2888 PARSE_ERR(@2, "Redeclaration of 'note' event handler.");
120 schoenebeck 2581 context->onNote = new OnNote($3);
121     $$ = context->onNote;
122     }
123 schoenebeck 2947 | ON INIT opt_statements END ON {
124 schoenebeck 2581 if (context->onInit)
125 schoenebeck 2888 PARSE_ERR(@2, "Redeclaration of 'init' event handler.");
126 schoenebeck 2581 context->onInit = new OnInit($3);
127     $$ = context->onInit;
128     }
129 schoenebeck 2947 | ON RELEASE opt_statements END ON {
130 schoenebeck 2581 if (context->onRelease)
131 schoenebeck 2888 PARSE_ERR(@2, "Redeclaration of 'release' event handler.");
132 schoenebeck 2581 context->onRelease = new OnRelease($3);
133     $$ = context->onRelease;
134     }
135 schoenebeck 2947 | ON CONTROLLER opt_statements END ON {
136 schoenebeck 2581 if (context->onController)
137 schoenebeck 2888 PARSE_ERR(@2, "Redeclaration of 'controller' event handler.");
138 schoenebeck 2581 context->onController = new OnController($3);
139     $$ = context->onController;
140     }
141    
142 schoenebeck 2951 function_declaration:
143     FUNCTION IDENTIFIER opt_statements END FUNCTION {
144     const char* name = $2;
145     if (context->functionProvider->functionByName(name)) {
146     PARSE_ERR(@2, (String("There is already a built-in function with name '") + name + "'.").c_str());
147     } else if (context->userFunctionByName(name)) {
148     PARSE_ERR(@2, (String("There is already a user defined function with name '") + name + "'.").c_str());
149     } else {
150     context->userFnTable[name] = $3;
151     }
152     }
153    
154 schoenebeck 2947 opt_statements:
155 schoenebeck 2911 /* epsilon (empty argument) */ {
156     $$ = new Statements();
157     }
158     | statements {
159     $$ = $1;
160     }
161    
162 schoenebeck 2581 statements:
163     statement {
164     $$ = new Statements();
165     if ($1) {
166     if (!isNoOperation($1)) $$->add($1); // filter out NoOperation statements
167     } else
168 schoenebeck 2888 PARSE_WRN(@1, "Not a statement.");
169 schoenebeck 2581 }
170     | statements statement {
171     $$ = $1;
172     if ($2) {
173     if (!isNoOperation($2)) $$->add($2); // filter out NoOperation statements
174     } else
175 schoenebeck 2888 PARSE_WRN(@2, "Not a statement.");
176 schoenebeck 2581 }
177    
178     statement:
179     functioncall {
180     $$ = $1;
181     }
182 schoenebeck 2951 | userfunctioncall {
183     $$ = $1;
184     }
185 schoenebeck 2581 | DECLARE VARIABLE {
186     const char* name = $2;
187     //printf("declared var '%s'\n", name);
188 schoenebeck 3573 if (context->variableByName(name)) {
189 schoenebeck 2888 PARSE_ERR(@2, (String("Redeclaration of variable '") + name + "'.").c_str());
190 schoenebeck 3573 } else if (name[0] == '@') {
191 schoenebeck 2581 context->vartable[name] = new StringVariable(context);
192 schoenebeck 3573 } else if (name[0] == '~') {
193     context->vartable[name] = new RealVariable(context);
194     } else if (name[0] == '$') {
195     context->vartable[name] = new IntVariable(context);
196     } else if (name[0] == '?') {
197     PARSE_ERR(@2, (String("Real number array variable '") + name + "' declaration requires array size.").c_str());
198     } else if (name[0] == '%') {
199     PARSE_ERR(@2, (String("Integer array variable '") + name + "' declaration requires array size.").c_str());
200 schoenebeck 2581 } else {
201 schoenebeck 3573 PARSE_ERR(@2, (String("Variable '") + name + "' declared with unknown type.").c_str());
202 schoenebeck 2581 }
203 schoenebeck 3573 $$ = new NoOperation;
204 schoenebeck 2581 }
205     | DECLARE POLYPHONIC VARIABLE {
206     const char* name = $3;
207     //printf("declared polyphonic var '%s'\n", name);
208 schoenebeck 3573 if (context->variableByName(name)) {
209 schoenebeck 2888 PARSE_ERR(@3, (String("Redeclaration of variable '") + name + "'.").c_str());
210 schoenebeck 3573 } else if (name[0] != '$' && name[0] != '~') {
211     PARSE_ERR(@3, "Polyphonic variables must only be declared either as integer or real number type.");
212     } else if (name[0] == '~') {
213     context->vartable[name] = new PolyphonicRealVariable(context);
214 schoenebeck 2581 } else {
215     context->vartable[name] = new PolyphonicIntVariable(context);
216     }
217 schoenebeck 3573 $$ = new NoOperation;
218 schoenebeck 2581 }
219     | DECLARE VARIABLE ASSIGNMENT expr {
220     const char* name = $2;
221     //printf("declared assign var '%s'\n", name);
222 schoenebeck 3573 const ExprType_t declType = exprTypeOfVarName(name);
223     if (context->variableByName(name)) {
224 schoenebeck 2888 PARSE_ERR(@2, (String("Redeclaration of variable '") + name + "'.").c_str());
225 schoenebeck 3573 $$ = new NoOperation;
226     } else if ($4->exprType() == STRING_EXPR) {
227     if (name[0] != '@')
228     PARSE_WRN(@2, (String("Variable '") + name + "' declared as " + typeStr(declType) + ", string expression assigned though.").c_str());
229 schoenebeck 2581 StringExprRef expr = $4;
230     if (expr->isConstExpr()) {
231     const String s = expr->evalStr();
232     StringVariableRef var = new StringVariable(context);
233     context->vartable[name] = var;
234     $$ = new Assignment(var, new StringLiteral(s));
235     } else {
236     StringVariableRef var = new StringVariable(context);
237     context->vartable[name] = var;
238     $$ = new Assignment(var, expr);
239     }
240 schoenebeck 3573 } else if ($4->exprType() == REAL_EXPR) {
241     if (name[0] != '~')
242     PARSE_WRN(@2, (String("Variable '") + name + "' declared as " + typeStr(declType) + ", real number expression assigned though.").c_str());
243     RealExprRef expr = $4;
244     RealVariableRef var = new RealVariable(context);
245     if (expr->isConstExpr()) {
246     const vmfloat f = expr->evalReal();
247     $$ = new Assignment(var, new RealLiteral(f));
248     } else {
249     $$ = new Assignment(var, expr);
250     }
251     var->copyUnitFrom(expr);
252     var->setFinal(expr->isFinal());
253     context->vartable[name] = var;
254     } else if ($4->exprType() == INT_EXPR) {
255     if (name[0] != '$')
256     PARSE_WRN(@2, (String("Variable '") + name + "' declared as " + typeStr(declType) + ", integer expression assigned though.").c_str());
257 schoenebeck 2581 IntExprRef expr = $4;
258 schoenebeck 3561 IntVariableRef var = new IntVariable(context);
259 schoenebeck 2581 if (expr->isConstExpr()) {
260 schoenebeck 3557 const vmint i = expr->evalInt();
261 schoenebeck 2581 $$ = new Assignment(var, new IntLiteral(i));
262     } else {
263     $$ = new Assignment(var, expr);
264     }
265 schoenebeck 3561 var->copyUnitFrom(expr);
266     var->setFinal(expr->isFinal());
267     context->vartable[name] = var;
268 schoenebeck 3573 } else if ($4->exprType() == EMPTY_EXPR) {
269     PARSE_ERR(@4, "Expression does not result in a value.");
270     $$ = new NoOperation;
271     } else if (isArray($4->exprType())) {
272     PARSE_ERR(@2, (String("Variable '") + name + "' declared as scalar type, array expression assigned though.").c_str());
273     $$ = new NoOperation;
274 schoenebeck 2581 }
275     }
276     | DECLARE VARIABLE '[' expr ']' {
277     //printf("declare array without args\n");
278     const char* name = $2;
279     if (!$4->isConstExpr()) {
280 schoenebeck 2888 PARSE_ERR(@4, (String("Array variable '") + name + "' must be declared with constant array size.").c_str());
281 schoenebeck 2581 } else if ($4->exprType() != INT_EXPR) {
282 schoenebeck 2888 PARSE_ERR(@4, (String("Size of array variable '") + name + "' declared with non integer expression.").c_str());
283 schoenebeck 2581 } else if (context->variableByName(name)) {
284 schoenebeck 2888 PARSE_ERR(@2, (String("Redeclaration of variable '") + name + "'.").c_str());
285 schoenebeck 2581 } else {
286     IntExprRef expr = $4;
287 schoenebeck 3561 if (expr->unitType() || expr->unitPrefix(0)) {
288     PARSE_ERR(@4, "Units are not allowed as array size.");
289 schoenebeck 2581 } else {
290 schoenebeck 3561 if (expr->isFinal())
291     PARSE_WRN(@4, "Final operator '!' is meaningless here.");
292     vmint size = expr->evalInt();
293     if (size <= 0) {
294     PARSE_ERR(@4, (String("Array variable '") + name + "' declared with array size " + ToString(size) + ".").c_str());
295     } else {
296 schoenebeck 3573 if (name[0] == '?') {
297     context->vartable[name] = new RealArrayVariable(context, size);
298     } else if (name[0] == '%') {
299     context->vartable[name] = new IntArrayVariable(context, size);
300     } else {
301     PARSE_ERR(@2, (String("Variable '") + name + "' declared as unknown array type: use either '%' or '?' instead of '" + String(name).substr(0,1) + "'.").c_str());
302     }
303 schoenebeck 3561 }
304 schoenebeck 2581 }
305     }
306 schoenebeck 3573 $$ = new NoOperation;
307 schoenebeck 2581 }
308     | DECLARE VARIABLE '[' expr ']' ASSIGNMENT '(' args ')' {
309     const char* name = $2;
310     if (!$4->isConstExpr()) {
311 schoenebeck 2888 PARSE_ERR(@4, (String("Array variable '") + name + "' must be declared with constant array size.").c_str());
312 schoenebeck 2581 } else if ($4->exprType() != INT_EXPR) {
313 schoenebeck 2888 PARSE_ERR(@4, (String("Size of array variable '") + name + "' declared with non integer expression.").c_str());
314 schoenebeck 2581 } else if (context->variableByName(name)) {
315 schoenebeck 2888 PARSE_ERR(@2, (String("Redeclaration of variable '") + name + "'.").c_str());
316 schoenebeck 2581 } else {
317     IntExprRef sizeExpr = $4;
318     ArgsRef args = $8;
319 schoenebeck 3557 vmint size = sizeExpr->evalInt();
320 schoenebeck 2581 if (size <= 0) {
321 schoenebeck 2888 PARSE_ERR(@4, (String("Array variable '") + name + "' must be declared with positive array size.").c_str());
322 schoenebeck 2581 } else if (args->argsCount() > size) {
323 schoenebeck 3257 PARSE_ERR(@8, (String("Array variable '") + name +
324 schoenebeck 2581 "' was declared with size " + ToString(size) +
325     " but " + ToString(args->argsCount()) +
326     " values were assigned." ).c_str());
327 schoenebeck 3561 } else if (sizeExpr->unitType() || sizeExpr->unitPrefix(0)) {
328     PARSE_ERR(@4, "Units are not allowed as array size.");
329 schoenebeck 2581 } else {
330 schoenebeck 3561 if (sizeExpr->isFinal())
331     PARSE_WRN(@4, "Final operator '!' is meaningless here.");
332 schoenebeck 3573 ExprType_t declType = EMPTY_EXPR;
333     if (name[0] == '%') {
334     declType = INT_EXPR;
335     } else if (name[0] == '?') {
336     declType = REAL_EXPR;
337     } else if (name[0] == '$') {
338     PARSE_ERR(@2, (String("Variable '") + name + "' declaration ambiguous: Use '%' as name prefix for integer arrays instead of '$'.").c_str());
339     } else if (name[0] == '~') {
340     PARSE_ERR(@2, (String("Variable '") + name + "' declaration ambiguous: Use '?' as name prefix for real number arrays instead of '~'.").c_str());
341     } else {
342     PARSE_ERR(@2, (String("Variable '") + name + "' declared as unknown array type: use either '%' or '?' instead of '" + String(name).substr(0,1) + "'.").c_str());
343     }
344 schoenebeck 2581 bool argsOK = true;
345 schoenebeck 3573 if (declType == EMPTY_EXPR) {
346     argsOK = false;
347     } else {
348     for (vmint i = 0; i < args->argsCount(); ++i) {
349     if (args->arg(i)->exprType() != declType) {
350     PARSE_ERR(
351     @8,
352     (String("Array variable '") + name +
353     "' declared with invalid assignment values. Assigned element " +
354     ToString(i+1) + " is not an " + typeStr(declType) + " expression.").c_str()
355     );
356     argsOK = false;
357     break;
358     } else if (args->arg(i)->asInt()->unitType() ||
359     args->arg(i)->asInt()->unitPrefix(0))
360     {
361     PARSE_ERR(
362     @8,
363     (String("Array variable '") + name +
364     "' declared with invalid assignment values. Assigned element " +
365     ToString(i+1) + " contains a unit.").c_str()
366     );
367     argsOK = false;
368     break;
369     }
370 schoenebeck 2581 }
371     }
372 schoenebeck 3013 if (argsOK) {
373 schoenebeck 3573 if (declType == REAL_EXPR)
374     context->vartable[name] = new RealArrayVariable(context, size, args);
375     else
376     context->vartable[name] = new IntArrayVariable(context, size, args);
377     }
378 schoenebeck 2581 }
379     }
380 schoenebeck 3573 $$ = new NoOperation;
381 schoenebeck 2581 }
382 schoenebeck 3257 | DECLARE CONST_ VARIABLE '[' expr ']' ASSIGNMENT '(' args ')' {
383     const char* name = $3;
384     if (!$5->isConstExpr()) {
385     PARSE_ERR(@5, (String("Array variable '") + name + "' must be declared with constant array size.").c_str());
386     } else if ($5->exprType() != INT_EXPR) {
387     PARSE_ERR(@5, (String("Size of array variable '") + name + "' declared with non integer expression.").c_str());
388     } else if (context->variableByName(name)) {
389     PARSE_ERR(@3, (String("Redeclaration of variable '") + name + "'.").c_str());
390     } else {
391     IntExprRef sizeExpr = $5;
392     ArgsRef args = $9;
393 schoenebeck 3557 vmint size = sizeExpr->evalInt();
394 schoenebeck 3257 if (size <= 0) {
395     PARSE_ERR(@5, (String("Array variable '") + name + "' must be declared with positive array size.").c_str());
396     } else if (args->argsCount() > size) {
397     PARSE_ERR(@9, (String("Array variable '") + name +
398     "' was declared with size " + ToString(size) +
399     " but " + ToString(args->argsCount()) +
400     " values were assigned." ).c_str());
401 schoenebeck 3561 } else if (sizeExpr->unitType() || sizeExpr->unitPrefix(0)) {
402     PARSE_ERR(@5, "Units are not allowed as array size.");
403 schoenebeck 3257 } else {
404 schoenebeck 3561 if (sizeExpr->isFinal())
405     PARSE_WRN(@5, "Final operator '!' is meaningless here.");
406 schoenebeck 3573 ExprType_t declType = EMPTY_EXPR;
407     if (name[0] == '%') {
408     declType = INT_EXPR;
409     } else if (name[0] == '?') {
410     declType = REAL_EXPR;
411     } else if (name[0] == '$') {
412     PARSE_ERR(@3, (String("Variable '") + name + "' declaration ambiguous: Use '%' as name prefix for integer arrays instead of '$'.").c_str());
413     } else if (name[0] == '~') {
414     PARSE_ERR(@3, (String("Variable '") + name + "' declaration ambiguous: Use '?' as name prefix for real number arrays instead of '~'.").c_str());
415     } else {
416     PARSE_ERR(@3, (String("Variable '") + name + "' declared as unknown array type: use either '%' or '?' instead of '" + String(name).substr(0,1) + "'.").c_str());
417     }
418 schoenebeck 3257 bool argsOK = true;
419 schoenebeck 3573 if (declType == EMPTY_EXPR) {
420     argsOK = false;
421     } else {
422     for (vmint i = 0; i < args->argsCount(); ++i) {
423     if (args->arg(i)->exprType() != declType) {
424     PARSE_ERR(
425     @9,
426     (String("Array variable '") + name +
427     "' declared with invalid assignment values. Assigned element " +
428     ToString(i+1) + " is not an " + typeStr(declType) + " expression.").c_str()
429     );
430     argsOK = false;
431     break;
432     }
433     if (!args->arg(i)->isConstExpr()) {
434     PARSE_ERR(
435     @9,
436     (String("const array variable '") + name +
437     "' must be defined with const values. Assigned element " +
438     ToString(i+1) + " is not a const expression though.").c_str()
439     );
440     argsOK = false;
441     break;
442     } else if (args->arg(i)->asInt()->unitType() ||
443     args->arg(i)->asInt()->unitPrefix(0))
444     {
445     PARSE_ERR(
446     @9,
447     (String("const array variable '") + name +
448     "' declared with invalid assignment values. Assigned element " +
449     ToString(i+1) + " contains a unit.").c_str()
450     );
451     argsOK = false;
452     break;
453     }
454 schoenebeck 3257 }
455     }
456     if (argsOK) {
457 schoenebeck 3573 if (declType == REAL_EXPR)
458     context->vartable[name] = new RealArrayVariable(context, size, args, true);
459     else
460     context->vartable[name] = new IntArrayVariable(context, size, args, true);
461     }
462 schoenebeck 3257 }
463     }
464 schoenebeck 3573 $$ = new NoOperation;
465 schoenebeck 3257 }
466 schoenebeck 2585 | DECLARE CONST_ VARIABLE ASSIGNMENT expr {
467 schoenebeck 2581 const char* name = $3;
468 schoenebeck 3573 const ExprType_t declType = exprTypeOfVarName(name);
469 schoenebeck 2581 if ($5->exprType() == STRING_EXPR) {
470 schoenebeck 3573 if (name[0] != '@')
471     PARSE_WRN(@5, (String("Variable '") + name + "' declared as " + typeStr(declType) + ", string expression assigned though.").c_str());
472 schoenebeck 2581 String s;
473     StringExprRef expr = $5;
474     if (expr->isConstExpr())
475     s = expr->evalStr();
476     else
477 schoenebeck 2888 PARSE_ERR(@5, (String("Assignment to const string variable '") + name + "' requires const expression.").c_str());
478 schoenebeck 2581 ConstStringVariableRef var = new ConstStringVariable(context, s);
479     context->vartable[name] = var;
480     //$$ = new Assignment(var, new StringLiteral(s));
481 schoenebeck 3573 } else if ($5->exprType() == REAL_EXPR) {
482     if (name[0] != '~')
483     PARSE_WRN(@5, (String("Variable '") + name + "' declared as " + typeStr(declType) + ", real number expression assigned though.").c_str());
484     vmfloat f = 0;
485     RealExprRef expr = $5;
486     if (expr->isConstExpr())
487     f = expr->evalReal();
488     else
489     PARSE_ERR(@5, (String("Assignment to const real number variable '") + name + "' requires const expression.").c_str());
490     ConstRealVariableRef var = new ConstRealVariable(f);
491     var->copyUnitFrom(expr);
492     var->setFinal(expr->isFinal());
493     context->vartable[name] = var;
494     //$$ = new Assignment(var, new IntLiteral(i));
495     } else if ($5->exprType() == INT_EXPR) {
496     if (name[0] != '$')
497     PARSE_WRN(@5, (String("Variable '") + name + "' declared as " + typeStr(declType) + ", integer expression assigned though.").c_str());
498 schoenebeck 3557 vmint i = 0;
499 schoenebeck 2581 IntExprRef expr = $5;
500     if (expr->isConstExpr())
501     i = expr->evalInt();
502     else
503 schoenebeck 2888 PARSE_ERR(@5, (String("Assignment to const integer variable '") + name + "' requires const expression.").c_str());
504 schoenebeck 2581 ConstIntVariableRef var = new ConstIntVariable(i);
505 schoenebeck 3561 var->copyUnitFrom(expr);
506     var->setFinal(expr->isFinal());
507 schoenebeck 2581 context->vartable[name] = var;
508     //$$ = new Assignment(var, new IntLiteral(i));
509 schoenebeck 3573 } else if ($5->exprType() == EMPTY_EXPR) {
510     PARSE_ERR(@5, "Expression does not result in a value.");
511     } else if (isArray($5->exprType())) {
512     PARSE_ERR(@5, (String("Variable '") + name + "' declared as scalar type, array expression assigned though.").c_str());
513 schoenebeck 2581 }
514 schoenebeck 3573 $$ = new NoOperation();
515 schoenebeck 2581 }
516     | assignment {
517     $$ = $1;
518     }
519 schoenebeck 2947 | WHILE '(' expr ')' opt_statements END WHILE {
520 schoenebeck 2581 if ($3->exprType() == INT_EXPR) {
521 schoenebeck 3561 IntExprRef expr = $3;
522     if (expr->isFinal() && expr->isConstExpr())
523     PARSE_WRN(@3, "Final operator '!' is meaningless here.");
524     $$ = new While(expr, $5);
525 schoenebeck 2581 } else {
526 schoenebeck 2888 PARSE_ERR(@3, "Condition for 'while' loops must be integer expression.");
527 schoenebeck 2581 $$ = new While(new IntLiteral(0), $5);
528     }
529     }
530 schoenebeck 3260 | SYNCHRONIZED opt_statements END SYNCHRONIZED {
531     $$ = new SyncBlock($2);
532     }
533 schoenebeck 2947 | IF '(' expr ')' opt_statements ELSE opt_statements END IF {
534 schoenebeck 3561 if ($3->exprType() == INT_EXPR) {
535     IntExprRef expr = $3;
536     if (expr->isFinal() && expr->isConstExpr())
537     PARSE_WRN(@3, "Final operator '!' is meaningless here.");
538     $$ = new If($3, $5, $7);
539     } else {
540     PARSE_ERR(@3, "Condition for 'if' must be integer expression.");
541     $$ = new If(new IntLiteral(0), $5, $7);
542     }
543 schoenebeck 2581 }
544 schoenebeck 2947 | IF '(' expr ')' opt_statements END IF {
545 schoenebeck 3561 if ($3->exprType() == INT_EXPR) {
546     IntExprRef expr = $3;
547     if (expr->isFinal() && expr->isConstExpr())
548     PARSE_WRN(@3, "Final operator '!' is meaningless here.");
549     $$ = new If($3, $5);
550     } else {
551     PARSE_ERR(@3, "Condition for 'if' must be integer expression.");
552     $$ = new If(new IntLiteral(0), $5);
553     }
554 schoenebeck 2581 }
555     | SELECT expr caseclauses END SELECT {
556     if ($2->exprType() == INT_EXPR) {
557 schoenebeck 3561 IntExprRef expr = $2;
558     if (expr->unitType() || expr->unitPrefix(0)) {
559     PARSE_ERR(@2, "Units are not allowed here.");
560     } else {
561     if (expr->isFinal() && expr->isConstExpr())
562     PARSE_WRN(@2, "Final operator '!' is meaningless here.");
563     $$ = new SelectCase(expr, $3);
564     }
565 schoenebeck 2581 } else {
566 schoenebeck 2888 PARSE_ERR(@2, "Statement 'select' can only by applied to integer expressions.");
567 schoenebeck 2581 $$ = new SelectCase(new IntLiteral(0), $3);
568     }
569     }
570    
571     caseclauses:
572     caseclause {
573     $$ = CaseBranches();
574     $$.push_back($1);
575     }
576     | caseclauses caseclause {
577     $$ = $1;
578     $$.push_back($2);
579     }
580    
581     caseclause:
582 schoenebeck 2947 CASE INTEGER opt_statements {
583 schoenebeck 2581 $$ = CaseBranch();
584     $$.from = new IntLiteral($2);
585     $$.statements = $3;
586     }
587 schoenebeck 2947 | CASE INTEGER TO INTEGER opt_statements {
588 schoenebeck 2581 $$ = CaseBranch();
589     $$.from = new IntLiteral($2);
590     $$.to = new IntLiteral($4);
591     $$.statements = $5;
592     }
593    
594 schoenebeck 2951 userfunctioncall:
595     CALL IDENTIFIER {
596     const char* name = $2;
597     StatementsRef fn = context->userFunctionByName(name);
598     if (context->functionProvider->functionByName(name)) {
599     PARSE_ERR(@1, (String("Keyword 'call' must only be used for user defined functions, not for any built-in function like '") + name + "'.").c_str());
600     $$ = StatementsRef();
601     } else if (!fn) {
602     PARSE_ERR(@2, (String("No user defined function with name '") + name + "'.").c_str());
603     $$ = StatementsRef();
604     } else {
605     $$ = fn;
606     }
607     }
608    
609 schoenebeck 2581 functioncall:
610     IDENTIFIER '(' args ')' {
611     const char* name = $1;
612     //printf("function call of '%s' with args\n", name);
613     ArgsRef args = $3;
614     VMFunction* fn = context->functionProvider->functionByName(name);
615 schoenebeck 2951 if (context->userFunctionByName(name)) {
616     PARSE_ERR(@1, (String("Missing 'call' keyword before user defined function name '") + name + "'.").c_str());
617     $$ = new FunctionCall(name, args, NULL);
618     } else if (!fn) {
619 schoenebeck 2888 PARSE_ERR(@1, (String("No built-in function with name '") + name + "'.").c_str());
620 schoenebeck 2581 $$ = new FunctionCall(name, args, NULL);
621 schoenebeck 3311 } else if (context->functionProvider->isFunctionDisabled(fn,context)) {
622     PARSE_DROP(@$);
623     $$ = new NoFunctionCall;
624 schoenebeck 2581 } else if (args->argsCount() < fn->minRequiredArgs()) {
625 schoenebeck 2888 PARSE_ERR(@3, (String("Built-in function '") + name + "' requires at least " + ToString(fn->minRequiredArgs()) + " arguments.").c_str());
626 schoenebeck 2581 $$ = new FunctionCall(name, args, NULL);
627     } else if (args->argsCount() > fn->maxAllowedArgs()) {
628 schoenebeck 2888 PARSE_ERR(@3, (String("Built-in function '") + name + "' accepts max. " + ToString(fn->maxAllowedArgs()) + " arguments.").c_str());
629 schoenebeck 2581 $$ = new FunctionCall(name, args, NULL);
630     } else {
631     bool argsOK = true;
632 schoenebeck 3557 for (vmint i = 0; i < args->argsCount(); ++i) {
633 schoenebeck 2581 if (args->arg(i)->exprType() != fn->argType(i) && !fn->acceptsArgType(i, args->arg(i)->exprType())) {
634 schoenebeck 2888 PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' expects " + typeStr(fn->argType(i)) + " type, but type " + typeStr(args->arg(i)->exprType()) + " was given instead.").c_str());
635 schoenebeck 2581 argsOK = false;
636     break;
637 schoenebeck 2945 } else if (fn->modifiesArg(i) && !args->arg(i)->isModifyable()) {
638     PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' expects an assignable variable.").c_str());
639     argsOK = false;
640     break;
641 schoenebeck 3573 } else if (isScalarNumber(args->arg(i)->exprType()) && !fn->acceptsArgUnitType(i, args->arg(i)->asScalarNumberExpr()->unitType())) {
642     if (args->arg(i)->asScalarNumberExpr()->unitType())
643     PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' does not expect unit " + unitTypeStr(args->arg(i)->asScalarNumberExpr()->unitType()) + ".").c_str());
644 schoenebeck 3561 else
645     PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' expects a unit.").c_str());
646     argsOK = false;
647     break;
648 schoenebeck 3573 } else if (isScalarNumber(args->arg(i)->exprType()) && args->arg(i)->asScalarNumberExpr()->unitPrefix(0) && !fn->acceptsArgUnitPrefix(i, args->arg(i)->asScalarNumberExpr()->unitType())) {
649     if (args->arg(i)->asScalarNumberExpr()->unitType())
650     PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' does not expect a unit prefix for unit" + unitTypeStr(args->arg(i)->asScalarNumberExpr()->unitType()) + ".").c_str());
651 schoenebeck 3564 else
652     PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' does not expect a unit prefix.").c_str());
653 schoenebeck 3561 argsOK = false;
654     break;
655 schoenebeck 3573 } else if (!fn->acceptsArgFinal(i) && isScalarNumber(args->arg(i)->exprType()) && args->arg(i)->asScalarNumberExpr()->isFinal()) {
656 schoenebeck 3561 PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' does not expect a \"final\" value.").c_str());
657     argsOK = false;
658     break;
659 schoenebeck 2581 }
660     }
661     $$ = new FunctionCall(name, args, argsOK ? fn : NULL);
662     }
663     }
664     | IDENTIFIER '(' ')' {
665     const char* name = $1;
666     //printf("function call of '%s' (with empty args)\n", name);
667     ArgsRef args = new Args;
668     VMFunction* fn = context->functionProvider->functionByName(name);
669 schoenebeck 2951 if (context->userFunctionByName(name)) {
670     PARSE_ERR(@1, (String("Missing 'call' keyword before user defined function name '") + name + "'.").c_str());
671     $$ = new FunctionCall(name, args, NULL);
672     } else if (!fn) {
673 schoenebeck 2888 PARSE_ERR(@1, (String("No built-in function with name '") + name + "'.").c_str());
674 schoenebeck 2581 $$ = new FunctionCall(name, args, NULL);
675 schoenebeck 3311 } else if (context->functionProvider->isFunctionDisabled(fn,context)) {
676     PARSE_DROP(@$);
677     $$ = new NoFunctionCall;
678 schoenebeck 2581 } else if (fn->minRequiredArgs() > 0) {
679 schoenebeck 2888 PARSE_ERR(@3, (String("Built-in function '") + name + "' requires at least " + ToString(fn->minRequiredArgs()) + " arguments.").c_str());
680 schoenebeck 2581 $$ = new FunctionCall(name, args, NULL);
681     } else {
682     $$ = new FunctionCall(name, args, fn);
683     }
684     }
685     | IDENTIFIER {
686     const char* name = $1;
687     //printf("function call of '%s' (without args)\n", name);
688     ArgsRef args = new Args;
689     VMFunction* fn = context->functionProvider->functionByName(name);
690 schoenebeck 2951 if (context->userFunctionByName(name)) {
691     PARSE_ERR(@1, (String("Missing 'call' keyword before user defined function name '") + name + "'.").c_str());
692     $$ = new FunctionCall(name, args, NULL);
693     } else if (!fn) {
694 schoenebeck 2888 PARSE_ERR(@1, (String("No built-in function with name '") + name + "'.").c_str());
695 schoenebeck 2581 $$ = new FunctionCall(name, args, NULL);
696 schoenebeck 3311 } else if (context->functionProvider->isFunctionDisabled(fn,context)) {
697     PARSE_DROP(@$);
698     $$ = new NoFunctionCall;
699 schoenebeck 2581 } else if (fn->minRequiredArgs() > 0) {
700 schoenebeck 2888 PARSE_ERR(@1, (String("Built-in function '") + name + "' requires at least " + ToString(fn->minRequiredArgs()) + " arguments.").c_str());
701 schoenebeck 2581 $$ = new FunctionCall(name, args, NULL);
702     } else {
703     $$ = new FunctionCall(name, args, fn);
704     }
705     }
706    
707     args:
708     arg {
709     $$ = new Args();
710     $$->add($1);
711     }
712     | args ',' arg {
713     $$ = $1;
714     $$->add($3);
715     }
716    
717     arg:
718     expr
719    
720     assignment:
721     VARIABLE ASSIGNMENT expr {
722     //printf("variable lookup with name '%s' as assignment expr\n", $1);
723     const char* name = $1;
724     VariableRef var = context->variableByName(name);
725     if (!var)
726 schoenebeck 2888 PARSE_ERR(@1, (String("Variable assignment: No variable declared with name '") + name + "'.").c_str());
727 schoenebeck 2581 else if (var->isConstExpr())
728 schoenebeck 2888 PARSE_ERR(@2, (String("Variable assignment: Cannot modify const variable '") + name + "'.").c_str());
729 schoenebeck 2942 else if (!var->isAssignable())
730     PARSE_ERR(@2, (String("Variable assignment: Variable '") + name + "' is not assignable.").c_str());
731 schoenebeck 2581 else if (var->exprType() != $3->exprType())
732 schoenebeck 2888 PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' is of type " + typeStr(var->exprType()) + ", assignment is of type " + typeStr($3->exprType()) + " though.").c_str());
733 schoenebeck 3573 else if (isScalarNumber(var->exprType())) {
734     ScalarNumberVariableRef numberVar = var;
735     ScalarNumberExprRef expr = $3;
736     if (numberVar->unitType() != expr->unitType())
737     PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' has unit type " + unitTypeStr(numberVar->unitType()) + ", assignment has unit type " + unitTypeStr(expr->unitType()) + " though.").c_str());
738     else if (numberVar->unitFactor() != expr->unitFactor())
739 schoenebeck 3561 PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' has a different unit prefix.").c_str());
740 schoenebeck 3573 else if (numberVar->isFinal() != expr->isFinal())
741     PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' was declared as " + String(numberVar->isFinal() ? "final" : "not final") + ", assignment is " + String(expr->isFinal() ? "final" : "not final") + " though.").c_str());
742 schoenebeck 3561 }
743 schoenebeck 2581 $$ = new Assignment(var, $3);
744     }
745     | VARIABLE '[' expr ']' ASSIGNMENT expr {
746     const char* name = $1;
747     VariableRef var = context->variableByName(name);
748     if (!var)
749 schoenebeck 2888 PARSE_ERR(@1, (String("No variable declared with name '") + name + "'.").c_str());
750 schoenebeck 3573 else if (!isArray(var->exprType()))
751 schoenebeck 2888 PARSE_ERR(@2, (String("Variable '") + name + "' is not an array variable.").c_str());
752 schoenebeck 3253 else if (var->isConstExpr())
753     PARSE_ERR(@5, (String("Variable assignment: Cannot modify const array variable '") + name + "'.").c_str());
754     else if (!var->isAssignable())
755     PARSE_ERR(@5, (String("Variable assignment: Array variable '") + name + "' is not assignable.").c_str());
756 schoenebeck 2581 else if ($3->exprType() != INT_EXPR)
757 schoenebeck 2888 PARSE_ERR(@3, (String("Array variable '") + name + "' accessed with non integer expression.").c_str());
758 schoenebeck 3561 else if ($3->asInt()->unitType())
759     PARSE_ERR(@3, "Unit types are not allowed as array index.");
760 schoenebeck 3573 else if ($6->exprType() != var->exprType())
761     PARSE_ERR(@5, (String("Variable '") + name + "' was declared as " + typeStr(var->exprType()) + ", assigned expression is " + typeStr($6->exprType()) + " though.").c_str());
762     else if ($6->asScalarNumberExpr()->unitType())
763 schoenebeck 3561 PARSE_ERR(@6, "Unit types are not allowed for array variables.");
764 schoenebeck 3573 else if ($6->asScalarNumberExpr()->isFinal())
765 schoenebeck 3561 PARSE_ERR(@6, "Final operator '!' not allowed for array variables.");
766 schoenebeck 3573 else if ($3->isConstExpr() && $3->asInt()->evalInt() >= ((ArrayExprRef)var)->arraySize())
767 schoenebeck 3257 PARSE_WRN(@3, (String("Index ") + ToString($3->asInt()->evalInt()) +
768     " exceeds size of array variable '" + name +
769     "' which was declared with size " +
770 schoenebeck 3573 ToString(((ArrayExprRef)var)->arraySize()) + ".").c_str());
771 schoenebeck 3561 else if ($3->asInt()->isFinal())
772     PARSE_WRN(@3, "Final operator '!' is meaningless here.");
773 schoenebeck 3573 if (var->exprType() == INT_ARR_EXPR) {
774     IntArrayElementRef element = new IntArrayElement(var, $3);
775     $$ = new Assignment(element, $6);
776     } else if (var->exprType() == REAL_ARR_EXPR) {
777     RealArrayElementRef element = new RealArrayElement(var, $3);
778     $$ = new Assignment(element, $6);
779     } else {
780     $$ = new NoOperation;
781     }
782 schoenebeck 2581 }
783    
784     unary_expr:
785     INTEGER {
786     $$ = new IntLiteral($1);
787     }
788 schoenebeck 3573 | REAL {
789     $$ = new RealLiteral($1);
790     }
791 schoenebeck 3561 | INTEGER_UNIT {
792     IntLiteralRef literal = new IntLiteral($1.iValue);
793     literal->setUnit($1.prefix, $1.unit);
794     $$ = literal;
795     }
796 schoenebeck 3573 | REAL_UNIT {
797     RealLiteralRef literal = new RealLiteral($1.fValue);
798     literal->setUnit($1.prefix, $1.unit);
799     $$ = literal;
800     }
801 schoenebeck 2581 | STRING {
802     $$ = new StringLiteral($1);
803     }
804     | VARIABLE {
805     //printf("variable lookup with name '%s' as unary expr\n", $1);
806     VariableRef var = context->variableByName($1);
807     if (var)
808     $$ = var;
809     else {
810 schoenebeck 2888 PARSE_ERR(@1, (String("No variable declared with name '") + $1 + "'.").c_str());
811 schoenebeck 2581 $$ = new IntLiteral(0);
812     }
813     }
814     | VARIABLE '[' expr ']' {
815     const char* name = $1;
816     VariableRef var = context->variableByName(name);
817     if (!var) {
818 schoenebeck 2888 PARSE_ERR(@1, (String("No variable declared with name '") + name + "'.").c_str());
819 schoenebeck 2581 $$ = new IntLiteral(0);
820 schoenebeck 3573 } else if (!isArray(var->exprType())) {
821 schoenebeck 2888 PARSE_ERR(@2, (String("Variable '") + name + "' is not an array variable.").c_str());
822 schoenebeck 2581 $$ = new IntLiteral(0);
823     } else if ($3->exprType() != INT_EXPR) {
824 schoenebeck 2888 PARSE_ERR(@3, (String("Array variable '") + name + "' accessed with non integer expression.").c_str());
825 schoenebeck 2581 $$ = new IntLiteral(0);
826 schoenebeck 3561 } else if ($3->asInt()->unitType() || $3->asInt()->unitPrefix(0)) {
827     PARSE_ERR(@3, "Units are not allowed as array index.");
828     $$ = new IntLiteral(0);
829 schoenebeck 2581 } else {
830 schoenebeck 3573 if ($3->isConstExpr() && $3->asInt()->evalInt() >= ((ArrayExprRef)var)->arraySize())
831 schoenebeck 3257 PARSE_WRN(@3, (String("Index ") + ToString($3->asInt()->evalInt()) +
832     " exceeds size of array variable '" + name +
833     "' which was declared with size " +
834 schoenebeck 3573 ToString(((ArrayExprRef)var)->arraySize()) + ".").c_str());
835 schoenebeck 3561 else if ($3->asInt()->isFinal())
836     PARSE_WRN(@3, "Final operator '!' is meaningless here.");
837 schoenebeck 3573 if (var->exprType() == REAL_ARR_EXPR) {
838     $$ = new RealArrayElement(var, $3);
839     } else {
840     $$ = new IntArrayElement(var, $3);
841     }
842 schoenebeck 2581 }
843     }
844     | '(' expr ')' {
845     $$ = $2;
846     }
847     | functioncall {
848     $$ = $1;
849     }
850     | '-' unary_expr {
851     $$ = new Neg($2);
852     }
853 schoenebeck 2935 | BITWISE_NOT unary_expr {
854     if ($2->exprType() != INT_EXPR) {
855     PARSE_ERR(@2, (String("Right operand of bitwise operator '.not.' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str());
856     $$ = new IntLiteral(0);
857 schoenebeck 3561 } else if ($2->asInt()->unitType() || $2->asInt()->unitPrefix(0)) {
858     PARSE_ERR(@2, "Units are not allowed for operands of bitwise operations.");
859     $$ = new IntLiteral(0);
860 schoenebeck 2935 } else {
861     $$ = new BitwiseNot($2);
862     }
863     }
864 schoenebeck 2581 | NOT unary_expr {
865     if ($2->exprType() != INT_EXPR) {
866 schoenebeck 2888 PARSE_ERR(@2, (String("Right operand of operator 'not' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str());
867 schoenebeck 2581 $$ = new IntLiteral(0);
868 schoenebeck 3561 } else if ($2->asInt()->unitType() || $2->asInt()->unitPrefix(0)) {
869     PARSE_ERR(@2, "Units are not allowed for operands of logical operations.");
870     $$ = new IntLiteral(0);
871 schoenebeck 2581 } else {
872     $$ = new Not($2);
873     }
874     }
875 schoenebeck 3561 | '!' unary_expr {
876 schoenebeck 3573 if (!isScalarNumber($2->exprType())) {
877     PARSE_ERR(@2, (String("Right operand of \"final\" operator '!' must be a scalar number expression, is ") + typeStr($2->exprType()) + " though.").c_str());
878 schoenebeck 3561 $$ = new IntLiteral(0);
879     } else {
880     $$ = new Final($2);
881     }
882     }
883 schoenebeck 2581
884     expr:
885     concat_expr
886    
887     concat_expr:
888 schoenebeck 2935 logical_or_expr
889     | concat_expr '&' logical_or_expr {
890 schoenebeck 2581 ExpressionRef lhs = $1;
891     ExpressionRef rhs = $3;
892     if (lhs->isConstExpr() && rhs->isConstExpr()) {
893     $$ = new StringLiteral(
894     lhs->evalCastToStr() + rhs->evalCastToStr()
895     );
896     } else {
897     $$ = new ConcatString(lhs, rhs);
898     }
899     }
900    
901 schoenebeck 2935 logical_or_expr:
902     logical_and_expr
903     | logical_or_expr OR logical_and_expr {
904 schoenebeck 2581 ExpressionRef lhs = $1;
905     ExpressionRef rhs = $3;
906     if (lhs->exprType() != INT_EXPR) {
907 schoenebeck 2888 PARSE_ERR(@1, (String("Left operand of operator 'or' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
908 schoenebeck 2581 $$ = new IntLiteral(0);
909     } else if (rhs->exprType() != INT_EXPR) {
910 schoenebeck 2888 PARSE_ERR(@3, (String("Right operand of operator 'or' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
911 schoenebeck 2581 $$ = new IntLiteral(0);
912 schoenebeck 3561 } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) {
913     PARSE_ERR(@1, "Units are not allowed for operands of logical operations.");
914     $$ = new IntLiteral(0);
915     } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) {
916     PARSE_ERR(@3, "Units are not allowed for operands of logical operations.");
917     $$ = new IntLiteral(0);
918 schoenebeck 2581 } else {
919     $$ = new Or(lhs, rhs);
920     }
921     }
922    
923 schoenebeck 2935 logical_and_expr:
924     bitwise_or_expr {
925 schoenebeck 2581 $$ = $1;
926     }
927 schoenebeck 2935 | logical_and_expr AND bitwise_or_expr {
928 schoenebeck 2581 ExpressionRef lhs = $1;
929     ExpressionRef rhs = $3;
930     if (lhs->exprType() != INT_EXPR) {
931 schoenebeck 2888 PARSE_ERR(@1, (String("Left operand of operator 'and' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
932 schoenebeck 2581 $$ = new IntLiteral(0);
933     } else if (rhs->exprType() != INT_EXPR) {
934 schoenebeck 2888 PARSE_ERR(@3, (String("Right operand of operator 'and' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
935 schoenebeck 2581 $$ = new IntLiteral(0);
936 schoenebeck 3561 } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) {
937     PARSE_ERR(@1, "Units are not allowed for operands of logical operations.");
938     $$ = new IntLiteral(0);
939     } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) {
940     PARSE_ERR(@3, "Units are not allowed for operands of logical operations.");
941     $$ = new IntLiteral(0);
942 schoenebeck 2581 } else {
943     $$ = new And(lhs, rhs);
944     }
945     }
946    
947 schoenebeck 2935 bitwise_or_expr:
948     bitwise_and_expr
949     | bitwise_or_expr BITWISE_OR bitwise_and_expr {
950     ExpressionRef lhs = $1;
951     ExpressionRef rhs = $3;
952     if (lhs->exprType() != INT_EXPR) {
953     PARSE_ERR(@1, (String("Left operand of bitwise operator '.or.' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
954     $$ = new IntLiteral(0);
955     } else if (rhs->exprType() != INT_EXPR) {
956     PARSE_ERR(@3, (String("Right operand of bitwise operator '.or.' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
957     $$ = new IntLiteral(0);
958 schoenebeck 3561 } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) {
959     PARSE_ERR(@1, "Units are not allowed for operands of bitwise operations.");
960     $$ = new IntLiteral(0);
961     } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) {
962     PARSE_ERR(@3, "Units are not allowed for operands of bitwise operations.");
963     $$ = new IntLiteral(0);
964 schoenebeck 2935 } else {
965     $$ = new BitwiseOr(lhs, rhs);
966     }
967     }
968    
969     bitwise_and_expr:
970     rel_expr {
971     $$ = $1;
972     }
973     | bitwise_and_expr BITWISE_AND rel_expr {
974     ExpressionRef lhs = $1;
975     ExpressionRef rhs = $3;
976     if (lhs->exprType() != INT_EXPR) {
977     PARSE_ERR(@1, (String("Left operand of bitwise operator '.and.' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
978     $$ = new IntLiteral(0);
979     } else if (rhs->exprType() != INT_EXPR) {
980     PARSE_ERR(@3, (String("Right operand of bitwise operator '.and.' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
981     $$ = new IntLiteral(0);
982 schoenebeck 3561 } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) {
983     PARSE_ERR(@1, "Units are not allowed for operands of bitwise operations.");
984     $$ = new IntLiteral(0);
985     } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) {
986     PARSE_ERR(@3, "Units are not allowed for operands of bitwise operations.");
987     $$ = new IntLiteral(0);
988 schoenebeck 2935 } else {
989     $$ = new BitwiseAnd(lhs, rhs);
990     }
991     }
992    
993 schoenebeck 2581 rel_expr:
994     add_expr
995     | rel_expr '<' add_expr {
996     ExpressionRef lhs = $1;
997     ExpressionRef rhs = $3;
998 schoenebeck 3573 if (!isScalarNumber(lhs->exprType())) {
999     PARSE_ERR(@1, (String("Left operand of operator '<' must be a scalar number expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1000 schoenebeck 2581 $$ = new IntLiteral(0);
1001 schoenebeck 3573 } else if (!isScalarNumber(rhs->exprType())) {
1002     PARSE_ERR(@3, (String("Right operand of operator '<' must be a scalar number expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1003 schoenebeck 2581 $$ = new IntLiteral(0);
1004 schoenebeck 3573 } else if (lhs->asScalarNumberExpr()->unitType() != rhs->asScalarNumberExpr()->unitType() ||
1005     lhs->asScalarNumberExpr()->unitFactor() != rhs->asScalarNumberExpr()->unitFactor())
1006 schoenebeck 3561 {
1007     PARSE_ERR(@2, "Operands of relative operations must have same unit.");
1008     $$ = new IntLiteral(0);
1009 schoenebeck 2581 } else {
1010     $$ = new Relation(lhs, Relation::LESS_THAN, rhs);
1011     }
1012     }
1013     | rel_expr '>' add_expr {
1014     ExpressionRef lhs = $1;
1015     ExpressionRef rhs = $3;
1016 schoenebeck 3573 if (!isScalarNumber(lhs->exprType())) {
1017     PARSE_ERR(@1, (String("Left operand of operator '>' must be a scalar number expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1018 schoenebeck 2581 $$ = new IntLiteral(0);
1019 schoenebeck 3573 } else if (!isScalarNumber(rhs->exprType())) {
1020     PARSE_ERR(@3, (String("Right operand of operator '>' must be a scalar number expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1021 schoenebeck 2581 $$ = new IntLiteral(0);
1022 schoenebeck 3573 } else if (lhs->asScalarNumberExpr()->unitType() != rhs->asScalarNumberExpr()->unitType() ||
1023     lhs->asScalarNumberExpr()->unitFactor() != rhs->asScalarNumberExpr()->unitFactor())
1024 schoenebeck 3561 {
1025     PARSE_ERR(@2, "Operands of relative operations must have same unit.");
1026     $$ = new IntLiteral(0);
1027 schoenebeck 2581 } else {
1028     $$ = new Relation(lhs, Relation::GREATER_THAN, rhs);
1029     }
1030     }
1031     | rel_expr LE add_expr {
1032     ExpressionRef lhs = $1;
1033     ExpressionRef rhs = $3;
1034 schoenebeck 3573 if (!isScalarNumber(lhs->exprType())) {
1035     PARSE_ERR(@1, (String("Left operand of operator '<=' must be a scalar number expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1036 schoenebeck 2581 $$ = new IntLiteral(0);
1037 schoenebeck 3573 } else if (!isScalarNumber(rhs->exprType())) {
1038     PARSE_ERR(@3, (String("Right operand of operator '<=' must be a scalar number expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1039 schoenebeck 2581 $$ = new IntLiteral(0);
1040 schoenebeck 3573 } else if (lhs->asScalarNumberExpr()->unitType() != rhs->asScalarNumberExpr()->unitType() ||
1041     lhs->asScalarNumberExpr()->unitFactor() != rhs->asScalarNumberExpr()->unitFactor())
1042 schoenebeck 3561 {
1043     PARSE_ERR(@2, "Operands of relative operations must have same unit.");
1044     $$ = new IntLiteral(0);
1045 schoenebeck 2581 } else {
1046     $$ = new Relation(lhs, Relation::LESS_OR_EQUAL, rhs);
1047     }
1048     }
1049     | rel_expr GE add_expr {
1050     ExpressionRef lhs = $1;
1051     ExpressionRef rhs = $3;
1052 schoenebeck 3573 if (!isScalarNumber(lhs->exprType())) {
1053     PARSE_ERR(@1, (String("Left operand of operator '>=' must be a scalar number expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1054 schoenebeck 2581 $$ = new IntLiteral(0);
1055 schoenebeck 3573 } else if (!isScalarNumber(rhs->exprType())) {
1056     PARSE_ERR(@3, (String("Right operand of operator '>=' must be a scalar number expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1057 schoenebeck 2581 $$ = new IntLiteral(0);
1058 schoenebeck 3573 } else if (lhs->asScalarNumberExpr()->unitType() != rhs->asScalarNumberExpr()->unitType() ||
1059     lhs->asScalarNumberExpr()->unitFactor() != rhs->asScalarNumberExpr()->unitFactor())
1060 schoenebeck 3561 {
1061     PARSE_ERR(@2, "Operands of relative operations must have same unit.");
1062     $$ = new IntLiteral(0);
1063 schoenebeck 2581 } else {
1064     $$ = new Relation(lhs, Relation::GREATER_OR_EQUAL, rhs);
1065     }
1066     }
1067     | rel_expr '=' add_expr {
1068 schoenebeck 3561 ExpressionRef lhs = $1;
1069     ExpressionRef rhs = $3;
1070 schoenebeck 3573 if (!isScalarNumber(lhs->exprType())) {
1071     PARSE_ERR(@1, (String("Left operand of operator '=' must be a scalar number expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1072 schoenebeck 3561 $$ = new IntLiteral(0);
1073 schoenebeck 3573 } else if (!isScalarNumber(rhs->exprType())) {
1074     PARSE_ERR(@3, (String("Right operand of operator '=' must be a scalar number expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1075 schoenebeck 3561 $$ = new IntLiteral(0);
1076 schoenebeck 3573 } else if (lhs->asScalarNumberExpr()->unitType() != rhs->asScalarNumberExpr()->unitType() ||
1077     lhs->asScalarNumberExpr()->unitFactor() != rhs->asScalarNumberExpr()->unitFactor())
1078 schoenebeck 3561 {
1079     PARSE_ERR(@2, "Operands of relative operations must have same unit.");
1080     $$ = new IntLiteral(0);
1081     } else {
1082     $$ = new Relation(lhs, Relation::EQUAL, rhs);
1083     }
1084 schoenebeck 2581 }
1085     | rel_expr '#' add_expr {
1086 schoenebeck 3561 ExpressionRef lhs = $1;
1087     ExpressionRef rhs = $3;
1088 schoenebeck 3573 if (!isScalarNumber(lhs->exprType())) {
1089     PARSE_ERR(@1, (String("Left operand of operator '#' must be a scalar number expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1090 schoenebeck 3561 $$ = new IntLiteral(0);
1091 schoenebeck 3573 } else if (!isScalarNumber(rhs->exprType())) {
1092     PARSE_ERR(@3, (String("Right operand of operator '#' must be a scalar number expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1093 schoenebeck 3561 $$ = new IntLiteral(0);
1094 schoenebeck 3573 } else if (lhs->asScalarNumberExpr()->unitType() != rhs->asScalarNumberExpr()->unitType() ||
1095     lhs->asScalarNumberExpr()->unitFactor() != rhs->asScalarNumberExpr()->unitFactor())
1096 schoenebeck 3561 {
1097     PARSE_ERR(@2, "Operands of relative operations must have same unit.");
1098     $$ = new IntLiteral(0);
1099     } else {
1100     $$ = new Relation(lhs, Relation::NOT_EQUAL, rhs);
1101     }
1102 schoenebeck 2581 }
1103    
1104     add_expr:
1105     mul_expr
1106     | add_expr '+' mul_expr {
1107     ExpressionRef lhs = $1;
1108     ExpressionRef rhs = $3;
1109 schoenebeck 3573 if (!isScalarNumber(lhs->exprType())) {
1110     PARSE_ERR(@1, (String("Left operand of operator '+' must be a scalar number expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1111 schoenebeck 2581 $$ = new IntLiteral(0);
1112 schoenebeck 3573 } else if (!isScalarNumber(rhs->exprType())) {
1113     PARSE_ERR(@1, (String("Right operand of operator '+' must be a scalar number expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1114 schoenebeck 2581 $$ = new IntLiteral(0);
1115 schoenebeck 3573 } else if (lhs->exprType() != rhs->exprType()) {
1116     PARSE_ERR(@2, (String("Operands of operator '+' must have same type; left operand is ") +
1117     typeStr(lhs->exprType()) + " and right operand is " + typeStr(rhs->exprType()) + " though.").c_str());
1118     $$ = new IntLiteral(0);
1119     } else if (lhs->asScalarNumberExpr()->unitType() != rhs->asScalarNumberExpr()->unitType() ||
1120     lhs->asScalarNumberExpr()->unitFactor() != rhs->asScalarNumberExpr()->unitFactor())
1121 schoenebeck 3561 {
1122     PARSE_ERR(@2, "Operands of '+' operations must have same unit.");
1123     $$ = new IntLiteral(0);
1124 schoenebeck 2581 } else {
1125     $$ = new Add(lhs,rhs);
1126     }
1127     }
1128     | add_expr '-' mul_expr {
1129     ExpressionRef lhs = $1;
1130     ExpressionRef rhs = $3;
1131 schoenebeck 3573 if (!isScalarNumber(lhs->exprType())) {
1132     PARSE_ERR(@1, (String("Left operand of operator '-' must be a scalar number expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1133 schoenebeck 2581 $$ = new IntLiteral(0);
1134 schoenebeck 3573 } else if (!isScalarNumber(rhs->exprType())) {
1135     PARSE_ERR(@1, (String("Right operand of operator '-' must be a scalar number expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1136 schoenebeck 2581 $$ = new IntLiteral(0);
1137 schoenebeck 3573 } else if (lhs->exprType() != rhs->exprType()) {
1138     PARSE_ERR(@2, (String("Operands of operator '-' must have same type; left operand is ") +
1139     typeStr(lhs->exprType()) + " and right operand is " + typeStr(rhs->exprType()) + " though.").c_str());
1140     $$ = new IntLiteral(0);
1141     } else if (lhs->asScalarNumberExpr()->unitType() != rhs->asScalarNumberExpr()->unitType() ||
1142     lhs->asScalarNumberExpr()->unitFactor() != rhs->asScalarNumberExpr()->unitFactor())
1143 schoenebeck 3561 {
1144     PARSE_ERR(@2, "Operands of '-' operations must have same unit.");
1145     $$ = new IntLiteral(0);
1146 schoenebeck 2581 } else {
1147     $$ = new Sub(lhs,rhs);
1148     }
1149     }
1150    
1151     mul_expr:
1152     unary_expr
1153     | mul_expr '*' unary_expr {
1154     ExpressionRef lhs = $1;
1155     ExpressionRef rhs = $3;
1156 schoenebeck 3573 if (!isScalarNumber(lhs->exprType())) {
1157     PARSE_ERR(@1, (String("Left operand of operator '*' must be a scalar number expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1158 schoenebeck 2581 $$ = new IntLiteral(0);
1159 schoenebeck 3573 } else if (!isScalarNumber(rhs->exprType())) {
1160     PARSE_ERR(@1, (String("Right operand of operator '*' must be a scalar number expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1161 schoenebeck 2581 $$ = new IntLiteral(0);
1162 schoenebeck 3573 } else if (lhs->asScalarNumberExpr()->unitType() && rhs->asScalarNumberExpr()->unitType()) {
1163 schoenebeck 3561 PARSE_ERR(@2, "Only one operand of operator '*' may have a unit type");
1164     $$ = new IntLiteral(0);
1165 schoenebeck 3573 } else if (lhs->exprType() != rhs->exprType()) {
1166     PARSE_ERR(@2, (String("Operands of operator '*' must have same type; left operand is ") +
1167     typeStr(lhs->exprType()) + " and right operand is " + typeStr(rhs->exprType()) + " though.").c_str());
1168     $$ = new IntLiteral(0);
1169     } else if (lhs->asScalarNumberExpr()->unitPrefix(0) && rhs->asScalarNumberExpr()->unitPrefix(0)) {
1170 schoenebeck 3561 PARSE_ERR(@2, "Only one operand of operator '*' may have a unit prefix");
1171     $$ = new IntLiteral(0);
1172 schoenebeck 2581 } else {
1173     $$ = new Mul(lhs,rhs);
1174     }
1175     }
1176     | mul_expr '/' unary_expr {
1177     ExpressionRef lhs = $1;
1178     ExpressionRef rhs = $3;
1179 schoenebeck 3573 if (!isScalarNumber(lhs->exprType())) {
1180     PARSE_ERR(@1, (String("Left operand of operator '/' must be a scalar number expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1181 schoenebeck 2581 $$ = new IntLiteral(0);
1182 schoenebeck 3573 } else if (!isScalarNumber(rhs->exprType())) {
1183     PARSE_ERR(@1, (String("Right operand of operator '/' must be a scalar number expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1184 schoenebeck 2581 $$ = new IntLiteral(0);
1185 schoenebeck 3573 } else if (lhs->asScalarNumberExpr()->unitType() && rhs->asScalarNumberExpr()->unitType() &&
1186     lhs->asScalarNumberExpr()->unitType() != rhs->asScalarNumberExpr()->unitType())
1187 schoenebeck 3561 {
1188     PARSE_ERR(@2, "Operands of operator '/' with two different unit types.");
1189     $$ = new IntLiteral(0);
1190 schoenebeck 3573 } else if (!lhs->asScalarNumberExpr()->unitType() && rhs->asScalarNumberExpr()->unitType()) {
1191 schoenebeck 3561 PARSE_ERR(@3, ("Dividing left operand without any unit type by right operand with unit type " + typeStr(rhs->exprType()) + " is not possible.").c_str());
1192     $$ = new IntLiteral(0);
1193 schoenebeck 3573 } else if (lhs->asScalarNumberExpr()->unitFactor() != rhs->asScalarNumberExpr()->unitFactor() &&
1194     lhs->asScalarNumberExpr()->unitPrefix(0) && rhs->asScalarNumberExpr()->unitPrefix(0))
1195 schoenebeck 3561 {
1196     PARSE_ERR(@2, "Dividing two operands with two different unit prefixes is not possible.");
1197     $$ = new IntLiteral(0);
1198 schoenebeck 3573 } else if (lhs->asScalarNumberExpr()->unitFactor() != rhs->asScalarNumberExpr()->unitFactor() &&
1199     rhs->asScalarNumberExpr()->unitPrefix(0))
1200 schoenebeck 3561 {
1201     PARSE_ERR(@3, "Dividing left operand without any unit prefix by right operand with unit prefix is not possible.");
1202     $$ = new IntLiteral(0);
1203 schoenebeck 3573 } else if (lhs->exprType() != rhs->exprType()) {
1204     PARSE_ERR(@2, (String("Operands of operator '/' must have same type; left operand is ") +
1205     typeStr(lhs->exprType()) + " and right operand is " + typeStr(rhs->exprType()) + " though.").c_str());
1206     $$ = new IntLiteral(0);
1207 schoenebeck 2581 } else {
1208     $$ = new Div(lhs,rhs);
1209     }
1210     }
1211     | mul_expr MOD unary_expr {
1212     ExpressionRef lhs = $1;
1213     ExpressionRef rhs = $3;
1214     if (lhs->exprType() != INT_EXPR) {
1215 schoenebeck 2888 PARSE_ERR(@1, (String("Left operand of modulo operator must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1216 schoenebeck 2581 $$ = new IntLiteral(0);
1217     } else if (rhs->exprType() != INT_EXPR) {
1218 schoenebeck 2888 PARSE_ERR(@3, (String("Right operand of modulo operator must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1219 schoenebeck 2581 $$ = new IntLiteral(0);
1220     } else {
1221 schoenebeck 3561 if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0))
1222     PARSE_ERR(@1, "Operands of modulo operator must not use any unit.");
1223     if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0))
1224     PARSE_ERR(@3, "Operands of modulo operator must not use any unit.");
1225 schoenebeck 2581 $$ = new Mod(lhs,rhs);
1226     }
1227     }
1228    
1229     %%
1230    
1231     void InstrScript_error(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* err) {
1232     //fprintf(stderr, "%d: %s\n", locp->first_line, err);
1233 schoenebeck 2889 context->addErr(locp->first_line, locp->last_line, locp->first_column+1, locp->last_column+1, err);
1234 schoenebeck 2581 }
1235    
1236     void InstrScript_warning(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* txt) {
1237     //fprintf(stderr, "WRN %d: %s\n", locp->first_line, txt);
1238 schoenebeck 2889 context->addWrn(locp->first_line, locp->last_line, locp->first_column+1, locp->last_column+1, txt);
1239 schoenebeck 2581 }
1240 schoenebeck 3008
1241     /// Custom implementation of yytnamerr() to ensure quotation is always stripped from token names before printing them to error messages.
1242     int InstrScript_tnamerr(char* yyres, const char* yystr) {
1243     if (*yystr == '"') {
1244     int yyn = 0;
1245     char const *yyp = yystr;
1246     for (;;)
1247     switch (*++yyp)
1248     {
1249     /*
1250     case '\'':
1251     case ',':
1252     goto do_not_strip_quotes;
1253    
1254     case '\\':
1255     if (*++yyp != '\\')
1256     goto do_not_strip_quotes;
1257     */
1258     /* Fall through. */
1259     default:
1260     if (yyres)
1261     yyres[yyn] = *yyp;
1262     yyn++;
1263     break;
1264    
1265     case '"':
1266     if (yyres)
1267     yyres[yyn] = '\0';
1268     return yyn;
1269     }
1270 schoenebeck 3034 /*
1271 schoenebeck 3008 do_not_strip_quotes: ;
1272 schoenebeck 3034 */
1273 schoenebeck 3008 }
1274    
1275     if (! yyres)
1276 schoenebeck 3054 return (int) yystrlen (yystr);
1277 schoenebeck 3008
1278 schoenebeck 3054 return int( yystpcpy (yyres, yystr) - yyres );
1279 schoenebeck 3008 }

  ViewVC Help
Powered by ViewVC