source: branches/CpuSingleSize/Parser.pas

Last change on this file was 240, checked in by chronos, 10 months ago
File size: 5.4 KB
Line 
1unit Parser;
2
3interface
4
5uses
6 Classes, SysUtils;
7
8type
9 TErrorEvent = procedure (Text: string; Pos: TPoint) of object;
10
11 TTokenKind = (tkKeyword, tkString, tkNumber, tkSpecialSymbol, tkEof, tkEol,
12 tkIdentifier);
13
14 TToken = record
15 Kind: TTokenKind;
16 Value: string;
17 Pos: TPoint;
18 end;
19
20 { TParserPos }
21
22 TParserPos = record
23 Index: Integer;
24 Pos: TPoint;
25 procedure Reset;
26 procedure NextChar;
27 procedure NextLine;
28 end;
29
30 { TParser }
31
32 TParser = class
33 private
34 FOnError: TErrorEvent;
35 public
36 Pos: TParserPos;
37 Source: string;
38 function IsDigit(Value: Char): Boolean;
39 function IsSpecialSymbol(C: Char): Boolean;
40 function IsAlpha(C: Char): Boolean;
41 function IsAlphaNumeric(C: Char): Boolean;
42 function IsWhiteSpace(C: Char): Boolean;
43 function ReadNext: TToken;
44 function CheckNext(Kind: TTokenKind; Value: string = ''): Boolean;
45 function CheckNextKind(Kind: TTokenKind): Boolean;
46 function CheckNextAndRead(Kind: TTokenKind; Value: string = ''): Boolean;
47 procedure Expect(Kind: TTokenKind; Value: string = '');
48 procedure Error(Text: string; Pos: TPoint);
49 procedure Reset;
50 constructor Create;
51 property OnError: TErrorEvent read FOnError write FOnError;
52 end;
53
54
55implementation
56
57{ TParserPos }
58
59procedure TParserPos.Reset;
60begin
61 Index := 1;
62 Pos := Point(1, 1);
63end;
64
65procedure TParserPos.NextChar;
66begin
67 Inc(Index);
68 Inc(Pos.X);
69end;
70
71procedure TParserPos.NextLine;
72begin
73 Inc(Index);
74 Pos.X := 1;
75 Inc(Pos.Y);
76end;
77
78{ TParser }
79
80function TParser.IsDigit(Value: Char): Boolean;
81begin
82 Result := Value in ['0'..'9'];
83end;
84
85function TParser.IsSpecialSymbol(C: Char): Boolean;
86begin
87 Result := (C = ':') or (C = ',') or (C = '(') or (C = ')') or (C = '+');
88end;
89
90function TParser.IsAlpha(C: Char): Boolean;
91begin
92 Result := (C in ['a'..'z']) or (C in ['A'..'Z']);
93end;
94
95function TParser.IsAlphaNumeric(C: Char): Boolean;
96begin
97 Result := IsAlpha(C) or IsDigit(C) or (C = '_');
98end;
99
100function TParser.IsWhiteSpace(C: Char): Boolean;
101begin
102 Result := (C = ' ') or (C = #9);
103end;
104
105function TParser.ReadNext: TToken;
106type
107 TParserState = (psNone, psNumber, psString, psComment, psIdentifier);
108var
109 C: Char;
110 State: TParserState;
111begin
112 State := psNone;
113 Result.Value := '';
114 while Pos.Index < Length(Source) do begin
115 C := Source[Pos.Index];
116 if State = psNone then begin
117 if IsWhiteSpace(C) then begin
118 end else
119 if C = ';' then begin
120 State := psComment;
121 end else
122 if IsAlpha(C) then begin
123 Result.Pos := Pos.Pos;
124 Result.Kind := tkIdentifier;
125 Result.Value := C;
126 State := psIdentifier;
127 end else
128 if IsDigit(C) then begin
129 Result.Pos := Pos.Pos;
130 Result.Kind := tkNumber;
131 Result.Value := C;
132 State := psNumber;
133 end else
134 if C = '''' then begin
135 Result.Pos := Pos.Pos;
136 Result.Kind := tkString;
137 State := psString;
138 end else
139 if C = #13 then begin
140 end else
141 if C = #10 then begin
142 Result.Pos := Pos.Pos;
143 Result.Kind := tkEol;
144 Result.Value := '';
145 Pos.NextLine;
146 Break;
147 end else
148 if IsSpecialSymbol(C) then begin
149 Result.Pos := Pos.Pos;
150 Result.Kind := tkSpecialSymbol;
151 Result.Value := C;
152 Pos.NextChar;
153 Break;
154 end else
155 Error('Unknown character ' + C, Pos.Pos);
156 end else
157 if State = psIdentifier then begin
158 if IsAlphaNumeric(C) then begin
159 Result.Value := Result.Value + C;
160 end else begin
161 Break;
162 end;
163 end else
164 if State = psComment then begin
165 if (C = #10) or (C = #13) then begin
166 State := psNone;
167 Continue;
168 end;
169 end else
170 if State = psNumber then begin
171 if IsDigit(C) then Result.Value := Result.Value + C
172 else begin
173 Break;
174 end;
175 end else
176 if State = psString then begin
177 if C = '''' then begin
178 Pos.NextChar;
179 Break;
180 end else begin
181 Result.Value := Result.Value + C;
182 end;
183 end;
184 Pos.NextChar;
185 end;
186 if (State = psNone) and (Pos.Index >= Length(Source)) then begin
187 Result.Kind := tkEof;
188 Result.Value := '';
189 Result.Pos := Pos.Pos;
190 end;
191end;
192
193function TParser.CheckNext(Kind: TTokenKind; Value: string = ''): Boolean;
194var
195 LastPos: TParserPos;
196 Token: TToken;
197begin
198 LastPos := Pos;
199 Token := ReadNext;
200 Result := (Token.Kind = Kind) and (LowerCase(Token.Value) = LowerCase(Value));
201 Pos := LastPos;
202end;
203
204function TParser.CheckNextKind(Kind: TTokenKind): Boolean;
205var
206 LastPos: TParserPos;
207 Token: TToken;
208begin
209 LastPos := Pos;
210 Token := ReadNext;
211 Result := Token.Kind = Kind;
212 Pos := LastPos;
213end;
214
215function TParser.CheckNextAndRead(Kind: TTokenKind; Value: string): Boolean;
216var
217 LastPos: TParserPos;
218 Token: TToken;
219begin
220 LastPos := Pos;
221 Token := ReadNext;
222 Result := (Token.Kind = Kind) and (LowerCase(Token.Value) = LowerCase(Value));
223 if not Result then Pos := LastPos;
224end;
225
226procedure TParser.Expect(Kind: TTokenKind; Value: string = '');
227var
228 Token: TToken;
229begin
230 Token := ReadNext;
231 if (Token.Kind <> Kind) or (LowerCase(Token.Value) <> LowerCase(Value)) then
232 Error('Expected ' + Value + ' but ' + Token.Value +' found.', Token.Pos);
233end;
234
235procedure TParser.Error(Text: string; Pos: TPoint);
236begin
237 if Assigned(FOnError) then
238 FOnError(Text, Pos);
239end;
240
241procedure TParser.Reset;
242begin
243 Pos.Reset;
244end;
245
246constructor TParser.Create;
247begin
248 Reset;
249end;
250
251end.
252
Note: See TracBrowser for help on using the repository browser.