~ubuntu-branches/ubuntu/lucid/structure-synth/lucid

« back to all changes in this revision

Viewing changes to StructureSynth/Parser/EisenParser.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Miriam Ruiz
  • Date: 2009-04-13 13:28:45 UTC
  • Revision ID: james.westby@ubuntu.com-20090413132845-d7d42t4llxjxq0ez
Tags: upstream-0.9
ImportĀ upstreamĀ versionĀ 0.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "EisenParser.h"
 
2
 
 
3
#include "../../SyntopiaCore/Logging/Logging.h"
 
4
#include "../Model/CustomRule.h"
 
5
 
 
6
#include <QColor>
 
7
 
 
8
using namespace SyntopiaCore::Logging;
 
9
using namespace StructureSynth::Model;
 
10
 
 
11
namespace StructureSynth {
 
12
        namespace Parser {      
 
13
                
 
14
                /*
 
15
                        EISENSCRIPT
 
16
                        -----------
 
17
 
 
18
                        EBNF:
 
19
                        -----
 
20
 
 
21
                        program = { set | rule } ;
 
22
                        rule = 'RULE' ,  rule_name, { rule_modifier } , '{', { set | action } , '}' ;
 
23
                        rule_modifier = { 'MAXDEPTH' integer | WEIGHT float }
 
24
                        action = transformation rule_ref ;
 
25
                        set = 'SET'  , var_name , string ;
 
26
 
 
27
                        'rule_ref', 'var_name', and 'string' are text strings with a reasonable set of allowed characters.
 
28
 
 
29
                        Example:
 
30
                        --------
 
31
 
 
32
                        //
 
33
                        //      C++ style multiline comments are allowed.
 
34
                        //  A pre-processor strips comments, and imports '#include's
 
35
                        //
 
36
                        #include "../basicstuff.es"
 
37
                        SET BackgroundColor = #F00  // All 'SET' commands outside the scope of a rule are executed at startup.
 
38
 
 
39
                        RULE core {
 
40
                                r1 
 
41
                        }
 
42
 
 
43
                        RULE r1 5 {
 
44
                        }
 
45
 
 
46
                        RULE r2 1 {
 
47
                        }
 
48
                */
 
49
 
 
50
 
 
51
                EisenParser::EisenParser(Tokenizer* tokenizer) : tokenizer(tokenizer) {
 
52
                };
 
53
 
 
54
                EisenParser::~EisenParser() {
 
55
                };
 
56
 
 
57
 
 
58
                void EisenParser::getSymbol() {
 
59
                        symbol = tokenizer->getSymbol();
 
60
                };
 
61
 
 
62
                bool EisenParser::accept(Symbol::SymbolType st) {
 
63
                        if (symbol.type == st) {
 
64
                                getSymbol();
 
65
                                return true;
 
66
                        }
 
67
                        return false;
 
68
                }
 
69
 
 
70
                void EisenParser::ruleModifierList(CustomRule* customRule) {
 
71
                        while (symbol.type == Symbol::Operator) { 
 
72
                                if (symbol.text == "weight") {
 
73
                                        getSymbol();
 
74
                                        double param = symbol.getNumerical();
 
75
                                        if (!accept(Symbol::Number)) {
 
76
                                                throw (ParseError("Rule modifier 'weight' expected numerical argument. Found: " + symbol.text, symbol.pos));
 
77
                                        }
 
78
                                        customRule->setWeight(param);
 
79
 
 
80
                                } else if (symbol.text == "maxdepth") {
 
81
                                        getSymbol();
 
82
                                        int param = (int)symbol.getNumerical();
 
83
                                        if (!symbol.isInteger || !accept(Symbol::Number)) {
 
84
                                                throw (ParseError("Rule modifier 'maxdepth' expected integer argument. Found: " + symbol.text, symbol.pos));
 
85
                                        }
 
86
                                        customRule->setMaxDepth(param);
 
87
 
 
88
                                        if (symbol.type == Symbol::MoreThan) {
 
89
                                                getSymbol();
 
90
                                                QString ruleName = symbol.text;
 
91
                                                if (!accept(Symbol::UserString)) throw (ParseError("After maxdepth retirement operator a rule name is expected. Found: " + symbol.text, symbol.pos));
 
92
                                                customRule->setRetirementRule(ruleName);
 
93
                                        }
 
94
                                } else {
 
95
                                        throw (ParseError("In rule modifier list: expected maxdepth or weight. Found: " + symbol.text, symbol.pos));
 
96
                                }
 
97
                        }
 
98
 
 
99
                        if (!symbol.type == Symbol::LeftBracket) {
 
100
                                throw (ParseError("After rule modifier list: expected a left bracket. Found: " + symbol.text, symbol.pos));
 
101
                        }
 
102
                }
 
103
 
 
104
                Rule* EisenParser::rule() {
 
105
                        // rule = 'RULE' ,  rule_name, '{', { set | action }  , '}' ;
 
106
                
 
107
                        if (!accept(Symbol::Rule)) throw (ParseError("Unexpected: trying to parse Rule not starting with rule identifier. Found: " + symbol.text, symbol.pos));
 
108
                        
 
109
                        QString ruleName = symbol.text;
 
110
                        if (!accept(Symbol::UserString)) throw (ParseError("After rule identifier a rule name is expected. Found: " + symbol.text, symbol.pos));
 
111
                        CustomRule* customRule = new CustomRule(ruleName);
 
112
 
 
113
                        if (symbol.type != Symbol::LeftBracket) {
 
114
                                // This must be a rule_modifier list.
 
115
                                ruleModifierList(customRule);
 
116
                        }
 
117
 
 
118
 
 
119
                        if (!accept(Symbol::LeftBracket)) throw (ParseError("After rule name a left bracket is expected. Found: " + symbol.text, symbol.pos));
 
120
                                
 
121
                        // TODO: implement rest of types:
 
122
                        // Possible actions:
 
123
                        //   SET something = something
 
124
                        //   rulename
 
125
                        //   { yaw 20 size 0.1 } rulename
 
126
                        //   20 * { forward 10 } rulename
 
127
                        while (symbol.type == Symbol::LeftBracket || symbol.type == Symbol::UserString ||
 
128
                                symbol.type == Symbol::Number || symbol.type == Symbol::Set) {    
 
129
                                
 
130
                                if (symbol.type == Symbol::Set) {
 
131
                                        Action a = setAction(); 
 
132
                                        customRule->appendAction(a);
 
133
                                } else {
 
134
                                        Action a = action(); 
 
135
                                        customRule->appendAction(a);
 
136
                                }
 
137
                        }
 
138
 
 
139
                        if (!accept(Symbol::RightBracket)) throw (ParseError("A rule definition must end with a right bracket. Found: "+symbol.text, symbol.pos));
 
140
 
 
141
                        return customRule;
 
142
                }
 
143
 
 
144
                double degreeToRad(double degrees) {
 
145
                        return degrees*3.14159265/180.0;
 
146
                }
 
147
 
 
148
                Transformation EisenParser::transformation() {
 
149
 
 
150
                        QString type = symbol.text;
 
151
                        if (!accept(Symbol::Operator)) throw (ParseError("Transformation: Expected transformation identifier (e.g. 'x' or 'rx'). Found: " + symbol.text, symbol.pos));
 
152
 
 
153
                        if (type == "x") {
 
154
                                double param = symbol.getNumerical();
 
155
                                if (!accept(Symbol::Number)) throw (ParseError("Transformation 'X' (X-axis translation): Expected numerical parameter. Found: " + symbol.text, symbol.pos));
 
156
                                return Transformation::createX(param);
 
157
                        } else if (type == "y") {
 
158
                                double param = symbol.getNumerical();
 
159
                                if (!accept(Symbol::Number)) throw (ParseError("Transformation 'Y' (Y-axis translation): Expected numerical parameter. Found: " + symbol.text, symbol.pos));
 
160
                                return Transformation::createY(param);
 
161
                        } else if (type == "z") {
 
162
                                double param = symbol.getNumerical();
 
163
                                if (!accept(Symbol::Number)) throw (ParseError("Transformation 'Z' (Z-axis translation): Expected numerical parameter. Found: " + symbol.text, symbol.pos));
 
164
                                return Transformation::createZ(param);
 
165
                        } else if (type == "rx") {
 
166
                                double param = symbol.getNumerical();
 
167
                                if (!accept(Symbol::Number)) throw (ParseError("Transformation 'RX' (X-axis rotation): Expected numerical parameter. Found: " + symbol.text, symbol.pos));
 
168
                                return Transformation::createRX(degreeToRad(param));
 
169
                        } else if (type == "ry") {
 
170
                                double param = symbol.getNumerical();
 
171
                                if (!accept(Symbol::Number)) throw (ParseError("Transformation 'RY' (Y-axis rotation): Expected numerical parameter. Found: " + symbol.text, symbol.pos));
 
172
                                return Transformation::createRY(degreeToRad(param));
 
173
                        } else if (type == "rz") {
 
174
                                double param = symbol.getNumerical();
 
175
                                if (!accept(Symbol::Number)) throw (ParseError("Transformation 'RZ' (Z-axis rotation): Expected numerical parameter. Found: " + symbol.text, symbol.pos));
 
176
                                return Transformation::createRZ(degreeToRad(param));
 
177
                        } else if (type == "hue") {
 
178
                                double param = symbol.getNumerical();
 
179
                                if (!accept(Symbol::Number)) throw (ParseError("Transformation 'hue': Expected numerical parameter. Found: " + symbol.text, symbol.pos));
 
180
                                return Transformation::createHSV(param, 1,1,1);
 
181
                        } else if (type == "sat") {
 
182
                                double param = symbol.getNumerical();
 
183
                                if (!accept(Symbol::Number)) throw (ParseError("Transformation 'sat': Expected numerical parameter. Found: " + symbol.text, symbol.pos));
 
184
                                return Transformation::createHSV(0, param,1,1);
 
185
                        } else if (type == "brightness") {
 
186
                                double param = symbol.getNumerical();
 
187
                                if (!accept(Symbol::Number)) throw (ParseError("Transformation 'brightness': Expected numerical parameter. Found: " + symbol.text, symbol.pos));
 
188
                                return Transformation::createHSV(0, 1,param,1);
 
189
                        } else if (type == "color") {
 
190
                                QString param = symbol.text;
 
191
                                if (!QColor(param).isValid()) throw (ParseError("Transformation 'color': Expected a valid color. Found: " + symbol.text, symbol.pos));
 
192
                                getSymbol();
 
193
                                return Transformation::createColor(param);
 
194
                        } else if (type == "alpha") {
 
195
                                double param = symbol.getNumerical();
 
196
                                if (!accept(Symbol::Number)) throw (ParseError("Transformation 'alpha': Expected numerical parameter. Found: " + symbol.text, symbol.pos));
 
197
                                return Transformation::createHSV(0, 1,1,param);
 
198
                        } else if (type == "matrix") {
 
199
                                QVector<double> ds;
 
200
                                for (unsigned int i = 0; i < 9; i++) {
 
201
                                        double param = symbol.getNumerical();
 
202
                                        if (!accept(Symbol::Number)) throw (ParseError("Transformation 'matrix': Expected nine (9) parameters. Found: " + symbol.text, symbol.pos));
 
203
                                        ds.append(param);
 
204
                                }
 
205
                                return Transformation::createMatrix(ds);
 
206
                        } else if (type == "s") {
 
207
                                double param = symbol.getNumerical();
 
208
                                if (!accept(Symbol::Number)) throw (ParseError("Transformation 'S' (size): Expected numerical parameter. Found: " + symbol.text, symbol.pos));
 
209
                                
 
210
                                if (symbol.type == Symbol::Number) {
 
211
                                        double param2 = symbol.getNumerical();
 
212
                                        getSymbol();
 
213
                                        double param3 = symbol.getNumerical();
 
214
                                        if (!accept(Symbol::Number)) throw (ParseError("Transformation 'S' (size): Expected third numerical parameter. Found: " + symbol.text, symbol.pos));
 
215
                                        return Transformation::createScale(param,param2,param3);
 
216
                                }
 
217
                                return Transformation::createScale(param,param,param);
 
218
                        } else if (type == "fx") {
 
219
                                return Transformation::createScale(-1,1,1);
 
220
                        } else if (type == "fy") {
 
221
                                return Transformation::createScale(1,-1,1);
 
222
                        } else if (type == "fz") {
 
223
                                return Transformation::createScale(1,1,-1);
 
224
                        } else {
 
225
                                throw (ParseError("Unknown transformation type: " + type, symbol.pos));
 
226
                        }
 
227
                }
 
228
 
 
229
                Transformation EisenParser::transformationList() {
 
230
                        // A transformationlist is something like: 
 
231
                        // { x 23 rx 23 }
 
232
 
 
233
                        Transformation t;
 
234
 
 
235
                        if (!accept(Symbol::LeftBracket)) throw (ParseError("Transformation List: Expected a left bracket. Found: " + symbol.text, symbol.pos));
 
236
 
 
237
                        while (symbol.type == Symbol::Operator) {    
 
238
                                t.append(transformation());
 
239
                        }
 
240
 
 
241
                        if (!accept(Symbol::RightBracket)) throw (ParseError("Transformation List: Expected a right bracket or an operator. Found: " + symbol.text, symbol.pos));
 
242
 
 
243
                        return t;
 
244
                }
 
245
 
 
246
                Action EisenParser::action() {
 
247
                        // There are 3 types of action statements:
 
248
                        //  { rx 20 ry 30 rz 20 } rulename
 
249
                        //  rulename
 
250
                        //  20 * { x 10 } 10 * { y 10 } rulename
 
251
                        
 
252
                        if (symbol.type == Symbol::LeftBracket) {
 
253
                                Transformation t = transformationList();
 
254
                                QString ruleName = symbol.text.trimmed();
 
255
                                if (!accept(Symbol::UserString)) throw (ParseError("Expected a rule name after the transformation list. Found: " + symbol.text, symbol.pos));
 
256
                                return Action(t, ruleName);
 
257
                        } else if (symbol.type == Symbol::UserString) {
 
258
                                QString ruleName = symbol.text.trimmed();
 
259
                                accept(Symbol::UserString);
 
260
                                return Action(ruleName);
 
261
                        } else if (symbol.type == Symbol::Number) {
 
262
 
 
263
                                Action action;
 
264
 
 
265
                                while (symbol.type == Symbol::Number) {
 
266
                                        // number of loops...
 
267
                                        if (!symbol.isInteger) throw (ParseError("Expected an integer count in the transformation loop. Found: " + symbol.text, symbol.pos));
 
268
                                        int count = symbol.intValue;
 
269
                                        getSymbol(); 
 
270
 
 
271
                                        // '*'
 
272
                                        if (!accept(Symbol::Multiply)) throw (ParseError("Expected a '*' after the transformation count. Found: " + symbol.text, symbol.pos));
 
273
                                        
 
274
                                        // transformation list
 
275
                                        Transformation t = transformationList();
 
276
                                        action.addTransformationLoop(TransformationLoop(count, t));
 
277
                                }
 
278
                                
 
279
                                // Rule reference
 
280
                                QString ruleName = symbol.text.trimmed();
 
281
                                if (!accept(Symbol::UserString)) throw (ParseError("Expected a rule name or a new loop after the transformation list. Found: " + symbol.text, symbol.pos));
 
282
                                action.setRule(ruleName);
 
283
 
 
284
                                return action;
 
285
 
 
286
                        } else {
 
287
                                throw (ParseError("A rule action must start with either a number, a rule name or a left bracket. Found: "+symbol.text, symbol.pos));    
 
288
                        }
 
289
                }
 
290
 
 
291
                Action EisenParser::setAction() {
 
292
                                accept(Symbol::Set);
 
293
                                
 
294
                                QString key = symbol.text;
 
295
                                if (symbol.type == Symbol::Operator && key == "maxdepth") {
 
296
                                        getSymbol();
 
297
                                } else if (!accept(Symbol::UserString)) throw (ParseError("Expected a valid setting name. Found: " + symbol.text, symbol.pos));
 
298
                                QString value = symbol.text; 
 
299
                                getSymbol(); // We will accept everything here! 
 
300
                                
 
301
                                return Action(key,value);
 
302
                }
 
303
 
 
304
                RuleSet* EisenParser::ruleset() {
 
305
                        RuleSet*  rs = new RuleSet();
 
306
                        getSymbol();
 
307
        
 
308
                        while (symbol.type == Symbol::Rule || symbol.type == Symbol::Set
 
309
                                    || symbol.type == Symbol::LeftBracket || symbol.type == Symbol::UserString || symbol.type == Symbol::Number) {    
 
310
                                if (symbol.type == Symbol::Rule) {
 
311
                                        Rule* r = rule(); 
 
312
                                        rs->addRule(r);
 
313
                                } else if (symbol.type == Symbol::Set) {
 
314
                                        Action a = setAction(); 
 
315
                                        rs->getTopLevelRule()->appendAction(a);
 
316
                                } else {
 
317
                                        Action a = action(); 
 
318
                                        rs->getTopLevelRule()->appendAction(a);
 
319
                                }
 
320
                        }
 
321
 
 
322
                        if (!accept(Symbol::End)) throw (ParseError("Unexpected symbol found. At this scope only RULE and SET statements are allowed. Found: " + symbol.text, symbol.pos));
 
323
                        return rs;
 
324
                }
 
325
 
 
326
 
 
327
                RuleSet* EisenParser::parseRuleset() {
 
328
                        return ruleset();
 
329
                }
 
330
        }
 
331
}
 
332