source: branches/ByteArray/Parser.pas

Last change on this file was 59, checked in by chronos, 6 months ago
  • Fixed: Assembler and disassembler to work correctly with supported instructions.
File size: 5.6 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 function Expect(Kind: TTokenKind; Value: string = ''): Boolean;
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
57resourcestring
58 SUnknownCharacter = 'Unknown character %s';
59 SExpectedButFound = 'Expected %s but %s found.';
60
61{ TParserPos }
62
63procedure TParserPos.Reset;
64begin
65 Index := 1;
66 Pos := Point(1, 1);
67end;
68
69procedure TParserPos.NextChar;
70begin
71 Inc(Index);
72 Inc(Pos.X);
73end;
74
75procedure TParserPos.NextLine;
76begin
77 Inc(Index);
78 Pos.X := 1;
79 Inc(Pos.Y);
80end;
81
82{ TParser }
83
84function TParser.IsDigit(Value: Char): Boolean;
85begin
86 Result := Value in ['0'..'9'];
87end;
88
89function TParser.IsSpecialSymbol(C: Char): Boolean;
90begin
91 Result := (C = ':') or (C = ',') or (C = '(') or (C = ')') or (C = '+');
92end;
93
94function TParser.IsAlpha(C: Char): Boolean;
95begin
96 Result := (C in ['a'..'z']) or (C in ['A'..'Z']);
97end;
98
99function TParser.IsAlphaNumeric(C: Char): Boolean;
100begin
101 Result := IsAlpha(C) or IsDigit(C) or (C = '_');
102end;
103
104function TParser.IsWhiteSpace(C: Char): Boolean;
105begin
106 Result := (C = ' ') or (C = #9);
107end;
108
109function TParser.ReadNext: TToken;
110type
111 TParserState = (psNone, psNumber, psString, psComment, psIdentifier);
112var
113 C: Char;
114 State: TParserState;
115begin
116 State := psNone;
117 Result.Value := '';
118 while Pos.Index < Length(Source) do begin
119 C := Source[Pos.Index];
120 if State = psNone then begin
121 if IsWhiteSpace(C) then begin
122 end else
123 if C = ';' then begin
124 State := psComment;
125 end else
126 if IsAlpha(C) then begin
127 Result.Pos := Pos.Pos;
128 Result.Kind := tkIdentifier;
129 Result.Value := C;
130 State := psIdentifier;
131 end else
132 if IsDigit(C) then begin
133 Result.Pos := Pos.Pos;
134 Result.Kind := tkNumber;
135 Result.Value := C;
136 State := psNumber;
137 end else
138 if C = '''' then begin
139 Result.Pos := Pos.Pos;
140 Result.Kind := tkString;
141 State := psString;
142 end else
143 if C = #13 then begin
144 end else
145 if C = #10 then begin
146 Result.Pos := Pos.Pos;
147 Result.Kind := tkEol;
148 Result.Value := '';
149 Pos.NextLine;
150 Break;
151 end else
152 if IsSpecialSymbol(C) then begin
153 Result.Pos := Pos.Pos;
154 Result.Kind := tkSpecialSymbol;
155 Result.Value := C;
156 Pos.NextChar;
157 Break;
158 end else
159 Error(Format(SUnknownCharacter, [C]), Pos.Pos);
160 end else
161 if State = psIdentifier then begin
162 if IsAlphaNumeric(C) then begin
163 Result.Value := Result.Value + C;
164 end else begin
165 Break;
166 end;
167 end else
168 if State = psComment then begin
169 if (C = #10) or (C = #13) then begin
170 State := psNone;
171 Continue;
172 end;
173 end else
174 if State = psNumber then begin
175 if IsDigit(C) then Result.Value := Result.Value + C
176 else begin
177 Break;
178 end;
179 end else
180 if State = psString then begin
181 if C = '''' then begin
182 Pos.NextChar;
183 Break;
184 end else begin
185 Result.Value := Result.Value + C;
186 end;
187 end;
188 Pos.NextChar;
189 end;
190 if (State = psNone) and (Pos.Index >= Length(Source)) then begin
191 Result.Kind := tkEof;
192 Result.Value := '';
193 Result.Pos := Pos.Pos;
194 end;
195end;
196
197function TParser.CheckNext(Kind: TTokenKind; Value: string = ''): Boolean;
198var
199 LastPos: TParserPos;
200 Token: TToken;
201begin
202 LastPos := Pos;
203 Token := ReadNext;
204 Result := (Token.Kind = Kind) and (LowerCase(Token.Value) = LowerCase(Value));
205 Pos := LastPos;
206end;
207
208function TParser.CheckNextKind(Kind: TTokenKind): Boolean;
209var
210 LastPos: TParserPos;
211 Token: TToken;
212begin
213 LastPos := Pos;
214 Token := ReadNext;
215 Result := Token.Kind = Kind;
216 Pos := LastPos;
217end;
218
219function TParser.CheckNextAndRead(Kind: TTokenKind; Value: string): Boolean;
220var
221 LastPos: TParserPos;
222 Token: TToken;
223begin
224 LastPos := Pos;
225 Token := ReadNext;
226 Result := (Token.Kind = Kind) and (LowerCase(Token.Value) = LowerCase(Value));
227 if not Result then Pos := LastPos;
228end;
229
230function TParser.Expect(Kind: TTokenKind; Value: string = ''): Boolean;
231var
232 Token: TToken;
233begin
234 Result := True;
235 Token := ReadNext;
236 if (Token.Kind <> Kind) or (LowerCase(Token.Value) <> LowerCase(Value)) then begin
237 Result := False;
238 Error(Format(SExpectedButFound, [Value, Token.Value]), Token.Pos);
239 end;
240end;
241
242procedure TParser.Error(Text: string; Pos: TPoint);
243begin
244 if Assigned(FOnError) then
245 FOnError(Text, Pos);
246end;
247
248procedure TParser.Reset;
249begin
250 Pos.Reset;
251end;
252
253constructor TParser.Create;
254begin
255 Reset;
256end;
257
258end.
259
Note: See TracBrowser for help on using the repository browser.