~sladen/openbve/openbve2

« back to all changes in this revision

Viewing changes to Route.CsvRw/Parser.Expressions.cs

  • Committer: Paul Sladen
  • Author(s): Michelle Boucquemont
  • Date: 2010-03-17 04:04:44 UTC
  • Revision ID: git-v1:c9050dde4c55fe2b9c257080653cee1a07c91303
import openbve2.zip (2010-03-14)

You will find a settings.cfg file where you can configure a series of
options and also which route or object to load. The options are
explained briefly via the comments in the settings.cfg file itself.
Select any route or object you want, but mind the following limitations:

* Background images and fog are not yet supported. Only a background
  color will be shown.
* Animated objects are not yet supported. This includes signals. These
  objects are not shown at all.
* Glow is not yet supported. All objects using glow will always show at
  full intensity instead of fading in.
* The legacy visibility system (where objects are disposed of as soon as
  the CSV/RW block the object was placed in has been passed by the camera)
  is not yet supported, only the new 2D grid is.

In-game, you can use the arrow, the WASD and the PageUp and PageDown keys to move and rotate around. Hold down the shift, control or alt key for faster movement. There is no way for you to jump to specific "track positions" as the new program does not have something like them internally. Also, you cannot jump to stations in any way at the moment. The initial position of the camera is the first stop point, though.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
using System;
 
2
using System.Globalization;
 
3
 
 
4
namespace Plugin {
 
5
        internal static partial class Parser {
 
6
                
 
7
                // --- classes ---
 
8
                
 
9
                /// <summary>Represents the type of an expression.</summary>
 
10
                internal enum ExpressionType {
 
11
                        /// <summary>The type of the expression has not been determined yet.</summary>
 
12
                        Unknown = 0,
 
13
                        /// <summary>The expression is a track position.</summary>
 
14
                        Position = 1,
 
15
                        /// <summary>The expression is from a namespace other than Track.</summary>
 
16
                        General = 2,
 
17
                        /// <summary>The expression is from the Track namespace.</summary>
 
18
                        Track = 3
 
19
                }
 
20
                
 
21
                /// <summary>Represents an expression consisting of a command, and optionally, indices, a suffix or arguments.</summary>
 
22
                internal class Expression {
 
23
                        // members
 
24
                        /// <summary>The file in which the expression occured.</summary>
 
25
                        internal string File;
 
26
                        /// <summary>The zero-based row at which the expression occured.</summary>
 
27
                        internal int Row;
 
28
                        /// <summary>The zero-based column at which the expression occured.</summary>
 
29
                        internal int Column;
 
30
                        /// <summary>The name of the command as it appears in the file.</summary>
 
31
                        internal string OriginalCommand;
 
32
                        /// <summary>The name of the command in CSV-equivalent form.</summary>
 
33
                        internal string CsvEquivalentCommand;
 
34
                        /// <summary>An array of indices. This field may be a null reference.</summary>
 
35
                        internal string[] Indices;
 
36
                        /// <summary>The suffix to the command. This field may be a null reference.</summary>
 
37
                        internal string Suffix;
 
38
                        /// <summary>An array of arguments. This field may be a null reference.</summary>
 
39
                        internal string[] Arguments;
 
40
                        /// <summary>The type of expression.</summary>
 
41
                        internal ExpressionType Type;
 
42
                        /// <summary>For commands from the Track namespace, this stores the associated track position in text form.</summary>
 
43
                        internal string PositionString;
 
44
                        /// <summary>For commands from the Track namespace, this stores the associated track position as a number.</summary>
 
45
                        internal double Position;
 
46
                        // constructors
 
47
                        /// <summary>Creates a new instance of this class.</summary>
 
48
                        /// <param name="file">The file in which the expression occured.</param>
 
49
                        /// <param name="row">The zero-based row at which the expression occured.</param>
 
50
                        /// <param name="column">The zero-based column at which the expression occured.</param>
 
51
                        /// <param name="command">The name of the command.</param>
 
52
                        /// <param name="indices">An array of indices. This field may be a null reference.</param>
 
53
                        /// <param name="suffix">The suffix to the command. This field may be a null reference.</param>
 
54
                        /// <param name="arguments">An array of arguments. This field may be a null reference.</param>
 
55
                        /// <remarks>This constructor may only be used for CSV routes.</remarks>
 
56
                        internal Expression(string file, int row, int column, string command, string[] indices, string suffix, string[] arguments) {
 
57
                                this.File = file;
 
58
                                this.Row = row;
 
59
                                this.Column = column;
 
60
                                this.OriginalCommand = command;
 
61
                                this.CsvEquivalentCommand = command;
 
62
                                this.Indices = indices;
 
63
                                this.Suffix = suffix;
 
64
                                this.Arguments = arguments;
 
65
                                this.PositionString = null;
 
66
                                this.Position = 0.0;
 
67
                        }
 
68
                        /// <summary>Creates a new instance of this class.</summary>
 
69
                        /// <param name="file">The file in which the expression occured.</param>
 
70
                        /// <param name="row">The zero-based row at which the expression occured.</param>
 
71
                        /// <param name="column">The zero-based column at which the expression occured.</param>
 
72
                        /// <param name="originalCommand">The name of the command as it appears in the file.</param>
 
73
                        /// <param name="csvEquivalentCommand">The name of the command in CSV-equivalent form.</param>
 
74
                        /// <param name="indices">An array of indices. This field may be a null reference.</param>
 
75
                        /// <param name="suffix">The suffix to the command. This field may be a null reference.</param>
 
76
                        /// <param name="arguments">An array of arguments. This field may be a null reference.</param>
 
77
                        internal Expression(string file, int row, int column, string originalCommand, string csvEquivalentCommand, string[] indices, string suffix, string[] arguments) {
 
78
                                this.File = file;
 
79
                                this.Row = row;
 
80
                                this.Column = column;
 
81
                                this.OriginalCommand = originalCommand;
 
82
                                this.CsvEquivalentCommand = csvEquivalentCommand;
 
83
                                this.Indices = indices;
 
84
                                this.Suffix = suffix;
 
85
                                this.Arguments = arguments;
 
86
                                this.PositionString = null;
 
87
                                this.Position = 0.0;
 
88
                        }
 
89
                }
 
90
                
 
91
                
 
92
                // --- functions ---
 
93
                
 
94
                /// <summary>Takes a cell from a CSV file and splits it into command, indices, suffix and arguments.</summary>
 
95
                /// <param name="file">The path to the route file.</param>
 
96
                /// <param name="row">The zero-based row at which the cell is stored.</param>
 
97
                /// <param name="column">The zero-based column at which the cell is stored.</param>
 
98
                /// <param name="cell">The content of the trimmed cell.</param>
 
99
                /// <param name="with">The last argument to the With command.</param>
 
100
                /// <param name="expression">Receives the expression on success.</param>
 
101
                /// <returns>Whether an expression could be extracted.</returns>
 
102
                private static bool GetExpressionFromCsvCell(string file, int row, int column, string cell, ref string with, out Expression expression) {
 
103
                        /*
 
104
                         * The following valid syntax variations are detected by this algorithm:
 
105
                         * 
 
106
                         * command (indexSequence) .suffix (argumentSequence)     command, indices, suffix, arguments
 
107
                         * command (indexSequence) .suffix argumentSequence       command, indices, suffix, arguments
 
108
                         * command (indexSequence) .suffix                        command, indices, suffix
 
109
                         * command (indexSequence) (argumentSequence)             command, indices, arguments
 
110
                         * command (indexSequence) argumentSequence               command, indices, arguments
 
111
                         * command (argumentSequence)                             command, arguments
 
112
                         * command argumentSequence                               command, arguments
 
113
                         * command                                                command only
 
114
                         * 
 
115
                         * Non-valid syntax is reported but still processed for the best of it.
 
116
                         * */
 
117
                        if (cell.Length == 0) {
 
118
                                /*
 
119
                                 * The cell is empty.
 
120
                                 * */
 
121
                                expression = null;
 
122
                                return false;
 
123
                        } else if (cell[0] == '.') {
 
124
                                /*
 
125
                                 * The cell starts with a period. Append it to the
 
126
                                 * argument to the last With command. If no With
 
127
                                 * command was used before, this is invalid.
 
128
                                 * */
 
129
                                if (with == null) {
 
130
                                        IO.ReportInvalidData(file, row, column, "A With statement is required before commands starting with a period can be used.");
 
131
                                        expression = null;
 
132
                                        return false;
 
133
                                } else {
 
134
                                        cell = with + cell;
 
135
                                }
 
136
                        }
 
137
                        /*
 
138
                         * Find the first character that is not part of
 
139
                         * the command and not part of whitespaces
 
140
                         * following the command.
 
141
                         * */
 
142
                        int firstNonCommandNonWhitespace;
 
143
                        for (firstNonCommandNonWhitespace = 0; firstNonCommandNonWhitespace < cell.Length; firstNonCommandNonWhitespace++) {
 
144
                                if (cell[firstNonCommandNonWhitespace] == '(') {
 
145
                                        break;
 
146
                                } else if (char.IsWhiteSpace(cell[firstNonCommandNonWhitespace])) {
 
147
                                        firstNonCommandNonWhitespace++;
 
148
                                        while (true) {
 
149
                                                if (!char.IsWhiteSpace(cell[firstNonCommandNonWhitespace])) {
 
150
                                                        break;
 
151
                                                } else {
 
152
                                                        firstNonCommandNonWhitespace++;
 
153
                                                }
 
154
                                        }
 
155
                                        break;
 
156
                                }
 
157
                        }
 
158
                        if (firstNonCommandNonWhitespace == cell.Length) {
 
159
                                /*
 
160
                                 * Neither a whitespace or an opening paranthesis was found.
 
161
                                 * The entire cell is just the command.
 
162
                                 * 
 
163
                                 * command
 
164
                                 * */
 
165
                                expression = new Expression(file, row, column, cell, null, null, null);
 
166
                        } else if (cell[firstNonCommandNonWhitespace] == '(') {
 
167
                                /*
 
168
                                 * An opening paranthesis was found. This could mark
 
169
                                 * the start of indices or of arguments. Let's find
 
170
                                 * the matching closing paranthesis first.
 
171
                                 * */
 
172
                                string command = cell.Substring(0, firstNonCommandNonWhitespace).TrimEnd();
 
173
                                int closingParanthesis = cell.IndexOf(')', firstNonCommandNonWhitespace + 1);
 
174
                                if (closingParanthesis != -1) {
 
175
                                        /*
 
176
                                         * The closing paranthesis was found. The text in-between
 
177
                                         * the parantheses could be indices or arguments. If the
 
178
                                         * closing paranthesis is at the end of the cell, the
 
179
                                         * text is the arguments, otherwise, the indices.
 
180
                                         * 
 
181
                                         * command (indexSequence) .suffix (argumentSequence)
 
182
                                         * command (indexSequence) .suffix argumentSequence
 
183
                                         * command (indexSequence) .suffix
 
184
                                         * command (indexSequence) (argumentSequence)
 
185
                                         * command (indexSequence) argumentSequence
 
186
                                         * command (argumentSequence)
 
187
                                         * */
 
188
                                        if (closingParanthesis == cell.Length - 1) {
 
189
                                                /*
 
190
                                                 * The closing paranthesis is at the end of the cell.
 
191
                                                 * The text in-between the parantheses is the
 
192
                                                 * arguments. Indices or suffixes do not occur.
 
193
                                                 * If the argument sequence contains further
 
194
                                                 * opening parantheses, this is invalid.
 
195
                                                 * 
 
196
                                                 * command (argumentSequence)
 
197
                                                 * */
 
198
                                                string argumentSequence = cell.Substring(firstNonCommandNonWhitespace + 1, closingParanthesis - firstNonCommandNonWhitespace - 1);
 
199
                                                if (argumentSequence.IndexOf('(') != -1) {
 
200
                                                        IO.ReportInvalidData(file, row, column, "The argument sequence contains an invalid opening paranthesis.");
 
201
                                                }
 
202
                                                string[] arguments = argumentSequence.Split(';');
 
203
                                                for (int k = 0; k < arguments.Length; k++) {
 
204
                                                        arguments[k] = arguments[k].Trim();
 
205
                                                }
 
206
                                                expression = new Expression(file, row, column, command, null, null, arguments);
 
207
                                        } else {
 
208
                                                /*
 
209
                                                 * The closing paranthesis is followed by something.
 
210
                                                 * The text in-between the parantheses is the indices.
 
211
                                                 * If the index sequence contains further opening
 
212
                                                 * parantheses, this is invalid.
 
213
                                                 * 
 
214
                                                 * command (indexSequence) .suffix (argumentSequence)
 
215
                                                 * command (indexSequence) .suffix argumentSequence
 
216
                                                 * command (indexSequence) .suffix
 
217
                                                 * command (indexSequence) (argumentSequence)
 
218
                                                 * command (indexSequence) argumentSequence
 
219
                                                 * */
 
220
                                                string indexSequence = cell.Substring(firstNonCommandNonWhitespace + 1, closingParanthesis - firstNonCommandNonWhitespace - 1);
 
221
                                                if (indexSequence.IndexOf('(') != -1) {
 
222
                                                        IO.ReportInvalidData(file, row, column, "The index sequence contains an invalid opening paranthesis.");
 
223
                                                }
 
224
                                                string[] indices = indexSequence.Split(';');
 
225
                                                for (int k = 0; k < indices.Length; k++) {
 
226
                                                        indices[k] = indices[k].Trim();
 
227
                                                }
 
228
                                                /*
 
229
                                                 * If the first non-whitespace character after the
 
230
                                                 * closing paranthesis is a period, this marks the
 
231
                                                 * start of a suffix, otherwise, of arguments.
 
232
                                                 * */
 
233
                                                int firstNonWhitespace;
 
234
                                                for (firstNonWhitespace = closingParanthesis + 1; firstNonWhitespace < cell.Length; firstNonWhitespace++) {
 
235
                                                        if (!char.IsWhiteSpace(cell[firstNonWhitespace])) {
 
236
                                                                break;
 
237
                                                        }
 
238
                                                }
 
239
                                                if (cell[firstNonWhitespace] == '.') {
 
240
                                                        /*
 
241
                                                         * The first non-whitespace character is a period.
 
242
                                                         * This marks the start of a suffix. The suffix
 
243
                                                         * terminates at the first whitespace or opening
 
244
                                                         * paranthesis. If not present, the rest of the
 
245
                                                         * cell is just the suffix.
 
246
                                                         * 
 
247
                                                         * command (indexSequence) .suffix (argumentSequence)
 
248
                                                         * command (indexSequence) .suffix argumentSequence
 
249
                                                         * command (indexSequence) .suffix
 
250
                                                         * */
 
251
                                                        int firstNonSuffix;
 
252
                                                        for (firstNonSuffix = firstNonWhitespace + 1; firstNonSuffix < cell.Length; firstNonSuffix++) {
 
253
                                                                if (cell[firstNonSuffix] == '(' || char.IsWhiteSpace(cell[firstNonSuffix])) {
 
254
                                                                        break;
 
255
                                                                }
 
256
                                                        }
 
257
                                                        if (firstNonSuffix == cell.Length) {
 
258
                                                                /*
 
259
                                                                 * No whitespace or opening parantheses was found.
 
260
                                                                 * The rest of the cell is just the suffix. If
 
261
                                                                 * the suffix contains closing parantheses, this
 
262
                                                                 * is invalid. If the suffix ends in a period,
 
263
                                                                 * this is invalid as well.
 
264
                                                                 * 
 
265
                                                                 * command (indexSequence) .suffix
 
266
                                                                 * */
 
267
                                                                string suffix = cell.Substring(firstNonWhitespace);
 
268
                                                                if (suffix.IndexOf(')') != -1) {
 
269
                                                                        IO.ReportInvalidData(file, row, column, "The suffix contains an invalid closing paranthesis.");
 
270
                                                                } else if (suffix[suffix.Length - 1] == '.') {
 
271
                                                                        IO.ReportInvalidData(file, row, column, "The suffix must not end in a period.");
 
272
                                                                }
 
273
                                                                expression = new Expression(file, row, column, command, indices, suffix, null);
 
274
                                                        } else {
 
275
                                                                /*
 
276
                                                                 * A whitespace or opening paranthesis was found.
 
277
                                                                 * This marks the end of the suffix and the start
 
278
                                                                 * of arguments. The arguments may be enclosed
 
279
                                                                 * by parantheses. Other occurences of parantheses
 
280
                                                                 * are invalid.
 
281
                                                                 * 
 
282
                                                                 * command (indexSequence) .suffix (argumentSequence)
 
283
                                                                 * command (indexSequence) .suffix argumentSequence
 
284
                                                                 * */
 
285
                                                                string suffix = cell.Substring(firstNonWhitespace, firstNonSuffix - firstNonWhitespace);
 
286
                                                                string argumentSequence = cell.Substring(firstNonSuffix).TrimStart();
 
287
                                                                if (argumentSequence[0] == '(' & argumentSequence[argumentSequence.Length - 1] == ')') {
 
288
                                                                        argumentSequence = argumentSequence.Substring(1, argumentSequence.Length - 2);
 
289
                                                                        if (argumentSequence.IndexOf('(') != -1) {
 
290
                                                                                IO.ReportInvalidData(file, row, column, "The argument sequence contains an invalid opening paranthesis.");
 
291
                                                                        } else if (argumentSequence.IndexOf(')') != -1) {
 
292
                                                                                IO.ReportInvalidData(file, row, column, "The argument sequence contains an invalid closing paranthesis.");
 
293
                                                                        }
 
294
                                                                } else if (argumentSequence[0] == '(') {
 
295
                                                                        IO.ReportInvalidData(file, row, column, "The argument sequence contains an invalid opening paranthesis.");
 
296
                                                                        argumentSequence = argumentSequence.Substring(1);
 
297
                                                                } else if (argumentSequence[argumentSequence.Length - 1] == ')') {
 
298
                                                                        IO.ReportInvalidData(file, row, column, "The argument sequence contains an invalid closing paranthesis.");
 
299
                                                                        argumentSequence = argumentSequence.Substring(0, argumentSequence.Length - 1);
 
300
                                                                }
 
301
                                                                string[] arguments = argumentSequence.Split(';');
 
302
                                                                for (int k = 0; k < arguments.Length; k++) {
 
303
                                                                        arguments[k] = arguments[k].Trim();
 
304
                                                                }
 
305
                                                                expression = new Expression(file, row, column, command, indices, suffix, arguments);
 
306
                                                        }
 
307
                                                } else {
 
308
                                                        /*
 
309
                                                         * The first non-whitespace character is not a period.
 
310
                                                         * This marks the start of arguments. The arguments
 
311
                                                         * may be enclosed by parantheses. Other occurences
 
312
                                                         * of parantheses are invalid.
 
313
                                                         * 
 
314
                                                         * command (indexSequence) (argumentSequence)
 
315
                                                         * command (indexSequence) argumentSequence
 
316
                                                         * */
 
317
                                                        string argumentSequence = cell.Substring(closingParanthesis + 1).TrimStart();
 
318
                                                        if (argumentSequence[0] == '(' & argumentSequence[argumentSequence.Length - 1] == ')') {
 
319
                                                                argumentSequence = argumentSequence.Substring(1, argumentSequence.Length - 2);
 
320
                                                                if (argumentSequence.IndexOf('(') != -1) {
 
321
                                                                        IO.ReportInvalidData(file, row, column, "The argument sequence contains an invalid opening paranthesis.");
 
322
                                                                } else if (argumentSequence.IndexOf(')') != -1) {
 
323
                                                                        IO.ReportInvalidData(file, row, column, "The argument sequence contains an invalid closing paranthesis.");
 
324
                                                                }
 
325
                                                        } else if (argumentSequence[0] == '(') {
 
326
                                                                IO.ReportInvalidData(file, row, column, "The argument sequence contains an invalid opening paranthesis.");
 
327
                                                                argumentSequence = argumentSequence.Substring(1);
 
328
                                                        } else if (argumentSequence[argumentSequence.Length - 1] == ')') {
 
329
                                                                IO.ReportInvalidData(file, row, column, "The argument sequence contains an invalid closing paranthesis.");
 
330
                                                                argumentSequence = argumentSequence.Substring(0, argumentSequence.Length - 1);
 
331
                                                        }
 
332
                                                        string[] arguments = argumentSequence.Split(';');
 
333
                                                        for (int k = 0; k < arguments.Length; k++) {
 
334
                                                                arguments[k] = arguments[k].Trim();
 
335
                                                        }
 
336
                                                        expression = new Expression(file, row, column, command, indices, null, arguments);
 
337
                                                }
 
338
                                        }
 
339
                                } else {
 
340
                                        /*
 
341
                                         * A closing paranthesis was not found. This
 
342
                                         * is invalid. Let's treat the text after the
 
343
                                         * opening paranthesis as arguments.
 
344
                                         * */
 
345
                                        IO.ReportInvalidData(file, row, column, "Missing closing paranthesis.");
 
346
                                        string argumentSequence = cell.Substring(firstNonCommandNonWhitespace + 1);
 
347
                                        string[] arguments = argumentSequence.Split(';');
 
348
                                        for (int k = 0; k < arguments.Length; k++) {
 
349
                                                arguments[k] = arguments[k].Trim();
 
350
                                        }
 
351
                                        expression = new Expression(file, row, column, command, null, null, arguments);
 
352
                                }
 
353
                        } else {
 
354
                                /*
 
355
                                 * Whitespace was found before any opening paranthesis.
 
356
                                 * The text following the whitespace is the arguments.
 
357
                                 * 
 
358
                                 * command argumentSequence
 
359
                                 * */
 
360
                                string command = cell.Substring(0, firstNonCommandNonWhitespace).TrimEnd();
 
361
                                string argumentSequence = cell.Substring(firstNonCommandNonWhitespace);
 
362
                                string[] arguments = argumentSequence.Split(';');
 
363
                                for (int k = 0; k < arguments.Length; k++) {
 
364
                                        arguments[k] = arguments[k].Trim();
 
365
                                }
 
366
                                expression = new Expression(file, row, column, command, null, null, arguments);
 
367
                        }
 
368
                        /*
 
369
                         * Now that we have the expression, check if it is
 
370
                         * a With command, and extract the argument to it
 
371
                         * if applicable.
 
372
                         * */
 
373
                        if (expression.CsvEquivalentCommand.Equals("With", StringComparison.OrdinalIgnoreCase)) {
 
374
                                if (expression.Arguments == null) {
 
375
                                        IO.ReportInvalidData(file, row, column, "The With statement must have exactly one argument.");
 
376
                                } else {
 
377
                                        if (expression.Indices != null | expression.Suffix != null | expression.Arguments.Length != 1) {
 
378
                                                IO.ReportInvalidData(file, row, column, "The With statement must not contain indices or a suffix, and must have exactly one argument.");
 
379
                                        }
 
380
                                        if (expression.Arguments[0][0] == '.' | expression.Arguments[0][expression.Arguments[0].Length - 1] == '.') {
 
381
                                                IO.ReportInvalidData(file, row, column, "The argument to the With statement must not start or end with a period.");
 
382
                                        } else {
 
383
                                                with = expression.Arguments[0];
 
384
                                        }
 
385
                                }
 
386
                                return false;
 
387
                        } else {
 
388
                                return true;
 
389
                        }
 
390
                }
 
391
                
 
392
                /// <summary>Takes a cell from an RW file and splits it into command, indices, suffix and arguments.</summary>
 
393
                /// <param name="file">The path to the route file.</param>
 
394
                /// <param name="row">The zero-based row at which the cell is stored.</param>
 
395
                /// <param name="column">The zero-based column at which the cell is stored.</param>
 
396
                /// <param name="cell">The content of the trimmed cell.</param>
 
397
                /// <param name="section">The last opened section.</param>
 
398
                /// <param name="expression">Receives the expression on success.</param>
 
399
                /// <returns>Whether an expression could be extracted.</returns>
 
400
                private static bool GetExpressionFromRwCell(string file, int row, int column, string cell, string section, out Expression expression) {
 
401
                        /*
 
402
                         * The following valid syntax variations are detected by this algorithm:
 
403
                         * 
 
404
                         * command (indexSequence) .suffix = argumentSequence     command, indices, suffix, arguments
 
405
                         * command (indexSequence) = argumentSequence             command, indices, arguments
 
406
                         * command = argumentSequence                             command, arguments
 
407
                         * 
 
408
                         * @ command (indexSequence) .suffix (argumentSequence)   command, indices, suffix, arguments
 
409
                         * @ command (indexSequence) (argumentSequence)           command, indices, arguments
 
410
                         * @ command (indexSequence) .suffix                      command, indices, suffix
 
411
                         * @ command (argumentSequence)                           command, arguments
 
412
                         * @ command                                              command only
 
413
                         * 
 
414
                         * The @ character is optional. Non-valid syntax is reported.
 
415
                         * 
 
416
                         * The syntax variations with the equals sign are not possible
 
417
                         * for the [Railway] section and are thus not considered.
 
418
                         * 
 
419
                         * The syntax variations without the equals sign are invalid
 
420
                         * when used outside the [Railway] section.
 
421
                         * */
 
422
                        if (cell.Length == 0) {
 
423
                                /*
 
424
                                 * The cell is empty.
 
425
                                 * */
 
426
                                expression = null;
 
427
                                return false;
 
428
                        } else {
 
429
                                /*
 
430
                                 * Check if the cell contains an equals sign that
 
431
                                 * determines the possible syntax variations, but
 
432
                                 * only if outside the [Railway] section.
 
433
                                 * */
 
434
                                int equals;
 
435
                                bool isRailwaySection = section.Equals("railway", StringComparison.OrdinalIgnoreCase);
 
436
                                if (isRailwaySection) {
 
437
                                        equals = -1;
 
438
                                } else {
 
439
                                        equals = cell.IndexOf('=');
 
440
                                }
 
441
                                if (equals >= 0) {
 
442
                                        /*
 
443
                                         * An equals sign was found. This means the argument
 
444
                                         * sequence will follow the equals sign. If the text
 
445
                                         * prior to the equals sign contains parantheses,
 
446
                                         * this marks the presence of indices.
 
447
                                         * 
 
448
                                         * command (indexSequence) .suffix = argumentSequence
 
449
                                         * command (indexSequence) = argumentSequence
 
450
                                         * command = argumentSequence
 
451
                                         * */
 
452
                                        string argumentSequence = cell.Substring(equals + 1).TrimStart();
 
453
                                        string[] arguments = argumentSequence.Split(',', ';');
 
454
                                        for (int k = 0; k < arguments.Length; k++) {
 
455
                                                arguments[k] = arguments[k].Trim();
 
456
                                        }
 
457
                                        string commandSequence = cell.Substring(0, equals).TrimEnd();
 
458
                                        int openingParanthesis = commandSequence.IndexOf('(');
 
459
                                        if (openingParanthesis >= 0) {
 
460
                                                /*
 
461
                                                 * An opening paranthesis was found.
 
462
                                                 * This marks the start of indices.
 
463
                                                 * Let's find the matching closing
 
464
                                                 * parantheses first.
 
465
                                                 * 
 
466
                                                 * command (indexSequence) .suffix = argumentSequence
 
467
                                                 * command (indexSequence) = argumentSequence
 
468
                                                 * */
 
469
                                                string originalCommand = commandSequence.Substring(0, openingParanthesis).TrimEnd();
 
470
                                                string csvEquivalentCommand = GetCsvEquivalentCommand(file, row, column, originalCommand, section, false);
 
471
                                                int closingParanthesis = commandSequence.IndexOf(')', openingParanthesis + 1);
 
472
                                                if (closingParanthesis >= 0) {
 
473
                                                        /*
 
474
                                                         * A closing paranthesis was found.
 
475
                                                         * */
 
476
                                                        string indexSequence = commandSequence.Substring(openingParanthesis + 1, closingParanthesis - openingParanthesis - 1);
 
477
                                                        if (indexSequence.IndexOf('(') != -1) {
 
478
                                                                IO.ReportInvalidData(file, row, column, "The index sequence contains an invalid opening paranthesis.");
 
479
                                                        }
 
480
                                                        string[] indices = indexSequence.Split(',', ';');
 
481
                                                        for (int k = 0; k < indices.Length; k++) {
 
482
                                                                indices[k] = indices[k].Trim();
 
483
                                                        }
 
484
                                                        if (closingParanthesis == commandSequence.Length - 1) {
 
485
                                                                /*
 
486
                                                                 * The closing paranthesis was found at the end
 
487
                                                                 * of the command sequence (just before the
 
488
                                                                 * equals sign). This means that there is
 
489
                                                                 * no suffix.
 
490
                                                                 * 
 
491
                                                                 * command (indexSequence) = argumentSequence
 
492
                                                                 * */
 
493
                                                                expression = new Expression(file, row, column, originalCommand, csvEquivalentCommand, indices, null, arguments);
 
494
                                                        } else {
 
495
                                                                /*
 
496
                                                                 * The closing paranthesis was found before
 
497
                                                                 * the end of the command sequence. This
 
498
                                                                 * means that the indices are followed by
 
499
                                                                 * a suffix. The suffix must start in a
 
500
                                                                 * period and must not end in a period.
 
501
                                                                 * 
 
502
                                                                 * command (indexSequence) .suffix = argumentSequence
 
503
                                                                 * */
 
504
                                                                string suffix = commandSequence.Substring(closingParanthesis + 1).TrimStart();
 
505
                                                                if (suffix.IndexOf('(') != -1) {
 
506
                                                                        IO.ReportInvalidData(file, row, column, "The suffix contains an invalid opening paranthesis.");
 
507
                                                                }
 
508
                                                                if (suffix[0] != '.' || suffix[suffix.Length - 1] == '.') {
 
509
                                                                        IO.ReportInvalidData(file, row, column, "The suffix must start with a period but must not end in a period.");
 
510
                                                                }
 
511
                                                                expression = new Expression(file, row, column, originalCommand, csvEquivalentCommand, indices, suffix, arguments);
 
512
                                                        }
 
513
                                                } else {
 
514
                                                        /*
 
515
                                                         * A closing paranthesis was not found. This
 
516
                                                         * is invalid. Let's treat the text after the
 
517
                                                         * opening paranthesis as indices.
 
518
                                                         * */
 
519
                                                        IO.ReportInvalidData(file, row, column, "Missing closing paranthesis.");
 
520
                                                        string indexSequence = commandSequence.Substring(openingParanthesis + 1).TrimStart();
 
521
                                                        string[] indices = indexSequence.Split(',', ';');
 
522
                                                        for (int k = 0; k < indices.Length; k++) {
 
523
                                                                indices[k] = indices[k].Trim();
 
524
                                                        }
 
525
                                                        expression = new Expression(file, row, column, originalCommand, csvEquivalentCommand, indices, null, arguments);
 
526
                                                }
 
527
                                        } else {
 
528
                                                /*
 
529
                                                 * An opening paranthesis was not found. There
 
530
                                                 * is only the command and the arguments.
 
531
                                                 * 
 
532
                                                 * command = argumentSequence
 
533
                                                 * */
 
534
                                                if (commandSequence.IndexOf(')') != -1) {
 
535
                                                        IO.ReportInvalidData(file, row, column, "The command contains an invalid closing paranthesis.");
 
536
                                                }
 
537
                                                string originalCommand = commandSequence;
 
538
                                                string csvEquivalentCommand = GetCsvEquivalentCommand(file, row, column, originalCommand, section, false);
 
539
                                                expression = new Expression(file, row, column, originalCommand, csvEquivalentCommand, null, null, arguments);
 
540
                                        }
 
541
                                } else {
 
542
                                        /*
 
543
                                         * No equals sign was found. If this situation is
 
544
                                         * encountered outside the [Railway] section, it
 
545
                                         * is invalid. Otherwise, now try to find an
 
546
                                         * an opening paranthesis.
 
547
                                         * 
 
548
                                         * @ command (indexSequence) .suffix (argumentSequence)
 
549
                                         * @ command (indexSequence) (argumentSequence)
 
550
                                         * @ command (indexSequence) .suffix
 
551
                                         * @ command (argumentSequence)
 
552
                                         * @ command
 
553
                                         * */
 
554
                                        if (!isRailwaySection) {
 
555
                                                IO.ReportInvalidData(file, row, column, "This syntax is not allowed outside the [Railway] section.");
 
556
                                        }
 
557
                                        int openingParanthesis = cell.IndexOf('(');
 
558
                                        if (openingParanthesis >= 0) {
 
559
                                                /*
 
560
                                                 * An opening paranthesis was found. This can
 
561
                                                 * mark the start of indices or arguments.
 
562
                                                 * First, find the matching closing paranthesis.
 
563
                                                 * */
 
564
                                                string originalCommand = cell.Substring(0, openingParanthesis).TrimEnd();
 
565
                                                if (originalCommand.IndexOf(')') != -1) {
 
566
                                                        IO.ReportInvalidData(file, row, column, "The command contains an invalid closing paranthesis.");
 
567
                                                }
 
568
                                                string csvEquivalentCommand = GetCsvEquivalentCommand(file, row, column, originalCommand, section, true);
 
569
                                                int closingParanthesis = cell.IndexOf(')', openingParanthesis + 1);
 
570
                                                if (closingParanthesis >= 0) {
 
571
                                                        /*
 
572
                                                         * The matching closing paranthesis was found. If
 
573
                                                         * it is at the end of the cell, this marks the
 
574
                                                         * end of arguments, otherwise of indices.
 
575
                                                         * 
 
576
                                                         * @ command (indexSequence) .suffix (argumentSequence)
 
577
                                                         * @ command (indexSequence) (argumentSequence)
 
578
                                                         * @ command (indexSequence) .suffix
 
579
                                                         * @ command (argumentSequence)
 
580
                                                         * */
 
581
                                                        if (closingParanthesis == cell.Length - 1) {
 
582
                                                                /*
 
583
                                                                 * The matching closing paranthesis is at
 
584
                                                                 * the end of the cell. The text between
 
585
                                                                 * the opening and closing parantheses
 
586
                                                                 * is the arguments.
 
587
                                                                 * 
 
588
                                                                 * @ command (argumentSequence)
 
589
                                                                 * */
 
590
                                                                string argumentSequence = cell.Substring(openingParanthesis + 1, closingParanthesis - openingParanthesis - 1);
 
591
                                                                if (argumentSequence.IndexOf('(') != -1) {
 
592
                                                                        IO.ReportInvalidData(file, row, column, "The argument sequence contains an invalid opening paranthesis.");
 
593
                                                                }
 
594
                                                                string[] arguments = argumentSequence.Split(',');
 
595
                                                                for (int k = 0; k < arguments.Length; k++) {
 
596
                                                                        arguments[k] = arguments[k].Trim();
 
597
                                                                }
 
598
                                                                expression = new Expression(file, row, column, originalCommand, csvEquivalentCommand, null, null, arguments);
 
599
                                                        } else {
 
600
                                                                /*
 
601
                                                                 * The matching closing paranthesis is before
 
602
                                                                 * the end of the cell. The text between the
 
603
                                                                 * opening and closing parantheses is the
 
604
                                                                 * indices. If another opening paranthesis
 
605
                                                                 * is found after the closing paranthesis,
 
606
                                                                 * this marks the start of arguments.
 
607
                                                                 * 
 
608
                                                                 * @ command (indexSequence) .suffix (argumentSequence)
 
609
                                                                 * @ command (indexSequence) (argumentSequence)
 
610
                                                                 * @ command (indexSequence) .suffix
 
611
                                                                 * */
 
612
                                                                string indexSequence = cell.Substring(openingParanthesis + 1, closingParanthesis - openingParanthesis - 1);
 
613
                                                                if (indexSequence.IndexOf('(') != -1) {
 
614
                                                                        IO.ReportInvalidData(file, row, column, "The index sequence contains an invalid opening paranthesis.");
 
615
                                                                }
 
616
                                                                string[] indices = indexSequence.Split(',');
 
617
                                                                for (int k = 0; k < indices.Length; k++) {
 
618
                                                                        indices[k] = indices[k].Trim();
 
619
                                                                }
 
620
                                                                openingParanthesis = cell.IndexOf('(', closingParanthesis + 1);
 
621
                                                                if (openingParanthesis >= 0) {
 
622
                                                                        /*
 
623
                                                                         * Another opening paranthesis was found. The cell
 
624
                                                                         * must end in a closing paranthesis and must not
 
625
                                                                         * contain further parantheses.
 
626
                                                                         * 
 
627
                                                                         * @ command (indexSequence) .suffix (argumentSequence)
 
628
                                                                         * @ command (indexSequence) (argumentSequence)
 
629
                                                                         * */
 
630
                                                                        string suffix = cell.Substring(closingParanthesis + 1, openingParanthesis - closingParanthesis - 1).Trim();
 
631
                                                                        if (suffix.Length != 0) {
 
632
                                                                                if (suffix.IndexOf(')') != -1) {
 
633
                                                                                        IO.ReportInvalidData(file, row, column, "The suffix contains an invalid closing paranthesis.");
 
634
                                                                                }
 
635
                                                                                if (suffix[0] != '.' || suffix[suffix.Length - 1] == '.') {
 
636
                                                                                        IO.ReportInvalidData(file, row, column, "The suffix must start with a period but must not end in a period.");
 
637
                                                                                }
 
638
                                                                        } else {
 
639
                                                                                suffix = null;
 
640
                                                                        }
 
641
                                                                        closingParanthesis = cell.IndexOf(')', openingParanthesis + 1);
 
642
                                                                        string argumentSequence;
 
643
                                                                        if (closingParanthesis >= 0) {
 
644
                                                                                if (closingParanthesis != cell.Length - 1) {
 
645
                                                                                        /*
 
646
                                                                                         * The closing paranthesis was found before
 
647
                                                                                         * the end of the cell. This is invalid.
 
648
                                                                                         * */
 
649
                                                                                        IO.ReportInvalidData(file, row, column, "The cell must end in a closing paranthesis.");
 
650
                                                                                }
 
651
                                                                                argumentSequence = cell.Substring(openingParanthesis + 1, closingParanthesis - openingParanthesis - 1);
 
652
                                                                        } else {
 
653
                                                                                /*
 
654
                                                                                 * No closing paranthesis was found. This is invalid.
 
655
                                                                                 * */
 
656
                                                                                argumentSequence = cell.Substring(openingParanthesis + 1);
 
657
                                                                                IO.ReportInvalidData(file, row, column, "Missing closing paranthesis.");
 
658
                                                                        }
 
659
                                                                        if (argumentSequence.IndexOf('(') != -1) {
 
660
                                                                                IO.ReportInvalidData(file, row, column, "The argument sequence contains an invalid opening paranthesis.");
 
661
                                                                        }
 
662
                                                                        string[] arguments = argumentSequence.Split(',');
 
663
                                                                        for (int k = 0; k < arguments.Length; k++) {
 
664
                                                                                arguments[k] = arguments[k].Trim();
 
665
                                                                        }
 
666
                                                                        expression = new Expression(file, row, column, originalCommand, csvEquivalentCommand, indices, suffix, arguments);
 
667
                                                                } else {
 
668
                                                                        /*
 
669
                                                                         * Another opening paranthesis was not found.
 
670
                                                                         * The rest of the cell is the suffix.
 
671
                                                                         * 
 
672
                                                                         * @ command (indexSequence) .suffix
 
673
                                                                         * */
 
674
                                                                        string suffix = cell.Substring(closingParanthesis + 1).TrimStart();
 
675
                                                                        if (suffix.IndexOf(')') != -1) {
 
676
                                                                                IO.ReportInvalidData(file, row, column, "The suffix contains an invalid closing paranthesis.");
 
677
                                                                                if (suffix.Length == 1) {
 
678
                                                                                        /*
 
679
                                                                                         * Special invalid case. What we thought were
 
680
                                                                                         * indices were meant to be arguments.
 
681
                                                                                         * */
 
682
                                                                                        expression = new Expression(file, row, column, originalCommand, csvEquivalentCommand, null, null, indices);
 
683
                                                                                        return true;
 
684
                                                                                }
 
685
                                                                        }
 
686
                                                                        if (suffix[0] != '.' || suffix[suffix.Length - 1] == '.') {
 
687
                                                                                IO.ReportInvalidData(file, row, column, "The suffix must start with a period but must not end in a period.");
 
688
                                                                        }
 
689
                                                                        expression = new Expression(file, row, column, originalCommand, csvEquivalentCommand, indices, suffix, null);
 
690
                                                                }
 
691
                                                        }
 
692
                                                } else {
 
693
                                                        /*
 
694
                                                         * A closing paranthesis was not found. This
 
695
                                                         * is invalid. Let's treat the text after the
 
696
                                                         * opening paranthesis as arguments.
 
697
                                                         * */
 
698
                                                        IO.ReportInvalidData(file, row, column, "Missing closing paranthesis.");
 
699
                                                        string argumentSequence = cell.Substring(openingParanthesis + 1);
 
700
                                                        string[] arguments = argumentSequence.Split(',');
 
701
                                                        for (int k = 0; k < arguments.Length; k++) {
 
702
                                                                arguments[k] = arguments[k].Trim();
 
703
                                                        }
 
704
                                                        expression = new Expression(file, row, column, originalCommand, csvEquivalentCommand, null, null, arguments);
 
705
                                                }
 
706
                                        } else {
 
707
                                                /*
 
708
                                                 * An opening paranthesis was not found. This
 
709
                                                 * means that the entire cell is just the
 
710
                                                 * command. Check for track positions and
 
711
                                                 * don't transform them to a CSV equivalent.
 
712
                                                 * 
 
713
                                                 * @ command
 
714
                                                 * */
 
715
                                                // TODO: Make sure to support colon-separated track positions here, too.
 
716
                                                double value;
 
717
                                                if (double.TryParse(cell, NumberStyles.Float, CultureInfo.InvariantCulture, out value)) {
 
718
                                                        expression = new Expression(file, row, column, cell, null, null, null);
 
719
                                                } else {
 
720
                                                        string originalCommand = cell;
 
721
                                                        if (originalCommand.IndexOf(')') != -1) {
 
722
                                                                IO.ReportInvalidData(file, row, column, "The command contains an invalid closing paranthesis.");
 
723
                                                        }
 
724
                                                        string csvEquivalentCommand = GetCsvEquivalentCommand(file, row, column, originalCommand, section, true);
 
725
                                                        expression = new Expression(file, row, column, originalCommand, csvEquivalentCommand, null, null, null);
 
726
                                                }
 
727
                                        }
 
728
                                }
 
729
                        }
 
730
                        AdjustCsvEquivalentExpression(expression);
 
731
                        return true;
 
732
                }
 
733
                
 
734
                /// <summary>Gets the CSV-equivalent command from an RW command.</summary>
 
735
                /// <param name="file">The path to the route file.</param>
 
736
                /// <param name="row">The zero-based row at which the cell is stored.</param>
 
737
                /// <param name="column">The zero-based column at which the cell is stored.</param>
 
738
                /// <param name="command">The RW command.</param>
 
739
                /// <param name="section">The last used section without the enclosing brackets.</param>
 
740
                /// <param name="allowAtSign">Whether to allow an at-sign at the beginning of the command.</param>
 
741
                /// <returns>The CSV-equivalent command.</returns>
 
742
                private static string GetCsvEquivalentCommand(string file, int row, int column, string command, string section, bool allowAtSign) {
 
743
                        switch (section.ToLowerInvariant()) {
 
744
                                case "object":
 
745
                                        section = "Structure";
 
746
                                        break;
 
747
                                case "railway":
 
748
                                        section = "Track";
 
749
                                        break;
 
750
                                case "cycle":
 
751
                                        section = "Cycle.Ground";
 
752
                                        break;
 
753
                        }
 
754
                        if (command.Length != 0 && command[0] == '@') {
 
755
                                if (!allowAtSign) {
 
756
                                        IO.ReportInvalidData(file, row, column, "An @-sign is not allowed at the beginning of the command.");
 
757
                                }
 
758
                                command = command.Substring(1).TrimStart();
 
759
                        }
 
760
                        return section + "." + command;
 
761
                }
 
762
                
 
763
                /// <summary>Adjusts an expression to convert from RW-specific organization to CSV-equivalent organization.</summary>
 
764
                /// <param name="expression">The expression to convert.</param>
 
765
                private static void AdjustCsvEquivalentExpression(Expression expression) {
 
766
                        if (expression.Indices == null & expression.Suffix == null) {
 
767
                                double value;
 
768
                                if (double.TryParse(expression.OriginalCommand, NumberStyles.Float, CultureInfo.InvariantCulture, out value)) {
 
769
                                        if (expression.CsvEquivalentCommand.StartsWith("signal.", StringComparison.OrdinalIgnoreCase)) {
 
770
                                                expression.Indices = new string[] { expression.CsvEquivalentCommand.Substring(7) };
 
771
                                                expression.CsvEquivalentCommand = "Signal";
 
772
                                                expression.Suffix = ".Load";
 
773
                                        } else if (expression.CsvEquivalentCommand.StartsWith("cycle.ground.", StringComparison.OrdinalIgnoreCase)) {
 
774
                                                expression.Indices = new string[] { expression.CsvEquivalentCommand.Substring(13) };
 
775
                                                expression.CsvEquivalentCommand = "Cycle.Ground";
 
776
                                                expression.Suffix = ".Params";
 
777
                                        }
 
778
                                }
 
779
                        }
 
780
                }
 
781
                
 
782
        }
 
783
}
 
 
b'\\ No newline at end of file'