52 |
52 |
53 return false; |
53 return false; |
54 } |
54 } |
55 |
55 |
56 ScriptReader::ScriptReader (str path) { |
56 ScriptReader::ScriptReader (str path) { |
57 atnewline = false; |
|
58 filepath = path; |
|
59 if (!(fp = fopen (path, "r"))) { |
57 if (!(fp = fopen (path, "r"))) { |
60 error ("couldn't open %s for reading!\n", path.chars ()); |
58 error ("couldn't open %s for reading!\n", path.chars ()); |
61 exit (1); |
59 exit (1); |
62 } |
60 } |
63 |
61 |
|
62 filepath = path; |
64 curline = 1; |
63 curline = 1; |
65 curchar = 1; |
64 curchar = 1; |
66 pos = 0; |
65 pos = 0; |
67 token = ""; |
66 token = ""; |
|
67 atnewline = false; |
|
68 commentmode = 0; |
68 } |
69 } |
69 |
70 |
70 ScriptReader::~ScriptReader () { |
71 ScriptReader::~ScriptReader () { |
|
72 FinalChecks (); |
71 fclose (fp); |
73 fclose (fp); |
72 } |
74 } |
73 |
75 |
74 char ScriptReader::ReadChar () { |
76 char ScriptReader::ReadChar () { |
75 char* c = (char*)malloc (sizeof (char)); |
77 char* c = (char*)malloc (sizeof (char)); |
88 |
90 |
89 curchar++; |
91 curchar++; |
90 return c[0]; |
92 return c[0]; |
91 } |
93 } |
92 |
94 |
|
95 char ScriptReader::PeekChar (int offset) { |
|
96 // Store current position |
|
97 long curpos = ftell (fp); |
|
98 |
|
99 // Forward by offset |
|
100 fseek (fp, offset, SEEK_CUR); |
|
101 |
|
102 // Read the character |
|
103 char* c = (char*)malloc (sizeof (char)); |
|
104 if (!fread (c, sizeof (char), 1, fp)) |
|
105 return 0; |
|
106 |
|
107 // Rewind back |
|
108 fseek (fp, curpos, SEEK_SET); |
|
109 |
|
110 return c[0]; |
|
111 } |
|
112 |
93 // true if was found, false if not. |
113 // true if was found, false if not. |
94 bool ScriptReader::Next () { |
114 bool ScriptReader::Next () { |
95 str tmp = ""; |
115 str tmp = ""; |
|
116 |
96 while (!feof (fp)) { |
117 while (!feof (fp)) { |
|
118 // Check if the next token possibly starts a comment. |
|
119 if (PeekChar () == '/' && !tmp.len()) { |
|
120 char c2 = PeekChar (1); |
|
121 // C++-style comment |
|
122 if (c2 == '/') |
|
123 commentmode = 1; |
|
124 else if (c2 == '*') |
|
125 commentmode = 2; |
|
126 |
|
127 // We don't need to actually read in the |
|
128 // comment characters, since they will get |
|
129 // ignored due to comment mode anyway. |
|
130 } |
|
131 |
97 c = ReadChar (); |
132 c = ReadChar (); |
|
133 |
|
134 // If this is a comment we're reading, check if this character |
|
135 // gets the comment terminated, otherwise ignore it. |
|
136 if (commentmode > 0) { |
|
137 if (commentmode == 1 && c == '\n') { |
|
138 // C++-style comments are terminated by a newline |
|
139 commentmode = 0; |
|
140 continue; |
|
141 } else if (commentmode == 2 && c == '*') { |
|
142 // C-style comments are terminated by a `*/` |
|
143 if (PeekChar() == '/') { |
|
144 commentmode = 0; |
|
145 // Now the char has to be read in since we |
|
146 // no longer are reading a comment |
|
147 ReadChar (); |
|
148 } |
|
149 } |
|
150 |
|
151 // Otherwise, ignore it. |
|
152 continue; |
|
153 } |
98 |
154 |
99 // Non-alphanumber characters (sans underscore) break the word too. |
155 // Non-alphanumber characters (sans underscore) break the word too. |
100 // If there was prior data, the delimeter pushes the cursor back so |
156 // If there was prior data, the delimeter pushes the cursor back so |
101 // that the next character will be the same delimeter. If there isn't, |
157 // that the next character will be the same delimeter. If there isn't, |
102 // the delimeter itself is included (and thus becomes a token itself.) |
158 // the delimeter itself is included (and thus becomes a token itself.) |
242 case RETURNVAL_INT: MustNumber (); break; |
298 case RETURNVAL_INT: MustNumber (); break; |
243 case RETURNVAL_STRING: MustString (); break; |
299 case RETURNVAL_STRING: MustString (); break; |
244 case RETURNVAL_BOOLEAN: MustBool (); break; |
300 case RETURNVAL_BOOLEAN: MustBool (); break; |
245 } |
301 } |
246 } |
302 } |
|
303 |
|
304 // Checks to be performed at the end of file |
|
305 void ScriptReader::FinalChecks () { |
|
306 // If comment mode is 2 by the time the file ended, the |
|
307 // comment was left unterminated. 1 is no problem, since |
|
308 // it's terminated by newlines anyway. |
|
309 if (commentmode == 2) |
|
310 ParserError ("unterminated `/*`-style comment"); |
|
311 } |