fdcil-cvs Mailing List for Free Pascal Compiler for IL
Status: Planning
Brought to you by:
miracle2k
You can subscribe to this list here.
| 2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(13) |
Aug
(14) |
Sep
|
Oct
|
Nov
|
Dec
|
|---|
|
From: Michael E. <mir...@us...> - 2004-08-16 18:54:12
|
Update of /cvsroot/fdcil/dev/miracle2k/fdcil-test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7003/miracle2k/fdcil-test Modified Files: fdcil.Compiler.pas fdcil.ExceptionHandling.pas fdcil.IO.Messages.Localize.pas fdcil.IO.Messages.pas fdcil.Lexer.pas fdcil.Parser.pas fdcil.SymbolTable.pas fdcil.Tokens.pas fdcil.bdsproj fdcil.dpr test.pas Log Message: some updates Index: fdcil.Compiler.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.Compiler.pas,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** fdcil.Compiler.pas 15 Aug 2004 11:34:46 -0000 1.2 --- fdcil.Compiler.pas 16 Aug 2004 18:54:00 -0000 1.3 *************** *** 56,73 **** begin try SymbolTable := TSymbolTable.Create; SymbolTable.Init; Input := TFileInput.Create(FileName); Lexer := TLexer.Create(Input, SymbolTable); ! Parser := TDelphiParser.Create(Lexer); Parser.Init; ! Parser.&Program; except on E: FileNotFoundException do MessageEmitter.Emit(mtFatal, System.String.Format(E_FILE_NOT_FOUND, FileName)); on E: EFatalError do ! MessageEmitter.Emit(mtFatal, E.Line, E.Column, E.Message); on E: EfdcilError do ! MessageEmitter.Emit(mtError, E.Line, E.Column, E.Message); end; end; --- 56,74 ---- begin try + MessageEmitter.CurrFileName := System.IO.Path.GetFileName(FileName); SymbolTable := TSymbolTable.Create; SymbolTable.Init; Input := TFileInput.Create(FileName); Lexer := TLexer.Create(Input, SymbolTable); ! Parser := TDelphiParser.Create(Lexer, SymbolTable); Parser.Init; ! Parser.DoParse; except on E: FileNotFoundException do MessageEmitter.Emit(mtFatal, System.String.Format(E_FILE_NOT_FOUND, FileName)); on E: EFatalError do ! MessageEmitter.Emit(mtFatal, E); on E: EfdcilError do ! MessageEmitter.Emit(mtError, E); end; end; Index: fdcil.Parser.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.Parser.pas,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** fdcil.Parser.pas 15 Aug 2004 11:34:46 -0000 1.2 --- fdcil.Parser.pas 16 Aug 2004 18:54:00 -0000 1.3 *************** *** 23,27 **** interface ! uses fdcil.ExceptionHandling, --- 23,27 ---- interface ! uses fdcil.ExceptionHandling, *************** *** 29,33 **** fdcil.IO.Messages.Localize, fdcil.Tokens, ! fdcil.Lexer; type --- 29,34 ---- fdcil.IO.Messages.Localize, fdcil.Tokens, ! fdcil.Lexer, ! fdcil.SymbolTable; type *************** *** 35,64 **** private fLexer: TLexer; protected function TokenToString(Token: TToken): string; overload; function TokenToString(TokenID: Integer): string; overload; function TokensToString(TokenIDs: array of Integer): string; procedure RaiseException(E: EfdcilError); procedure HandleException(E: Exception); ! procedure Match(Token: Integer); ! procedure SyncToken(StopTokens: TTokenSet); procedure Next; procedure &Interface; procedure &Implementation; ! procedure Block; procedure Ident; public ! function get_CurrentToken: Integer; public ! constructor Create(Lexer: TLexer); ! procedure &Program; procedure Init; ! property Look: Integer read get_CurrentToken; ! // TODO: add a shortcut property for fLexer.CurrToken end; --- 36,91 ---- private fLexer: TLexer; + fSymbolTable: TSymbolTable; protected + // TODO: Implement a ToString() method for TToken? function TokenToString(Token: TToken): string; overload; function TokenToString(TokenID: Integer): string; overload; function TokensToString(TokenIDs: array of Integer): string; + // Initializes the basic exception object with the current data from the + // Lexer, e.g. the current line; use this instead of the raise keyword. procedure RaiseException(E: EfdcilError); + procedure UnexpectedToken(Expected: string); + // Call within an except block; will analyze the current exception and + // write appropriate messages to the output. procedure HandleException(E: Exception); ! // Directly proceed to next token procedure Next; + // Check if the current token equals the one that is expected; Proceeds + // to next token if successfull, otherwise an exception is raised. + procedure Match(TokenID: Integer); + // Used for error recovery; Calls Next(); until a token from "StopTokens" + // is found; Various token sets are defined in fdcil.ExceptionHandling. + procedure SyncToken(StopTokens: TTokenSet); + // Parsing Methods + procedure &Program; + procedure &Unit; procedure &Interface; procedure &Implementation; ! procedure &Uses; ! procedure &Type; ! procedure TypeIdent; ! procedure &Class; ! procedure &Record; ! procedure &Var; ! procedure &Const; ! procedure &ResourceString; ! procedure Block(EndWithDot: boolean = False); procedure Ident; public ! function get_CurrentTokenID: Integer; ! function get_LookToken: TToken; public ! constructor Create(Lexer: TLexer; SymbolTable: TSymbolTable); ! procedure DoParse; procedure Init; ! // TODO: Perhaps speed can be increased if you directly access a simple ! // field member, without using any get-method ! property Look: Integer read get_CurrentTokenID; ! property LookToken: TToken read get_LookToken; end; *************** *** 67,74 **** { TDelphiParser } ! constructor TDelphiParser.Create(Lexer: TLexer); begin inherited Create; fLexer := Lexer; end; --- 94,102 ---- { TDelphiParser } ! constructor TDelphiParser.Create(Lexer: TLexer; SymbolTable: TSymbolTable); begin inherited Create; fLexer := Lexer; + fSymbolTable := SymbolTable; end; *************** *** 78,87 **** end; ! procedure TDelphiParser.Match(Token: Integer); begin ! if fLexer.CurrToken.TokenID = Token then Next else ! RaiseException(EExpectedError.Create(TokenToString(Token), TokenToString(fLexer.CurrToken))); end; --- 106,115 ---- end; ! procedure TDelphiParser.Match(TokenID: Integer); begin ! if LookToken.TokenID = TokenID then Next else ! UnexpectedToken(TokenToString(TokenID)); end; *************** *** 91,99 **** end; ! function TDelphiParser.get_CurrentToken: Integer; begin Result := fLexer.CurrToken.TokenID; end; procedure TDelphiParser.SyncToken(StopTokens: TTokenSet); --- 119,132 ---- end; ! function TDelphiParser.get_CurrentTokenID: Integer; begin Result := fLexer.CurrToken.TokenID; end; + function TDelphiParser.get_LookToken: TToken; + begin + Result := fLexer.CurrToken; + end; + procedure TDelphiParser.SyncToken(StopTokens: TTokenSet); *************** *** 117,125 **** procedure TDelphiParser.RaiseException(E: EfdcilError); begin ! E.Line := fLexer.CurrToken.Line; ! E.Column := fLexer.CurrToken.Column; raise E; end; procedure TDelphiParser.HandleException(E: Exception); begin --- 150,163 ---- procedure TDelphiParser.RaiseException(E: EfdcilError); begin ! E.Line := LookToken.Line; ! E.Column := LookToken.Column; raise E; end; + procedure TDelphiParser.UnexpectedToken(Expected: string); + begin + RaiseException(EExpectedError.Create(Expected, TokenToString(LookToken))); + end; + procedure TDelphiParser.HandleException(E: Exception); begin *************** *** 129,138 **** except on E: EParserError do ! MessageEmitter.Emit(mtError, E.Line, E.Column, E.Message); on E: EExpectedError do ! MessageEmitter.Emit(mtError, E.Line, E.Column, E.Message); on E: EFatalError do begin ! MessageEmitter.Emit(mtFatal, E.Line, E.Column, E.Message); raise; // Stop parsing when a fatal error occurs end; --- 167,176 ---- except on E: EParserError do ! MessageEmitter.Emit(mtError, E); on E: EExpectedError do ! MessageEmitter.Emit(mtError, E); on E: EFatalError do begin ! MessageEmitter.Emit(mtFatal, E); raise; // Stop parsing when a fatal error occurs end; *************** *** 143,147 **** begin if Token.TokenID = T_IDENT then ! Result := S_IDENTIFIER + ' ''' + Token.Value + '''' else Result := TokenToString(Token.TokenID); --- 181,185 ---- begin if Token.TokenID = T_IDENT then ! Result := S_IDENTIFIER_PREFIX + ' ''' + Token.Value + '''' else Result := TokenToString(Token.TokenID); *************** *** 150,160 **** function TDelphiParser.TokenToString(TokenID: Integer): string; begin - // TODO: Lookup token string name in keyword table if TokenID = 0 then Result := S_END_OF_FILE else if TokenID = T_IDENT then Result := S_IDENTIFIER else ! Result := '''' + TokenID.ToString() + ''''; end; --- 188,201 ---- function TDelphiParser.TokenToString(TokenID: Integer): string; begin if TokenID = 0 then Result := S_END_OF_FILE else if TokenID = T_IDENT then Result := S_IDENTIFIER + else if TokenID = T_INT then + Result := S_NUMBER + else if TokenID = T_FLOAT then + Result := S_FLOAT else ! Result := '''' + fSymbolTable.KeywordToString(TokenID) + ''''; end; *************** *** 168,259 **** end; ! // TODO: add a few explaining comments to the parsing procedures procedure TDelphiParser.&Program; begin ! if Look = T_PROGRAM then ! begin ! Match(T_PROGRAM); Ident; Match(T_SEMICOLON); ! &Implementation; ! Block; ! end ! ! else if Look = T_UNIT then ! begin ! Match(T_UNIT); Ident; Match(T_SEMICOLON); ! Match(T_INTERFACE); ! &Interface; ! Match(T_IMPLEMENTATION); ! &Implementation; ! if Look = T_INITIALIZATION then begin ! Match(T_INITIALIZATION); ! Block; ! Match(T_FINALIZATION); ! Block; ! end ! // TODO: unit begin block ! else if Look = T_FINALIZATION then ! RaiseException(EParserError.Create(E_FIN_WITHOUT_INIT)); ! Match(T_END); Match(T_DOT); ! end ! else if Look = T_PACKAGE then ! RaiseException(EFatalError.Create('Packages not yet supported')) ! else if Look = T_LIBRARY then ! RaiseException(EFatalError.Create('Libraries not yet supported')) ! ! else ! // TODO: "Root keyword" should be replaced by the token we would automatically ! // expect after reading the file extension, e.g. "UNIT" for .pas files. ! RaiseException(EExpectedError.Create('Root keyword', TokenToString(fLexer.CurrToken))); ! if Look <> T_NULL then ! MessageEmitter.Emit(mtHint, E_TEXT_AFTER_END_IGNORED); end; procedure TDelphiParser.&Interface; begin ! try ! case Look of ! T_USES: ! begin ! Next; ! repeat ! Ident; ! case Look of ! T_COMMA: Next; ! T_SEMICOLON: begin Match(T_SEMICOLON); break; end; ! else ! RaiseException(EExpectedError.Create(TokensToString([T_COMMA, T_SEMICOLON]), ! TokenToString(fLexer.CurrToken))); ! end; ! until False; ! end; T_TYPE: ! begin ! end; ! T_VAR: ! begin ! end; ! T_CONST: ! begin ! end; ! T_RESOURCESTRING: ! begin ! end; ! ! // TODO: functions ! end; ! except ! on E: Exception do begin ! HandleException(E); ! SyncToken(InterfaceSync); &Interface; end; ! end; end; --- 209,318 ---- end; ! procedure TDelphiParser.DoParse; ! begin ! // First, we need a root keyword ! case Look of ! T_PROGRAM: &Program; ! T_UNIT: &Unit; ! T_LIBRARY: ! RaiseException(EFatalError.Create('Libraries not yet supported')); ! T_PACKAGE: ! RaiseException(EFatalError.Create('Packages not yet supported')); ! else ! // TODO: "Root keyword" should be replaced by the token we would automatically ! // expect after reading the file extension, e.g. "UNIT" for .pas files. ! UnexpectedToken('Root keyword'); ! end; ! ! // If there are still tokens, we ignore them, but notify the user; ! if Look <> T_NULL then ! MessageEmitter.Emit(mtHint, E_TEXT_AFTER_END_IGNORED); ! end; procedure TDelphiParser.&Program; begin ! Match(T_PROGRAM); Ident; Match(T_SEMICOLON); ! &Implementation; ! Block; ! end; ! procedure TDelphiParser.&Unit; ! begin ! // Unit header ! Match(T_UNIT); Ident; Match(T_SEMICOLON); ! // Interface section ! Match(T_INTERFACE); ! repeat ! try ! &Interface; ! if Look = T_IMPLEMENTATION then break ! else UnexpectedToken('Declaration'); // TODO: localize ! except ! on E: Exception do begin ! HandleException(E); ! SyncToken(InterfaceSync); ! end; ! end; ! until False; ! // Implementation section ! Match(T_IMPLEMENTATION); ! &Implementation; ! ! // Initialization section is not required ! if Look = T_INITIALIZATION then begin ! Match(T_INITIALIZATION); ! // TODO: Sync()! ! //Block; ! // Finalization section is also not required ! if Look = T_FINALIZATION then begin ! Match(T_FINALIZATION); ! // TODO: Sync()! ! //Block; ! end; ! end ! else if Look = T_FINALIZATION then ! RaiseException(EParserError.Create(E_FIN_WITHOUT_INIT)) ! else if Look = T_BEGIN then begin ! Block(True); ! exit; // Block already included the final "end." ! end; ! // "end." ! Match(T_END); Match(T_DOT); end; procedure TDelphiParser.&Interface; begin ! // There may be a uses-section at the very beginning; Note this is the only ! // place within interface where this is allowed. ! // TODO: multiple uses statements should we allowed ! if Look = T_USES then ! try ! &Uses; ! except ! // If there was an error, sync to the implementation part ! on E: Exception do begin ! HandleException(E); ! SyncToken(UsesSync); ! end; ! end; + // Now we have to expect different section which may be used multiple times + repeat + case Look of T_TYPE: ! &Type; T_VAR: ! &Var; T_CONST: ! &Const; T_RESOURCESTRING: ! &ResourceString; ! else ! break; // Caller will raise exception ! // TODO: functions end; ! until False; end; *************** *** 263,267 **** end; ! procedure TDelphiParser.Block; begin Match(T_BEGIN); --- 322,326 ---- end; ! procedure TDelphiParser.Block(EndWithDot: boolean = False); begin Match(T_BEGIN); *************** *** 272,276 **** on E: Exception do HandleException(E); end; ! Match(T_END); Match(T_SEMICOLON); end; --- 331,339 ---- on E: Exception do HandleException(E); end; ! Match(T_END); ! if EndWithDot then ! Match(T_DOT) ! else ! Match(T_SEMICOLON); end; *************** *** 284,286 **** --- 347,500 ---- end; + procedure TDelphiParser.&Class; + begin + // Eat class keyword + Match(T_CLASS); + // There is a left parantheses to define base classes + if Look = T_LPAREN then begin + Next; + Match(T_IDENT); + while Look = T_COMMA do begin + Next; + Ident; + end; + Match(T_RPAREN); + end; + + // Either end directly with a semicolon.. + if Look = T_SEMICOLON then + Match(T_SEMICOLON) + // .. or there is a definition part + else begin + // TODO: Parse definitions! + Match(T_END); Match(T_SEMICOLON); + end; + end; + + procedure TDelphiParser.&Record; + begin + // Eat record keyword + Match(T_RECORD); + + // Either end directly with a semicolon.. + if Look = T_SEMICOLON then + Match(T_SEMICOLON) + // .. or there is a definition part + else begin + // TODO: Parse definitions! + Match(T_END); Match(T_SEMICOLON); + end; + end; + + procedure TDelphiParser.&Uses; + begin + // Eat uses-token + Match(T_USES); + repeat + // We need at the very least /one/ identifier + Ident; + case Look of + // If there is a comma, continue the loop to find more idents + T_COMMA: + Next; + // If there is a semicolon, this was the last ident; exit loop; + T_SEMICOLON: + begin + Next; + break; // leave the loop + end; + // Anything else is unexpected: Show an error message + else + UnexpectedToken(TokensToString([T_COMMA, T_SEMICOLON])); + end; + until False; + end; + + procedure TDelphiParser.&Type; + begin + // Eat type-token + Match(T_TYPE); + repeat + // Require an identifier followed by a equality operator + Match(T_IDENT); + Match(T_EQUAL); + + // Parse the type identifier after the equality token + case Look of + T_CLASS: &Class; + T_RECORD: &Record; + else begin TypeIdent; Match(T_SEMICOLON); end; + end; + until Look <> T_IDENT; + end; + + procedure TDelphiParser.&Const; + begin + Match(T_CONST); + repeat + Match(T_IDENT); Match(T_EQUAL); + if Look = T_INT then Match(T_INT) + else if Look = T_FLOAT then Match(T_FLOAT) + else if Look = T_STRING then Match(T_STRING) + else UnexpectedToken(S_TYPE); + Match(T_SEMICOLON); + if Look <> T_IDENT then break; + until False; + end; + + procedure TDelphiParser.&ResourceString; + begin + + end; + + procedure TDelphiParser.&Var; + begin + Match(T_VAR); + repeat + Match(T_IDENT); Match(T_COLON); Ident; Match(T_SEMICOLON); + if Look <> T_IDENT then break; + until False; + end; + + procedure TDelphiParser.TypeIdent; + begin + // Range, e.g. 0..4 + if Look = T_INT then begin + Next; + Match(T_DOUBLEDOT); + Match(T_INT); + end + + // Array + else if Look = T_ARRAY then begin + Next; + Match(T_LBRACKET); + Match(T_INT); + Match(T_DOUBLEDOT); + Match(T_INT); + Match(T_RBRACKET); + Match(T_OF); + TypeIdent; + end + + // Enum + else if Look = T_LPAREN then begin + Next; + Match(T_IDENT); + while Look = T_COMMA do begin + Match(T_COMMA); + Match(T_IDENT); + end; + Match(T_RPAREN); + end + + // Another Identifier + else if Look = T_IDENT then + Ident + + // Anything else is a syntax error + else + UnexpectedToken(S_TYPE); + end; + end. Index: fdcil.dpr =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.dpr,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** fdcil.dpr 15 Aug 2004 11:34:46 -0000 1.2 --- fdcil.dpr 16 Aug 2004 18:54:00 -0000 1.3 *************** *** 28,32 **** fdcil.Tokens in 'fdcil.Tokens.pas', fdcil.Compiler in 'fdcil.Compiler.pas', - fdcil.Tokenizer in 'fdcil.Tokenizer.pas', fdcil.Lexer in 'fdcil.Lexer.pas', fdcil.Parser in 'fdcil.Parser.pas', --- 28,31 ---- Index: fdcil.bdsproj =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.bdsproj,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** fdcil.bdsproj 15 Aug 2004 11:34:46 -0000 1.2 --- fdcil.bdsproj 16 Aug 2004 18:54:00 -0000 1.3 *************** *** 157,165 **** <VersionInfo Name="Locale" Type="Integer">1031</VersionInfo> <VersionInfo Name="CodePage" Type="Integer">1252</VersionInfo> ! </VersionInfo> <FileList> <File FileName="fdcil.CommandLine.pas" ContainerId="" ModuleName="fdcil.CommandLine"/> <File FileName="fdcil.Tokens.pas" ContainerId="" ModuleName="fdcil.Tokens"/> <File FileName="fdcil.Compiler.pas" ContainerId="" ModuleName="fdcil.Compiler"/> - <File FileName="fdcil.Tokenizer.pas" ContainerId="" ModuleName="fdcil.Tokenizer"/> <File FileName="fdcil.Lexer.pas" ContainerId="" ModuleName="fdcil.Lexer"/> <File FileName="fdcil.Parser.pas" ContainerId="" ModuleName="fdcil.Parser"/> --- 157,167 ---- <VersionInfo Name="Locale" Type="Integer">1031</VersionInfo> <VersionInfo Name="CodePage" Type="Integer">1252</VersionInfo> ! </VersionInfo> ! ! ! <FileList> <File FileName="fdcil.CommandLine.pas" ContainerId="" ModuleName="fdcil.CommandLine"/> <File FileName="fdcil.Tokens.pas" ContainerId="" ModuleName="fdcil.Tokens"/> <File FileName="fdcil.Compiler.pas" ContainerId="" ModuleName="fdcil.Compiler"/> <File FileName="fdcil.Lexer.pas" ContainerId="" ModuleName="fdcil.Lexer"/> <File FileName="fdcil.Parser.pas" ContainerId="" ModuleName="fdcil.Parser"/> Index: test.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/test.pas,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** test.pas 15 Aug 2004 11:34:47 -0000 1.2 --- test.pas 16 Aug 2004 18:54:00 -0000 1.3 *************** *** 3,14 **** interface ! uses SysUtils - uses Windows, - uses Math, implementation end. --- 3,38 ---- interface ! uses Windows; ! ! const ! s = ! i = 8; ! ! ! type ! tsert = (sdf, dsdf); ! ! MyClass = class(Test1, Test2); ! ! MyClass2 = class(Tet1, Test2, I3) ! end; ! ! ! type ! Someting = array[1..2] of test; ! ! var ! test: string; ! ! var test: integer; implementation + begin + end. + + Ignored Text Index: fdcil.Lexer.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.Lexer.pas,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** fdcil.Lexer.pas 15 Aug 2004 11:34:46 -0000 1.2 --- fdcil.Lexer.pas 16 Aug 2004 18:54:00 -0000 1.3 *************** *** 519,525 **** end; ! procedure &Symbol; // TODO: use symbol table to load tokens begin Value := Look; case Look of '+': Token := T_ADD_OP; --- 519,526 ---- end; ! procedure &Symbol; begin Value := Look; + // TODO: This is already in the symbol table, use the data there to decide which symbol we have found case Look of '+': Token := T_ADD_OP; *************** *** 546,550 **** ':': Token := T_COLON; ';': Token := T_SEMICOLON; ! '.': Token := T_DOT; ',': Token := T_COMMA; '&': Token := T_AMPERSAND; --- 547,555 ---- ':': Token := T_COLON; ';': Token := T_SEMICOLON; ! '.': begin ! GetChar; ! if Look = '.' then begin Token := T_DOUBLEDOT; Value := Value + Look; end ! else begin Token := T_DOT; exit; end; ! end; ',': Token := T_COMMA; '&': Token := T_AMPERSAND; *************** *** 563,567 **** if Look = '''' then begin GetChar; ! if not (Look = '''') then break else Value := Value + ''''; end; --- 568,572 ---- if Look = '''' then begin GetChar; ! if not (Look = '''') then exit else Value := Value + ''''; end; *************** *** 622,626 **** if Look = '$' then CompilerDirective; Comment; ! end; end; --- 627,631 ---- if Look = '$' then CompilerDirective; Comment; ! end else Token := T_LPAREN; end; Index: fdcil.Tokens.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.Tokens.pas,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** fdcil.Tokens.pas 15 Aug 2004 11:34:46 -0000 1.2 --- fdcil.Tokens.pas 16 Aug 2004 18:54:00 -0000 1.3 *************** *** 54,57 **** --- 54,62 ---- T_INITIALIZATION = 2013; T_FINALIZATION = 2014; + T_CLASS = 2015; + T_RECORD = 2016; + T_ARRAY = 2017; + T_OF = 2018; + T_AS = 2019; // Operators *************** *** 71,75 **** T_LPAREN = 4001; T_RPAREN = 4002; ! T_LBRACKET = 4003; T_RBRACKET = 4003; T_COLON = 4005; --- 76,80 ---- T_LPAREN = 4001; T_RPAREN = 4002; ! T_LBRACKET = 4003; // TODO: is this the right name? T_RBRACKET = 4003; T_COLON = 4005; *************** *** 78,86 **** T_POINTER = 4008; T_EQUAL = 4009; ! T_DOT = 4010; T_COMMA = 4011; T_SHARP = 4012; T_AMPERSAND = 4013; ! T_HOCHKOMMA = 4014; // Other tokens --- 83,92 ---- T_POINTER = 4008; T_EQUAL = 4009; ! T_DOT = 4010; // TODO: is this the right name? T_COMMA = 4011; T_SHARP = 4012; T_AMPERSAND = 4013; ! T_HOCHKOMMA = 4014; // TODO: english name? ! T_DOUBLEDOT = 4015; // Other tokens Index: fdcil.IO.Messages.Localize.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.IO.Messages.Localize.pas,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** fdcil.IO.Messages.Localize.pas 15 Aug 2004 11:34:46 -0000 1.2 --- fdcil.IO.Messages.Localize.pas 16 Aug 2004 18:54:00 -0000 1.3 *************** *** 26,30 **** resourcestring E_FILE_NOT_FOUND = 'File not found: ''{0}'''; ! E_TEXT_AFTER_END_IGNORED = 'Text after final ''End.'' is ignored by compiler'; E_UNEXPECTED = '{0} expected but {1} found'; --- 26,30 ---- resourcestring E_FILE_NOT_FOUND = 'File not found: ''{0}'''; ! E_TEXT_AFTER_END_IGNORED = 'Text after final ''END.'' is ignored by compiler'; E_UNEXPECTED = '{0} expected but {1} found'; *************** *** 32,37 **** S_END_OF_FILE = 'end of file'; - S_IDENTIFIER = 'identifier'; S_OR = 'or'; implementation --- 32,47 ---- S_END_OF_FILE = 'end of file'; S_OR = 'or'; + S_IDENTIFIER_PREFIX = 'identifier'; + + S_IDENTIFIER = 'Identifier'; + S_TYPE = 'Type'; + S_DECLARATION = 'Declaration'; + S_NUMBER = 'number'; + S_FLOAT = 'real constant'; + + S_FATAL_ERROR = 'Fatal Error'; + S_ERROR = 'Error'; + S_HINT = 'Hint'; implementation Index: fdcil.IO.Messages.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.IO.Messages.pas,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** fdcil.IO.Messages.pas 15 Aug 2004 11:34:46 -0000 1.2 --- fdcil.IO.Messages.pas 16 Aug 2004 18:54:00 -0000 1.3 *************** *** 24,37 **** interface type TMessageType = (mtFatal, mtError, mtHint); ! TMessageEmitter = class(System.Object) protected function MessageTypeToString(MessageType: TMessageType): string; public procedure Emit(MessageType: TMessageType; Message: string); overload; ! procedure Emit(MessageType: TMessageType; Line, Col: Integer; ! Message: string); overload; end; --- 24,47 ---- interface + uses + fdcil.ExceptionHandling; + type TMessageType = (mtFatal, mtError, mtHint); ! TMessageEmitter = class(System.Object) + private + FCurrFileName: string; protected function MessageTypeToString(MessageType: TMessageType): string; public procedure Emit(MessageType: TMessageType; Message: string); overload; ! procedure Emit(MessageType: TMessageType; E: EfdcilError); overload; ! ! // This is the filename used in the output messages; It is updated by the ! // TCompiler object everytime it tries to compile a new file; an alternative ! // (and maybe better) solution would be to add a new FileName property to ! // the base EfdcilError exception class. ! property CurrFileName: string read fCurrFileName write fCurrFileName; end; *************** *** 40,43 **** --- 50,56 ---- implementation + uses + fdcil.IO.Messages.Localize; + var InternalMessageEmitter: TMessageEmitter = nil; *************** *** 52,57 **** { TMessageEmitter } - // TODO: add a MessageEmitter.Emit(E: Exception) method? - procedure TMessageEmitter.Emit(MessageType: TMessageType; Message: string); begin --- 65,68 ---- *************** *** 59,68 **** end; ! procedure TMessageEmitter.Emit(MessageType: TMessageType; Line, ! Col: Integer; Message: string); begin - // TODO: 'filename' needs to be passed Console.WriteLine('[' + MessageTypeToString(MessageType) + '] ' + ! 'FileName(' + Line.ToString() + '): ' + Message); end; --- 70,77 ---- end; ! procedure TMessageEmitter.Emit(MessageType: TMessageType; E: EfdcilError); begin Console.WriteLine('[' + MessageTypeToString(MessageType) + '] ' + ! CurrFileName + '(' + E.Line.ToString() + '): ' + E.Message); end; *************** *** 71,77 **** begin case MessageType of ! mtFatal: Result := 'Fatal Error'; ! mtError: Result := 'Error'; ! mtHint: Result := 'Hint'; else raise Exception.Create('Description for message type is missing'); --- 80,86 ---- begin case MessageType of ! mtFatal: Result := S_FATAL_ERROR; ! mtError: Result := S_ERROR; ! mtHint: Result := S_HINT; else raise Exception.Create('Description for message type is missing'); Index: fdcil.SymbolTable.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.SymbolTable.pas,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** fdcil.SymbolTable.pas 15 Aug 2004 11:34:46 -0000 1.2 --- fdcil.SymbolTable.pas 16 Aug 2004 18:54:00 -0000 1.3 *************** *** 29,34 **** type TSymbol = record ! IsSpecial: Boolean; ! Token: Integer; end; --- 29,38 ---- type TSymbol = record ! public ! TokenID: Integer; ! IsSpecial: boolean; // Either a keyword or an operator ! public ! function Equals(obj: TObject): Boolean; override; ! function GetHashCode: Integer; override; end; *************** *** 37,47 **** fSymbols: HashTable; protected ! function MakeSymbol(IsSpecial: Boolean; Token: Integer): TSymbol; public constructor Create; procedure Init; ! procedure AddKeyword(Name: string; Symbol: TSymbol); function QueryKeyword(Keyword: string): Integer; end; --- 41,52 ---- fSymbols: HashTable; protected ! function MakeSymbol(TokenID: Integer): TSymbol; public constructor Create; procedure Init; ! procedure AddSymbol(Name: string; Symbol: TSymbol); function QueryKeyword(Keyword: string): Integer; + function KeywordToString(Keyword: integer): string; end; *************** *** 53,58 **** { TSymbolTable } ! procedure TSymbolTable.AddKeyword(Name: string; Symbol: TSymbol); begin fSymbols.Add(Symbol, Name); fSymbols.Add(Name, Symbol); --- 58,64 ---- { TSymbolTable } ! procedure TSymbolTable.AddSymbol(Name: string; Symbol: TSymbol); begin + Name := Name.ToLower; fSymbols.Add(Symbol, Name); fSymbols.Add(Name, Symbol); *************** *** 67,94 **** procedure TSymbolTable.Init; begin ! AddKeyword('program', MakeSymbol(True, T_PROGRAM)); ! AddKeyword('unit', MakeSymbol(True, T_UNIT)); ! AddKeyword('library', MakeSymbol(True, T_LIBRARY)); ! AddKeyword('package', MakeSymbol(True, T_PACKAGE)); ! AddKeyword('interface', MakeSymbol(True, T_INTERFACE)); ! AddKeyword('implementation', MakeSymbol(True, T_IMPLEMENTATION)); ! AddKeyword('uses', MakeSymbol(True, T_USES)); ! AddKeyword('begin', MakeSymbol(True, T_BEGIN)); ! AddKeyword('end', MakeSymbol(True, T_END)); ! AddKeyword('if', MakeSymbol(True, T_IF)); ! AddKeyword('then', MakeSymbol(True, T_THEN)); ! AddKeyword('else', MakeSymbol(True, T_ELSE)); ! AddKeyword('div', MakeSymbol(True, T_INT_DIVIDE_OP)); ! AddKeyword('mod', MakeSymbol(True, T_MODULO)); ! AddKeyword('<', MakeSymbol(True, T_LT_OP)); ! AddKeyword('>', MakeSymbol(True, T_GT_OP)); end; ! function TSymbolTable.MakeSymbol(IsSpecial: Boolean; ! Token: Integer): TSymbol; begin ! Result.IsSpecial := IsSpecial; ! Result.Token := Token; end; --- 73,128 ---- procedure TSymbolTable.Init; begin ! // Keywords ! AddSymbol('program', MakeSymbol(T_PROGRAM)); ! AddSymbol('unit', MakeSymbol(T_UNIT)); ! AddSymbol('library', MakeSymbol(T_LIBRARY)); ! AddSymbol('package', MakeSymbol(T_PACKAGE)); ! AddSymbol('interface', MakeSymbol(T_INTERFACE)); ! AddSymbol('implementation', MakeSymbol(T_IMPLEMENTATION)); ! AddSymbol('initialization', MakeSymbol(T_INITIALIZATION)); ! AddSymbol('finalization', MakeSymbol(T_FINALIZATION)); ! AddSymbol('uses', MakeSymbol(T_USES)); ! AddSymbol('class', MakeSymbol(T_CLASS)); ! AddSymbol('record', MakeSymbol(T_RECORD)); ! AddSymbol('array', MakeSymbol(T_ARRAY)); ! AddSymbol('type', MakeSymbol(T_TYPE)); ! AddSymbol('var', MakeSymbol(T_VAR)); ! AddSymbol('const', MakeSymbol(T_CONST)); ! AddSymbol('begin', MakeSymbol(T_BEGIN)); ! AddSymbol('end', MakeSymbol(T_END)); ! AddSymbol('if', MakeSymbol(T_IF)); ! AddSymbol('then', MakeSymbol(T_THEN)); ! AddSymbol('else', MakeSymbol(T_ELSE)); ! AddSymbol('div', MakeSymbol(T_INT_DIVIDE_OP)); ! AddSymbol('mod', MakeSymbol(T_MODULO)); ! AddSymbol('of', MakeSymbol(T_OF)); ! AddSymbol('as', MakeSymbol(T_AS)); ! // Just symbols, but we use this to convert the token ids to a string ! AddSymbol(';', MakeSymbol(T_SEMICOLON)); ! AddSymbol('(', MakeSymbol(T_LPAREN)); ! AddSymbol(')', MakeSymbol(T_RPAREN)); ! AddSymbol('.', MakeSymbol(T_DOT)); ! AddSymbol(',', MakeSymbol(T_COMMA)); ! AddSymbol('<', MakeSymbol(T_LT_OP)); ! AddSymbol('>', MakeSymbol(T_GT_OP)); end; ! function TSymbolTable.KeywordToString(Keyword: integer): string; ! var ! HashValue: System.Object; ! tempSymbol: TSymbol; begin ! Result := Keyword.ToString(); ! tempSymbol.TokenID := Keyword; ! HashValue := fSymbols.Item[System.Object(tempSymbol)]; ! if HashValue <> nil then ! Result := System.String(HashValue).ToUpper; ! end; ! ! function TSymbolTable.MakeSymbol(TokenID: Integer): TSymbol; ! begin ! Result.IsSpecial := True; ! Result.TokenID := TokenID; end; *************** *** 98,104 **** begin Result := T_NULL; ! HashValue := fSymbols.Item[Keyword]; if HashValue <> nil then ! Result := TSymbol(HashValue).Token; end; --- 132,153 ---- begin Result := T_NULL; ! HashValue := fSymbols.Item[Keyword.ToLower]; if HashValue <> nil then ! Result := TSymbol(HashValue).TokenID; ! end; ! ! { TSymbol } ! ! function TSymbol.Equals(obj: TObject): Boolean; ! begin ! if obj is TSymbol then ! Result := TSymbol(obj).TokenID = Self.TokenID ! else ! Result := False; ! end; ! ! function TSymbol.GetHashCode: Integer; ! begin ! Result := Self.TokenID; end; Index: fdcil.ExceptionHandling.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.ExceptionHandling.pas,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** fdcil.ExceptionHandling.pas 15 Aug 2004 11:34:46 -0000 1.2 --- fdcil.ExceptionHandling.pas 16 Aug 2004 18:54:00 -0000 1.3 *************** *** 33,39 **** --- 33,41 ---- fLine: Integer; fColumn: Integer; + //fFileName: string; public property Line: Integer read fLine write fLine; property Column: Integer read fColumn write fColumn; + //property FileName: string read fFileName write fFileName; end; *************** *** 50,55 **** StatementSync: array[0..2] of Integer = (T_SEMICOLON, T_BEGIN, T_END); ! InterfaceSync: array[1..5] of Integer = ! (T_USES, T_TYPE, T_VAR, T_CONST, T_IMPLEMENTATION); implementation --- 52,59 ---- StatementSync: array[0..2] of Integer = (T_SEMICOLON, T_BEGIN, T_END); ! InterfaceSync: array[1..4] of Integer = ! (T_TYPE, T_VAR, T_CONST, T_IMPLEMENTATION); ! UsesSync: array[1..1] of Integer = ! (T_IMPLEMENTATION); implementation |
|
From: Michael E. <mir...@us...> - 2004-08-15 11:34:59
|
Update of /cvsroot/fdcil/dev/miracle2k/fdcil-test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3491/miracle2k/fdcil-test Modified Files: fdcil.CommandLine.pas fdcil.Compiler.pas fdcil.ExceptionHandling.pas fdcil.IO.Messages.Localize.pas fdcil.IO.Messages.pas fdcil.Lexer.pas fdcil.Parser.pas fdcil.SymbolTable.pas fdcil.Tokens.pas fdcil.bdsproj fdcil.dpr test.pas Log Message: Index: fdcil.Compiler.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.Compiler.pas,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** fdcil.Compiler.pas 9 Aug 2004 11:16:54 -0000 1.1 --- fdcil.Compiler.pas 15 Aug 2004 11:34:46 -0000 1.2 *************** *** 66,71 **** on E: FileNotFoundException do MessageEmitter.Emit(mtFatal, System.String.Format(E_FILE_NOT_FOUND, FileName)); ! on E: EParserError do ! MessageEmitter.Emit(mtError, E.Message); end; end; --- 66,73 ---- on E: FileNotFoundException do MessageEmitter.Emit(mtFatal, System.String.Format(E_FILE_NOT_FOUND, FileName)); ! on E: EFatalError do ! MessageEmitter.Emit(mtFatal, E.Line, E.Column, E.Message); ! on E: EfdcilError do ! MessageEmitter.Emit(mtError, E.Line, E.Column, E.Message); end; end; Index: fdcil.Parser.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.Parser.pas,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** fdcil.Parser.pas 9 Aug 2004 11:16:54 -0000 1.1 --- fdcil.Parser.pas 15 Aug 2004 11:34:46 -0000 1.2 *************** *** 27,30 **** --- 27,31 ---- fdcil.ExceptionHandling, fdcil.IO.Messages, + fdcil.IO.Messages.Localize, fdcil.Tokens, fdcil.Lexer; *************** *** 35,43 **** --- 36,54 ---- fLexer: TLexer; protected + function TokenToString(Token: TToken): string; overload; + function TokenToString(TokenID: Integer): string; overload; + function TokensToString(TokenIDs: array of Integer): string; + + procedure RaiseException(E: EfdcilError); + procedure HandleException(E: Exception); + procedure Match(Token: Integer); + procedure SyncToken(StopTokens: TTokenSet); procedure Next; + procedure &Interface; procedure &Implementation; procedure Block; + procedure Ident; public function get_CurrentToken: Integer; *************** *** 49,52 **** --- 60,64 ---- property Look: Integer read get_CurrentToken; + // TODO: add a shortcut property for fLexer.CurrToken end; *************** *** 55,168 **** { TDelphiParser } ! procedure TDelphiParser.&Program; begin ! if Look = T_PROGRAM then ! begin ! Match(T_PROGRAM); Match(T_IDENT); Match(T_SEMICOLON); ! &Implementation; ! Block; ! end ! else if Look = T_UNIT then ! begin ! //Match(T_UNIT); Match(T_IDENT); Match(T_SEMICOLON); ! //Match(T_END); Match(T_DOT); ! raise EParserError.Create('Units not yet supported'); ! end ! else if Look = T_PACKAGE then ! begin ! //Match(T_PACKAGE); Match(T_IDENT); Match(T_SEMICOLON); ! //Block; ! raise EParserError.Create('Packages not yet supported'); ! end ! else if Look = T_LIBRARY then begin ! //Match(T_LIBRARY); Match(T_IDENT); Match(T_SEMICOLON); ! //Block; ! raise EParserError.Create('Libraries not yet supported'); ! end ! else ! raise EParserError.Create('PROGRAM, UNIT, PACKAGE OR LIBRARY expected'); // TODO: make localizable ! if Look <> T_NULL then ! MessageEmitter.Emit(mtHint, 'Text after final ''End.'' is ignored by compiler'); end; ! procedure TDelphiParser.Block; begin ! try ! Match(T_BEGIN); ! Match(T_END); Match(T_SEMICOLON); except - // We can continue with parsing and find more errors on E: EParserError do ! MessageEmitter.Emit(mtError, E.Message); end; end; ! constructor TDelphiParser.Create(Lexer: TLexer); begin ! inherited Create; ! fLexer := Lexer; end; ! procedure TDelphiParser.Init; begin ! fLexer.GetToken; end; ! procedure TDelphiParser.Match(Token: Integer); begin ! if fLexer.CurrToken.Token = Token then ! Next ! else ! raise EParserError.Create('Expected ' + Token.ToString()); end; ! procedure TDelphiParser.Next; begin ! fLexer.GetToken; end; ! function TDelphiParser.get_CurrentToken: Integer; begin ! Result := fLexer.CurrToken.Token; end; procedure TDelphiParser.&Implementation; begin - case Look of - - T_USES: - begin - Next; - repeat - Match(T_IDENT); // TODO: Delphi for .NET supports namespaces; unit names may contain "." characters - case Look of - T_COMMA: Next; - T_SEMICOLON: begin Match(T_SEMICOLON); break; end; - else raise EParserError.Create('Expected ; or ,'); - end; - until False; - end; ! T_TYPE: ! begin ! end; ! ! T_VAR: ! begin ! end; ! T_CONST: ! begin ! end; ! T_RESOURCESTRING: ! begin ! end; end; end; --- 67,284 ---- { TDelphiParser } ! constructor TDelphiParser.Create(Lexer: TLexer); begin ! inherited Create; ! fLexer := Lexer; ! end; ! procedure TDelphiParser.Init; ! begin ! fLexer.GetToken; ! end; ! procedure TDelphiParser.Match(Token: Integer); ! begin ! if fLexer.CurrToken.TokenID = Token then ! Next ! else ! RaiseException(EExpectedError.Create(TokenToString(Token), TokenToString(fLexer.CurrToken))); ! end; ! procedure TDelphiParser.Next; ! begin ! fLexer.GetToken; ! end; ! ! function TDelphiParser.get_CurrentToken: Integer; ! begin ! Result := fLexer.CurrToken.TokenID; ! end; ! ! procedure TDelphiParser.SyncToken(StopTokens: TTokenSet); ! ! function TokenIncluded: boolean; ! var ! i: Integer; begin ! Result := False; ! for i := Low(StopTokens) to High(StopTokens) do ! if StopTokens[i] = Look then begin ! Result := True; ! break; ! end; ! end; ! begin ! while not TokenIncluded do ! Next; ! end; ! procedure TDelphiParser.RaiseException(E: EfdcilError); ! begin ! E.Line := fLexer.CurrToken.Line; ! E.Column := fLexer.CurrToken.Column; ! raise E; end; ! procedure TDelphiParser.HandleException(E: Exception); begin ! // TODO: Would it be better to use: "if E.ClassType = ..." ? ! try ! raise E; except on E: EParserError do ! MessageEmitter.Emit(mtError, E.Line, E.Column, E.Message); ! on E: EExpectedError do ! MessageEmitter.Emit(mtError, E.Line, E.Column, E.Message); ! on E: EFatalError do ! begin ! MessageEmitter.Emit(mtFatal, E.Line, E.Column, E.Message); ! raise; // Stop parsing when a fatal error occurs ! end; end; end; ! function TDelphiParser.TokenToString(Token: TToken): string; begin ! if Token.TokenID = T_IDENT then ! Result := S_IDENTIFIER + ' ''' + Token.Value + '''' ! else ! Result := TokenToString(Token.TokenID); end; ! function TDelphiParser.TokenToString(TokenID: Integer): string; begin ! // TODO: Lookup token string name in keyword table ! if TokenID = 0 then ! Result := S_END_OF_FILE ! else if TokenID = T_IDENT then ! Result := S_IDENTIFIER ! else ! Result := '''' + TokenID.ToString() + ''''; end; ! function TDelphiParser.TokensToString(TokenIDs: array of Integer): string; ! var ! i: Integer; begin ! for i := Low(TokenIDs) to High(TokenIDs) - 1 do ! Result := TokenToString(TokenIDs[i]) + ' ' + S_OR + ' '; ! Result := Result + TokenToString(TokenIDs[High(TokenIDs)]); end; ! // TODO: add a few explaining comments to the parsing procedures ! ! procedure TDelphiParser.&Program; begin ! if Look = T_PROGRAM then ! begin ! Match(T_PROGRAM); Ident; Match(T_SEMICOLON); ! &Implementation; ! Block; ! end ! ! else if Look = T_UNIT then ! begin ! Match(T_UNIT); Ident; Match(T_SEMICOLON); ! Match(T_INTERFACE); ! &Interface; ! Match(T_IMPLEMENTATION); ! &Implementation; ! if Look = T_INITIALIZATION then begin ! Match(T_INITIALIZATION); ! Block; ! Match(T_FINALIZATION); ! Block; ! end ! // TODO: unit begin block ! else if Look = T_FINALIZATION then ! RaiseException(EParserError.Create(E_FIN_WITHOUT_INIT)); ! Match(T_END); Match(T_DOT); ! end ! ! else if Look = T_PACKAGE then ! RaiseException(EFatalError.Create('Packages not yet supported')) ! ! else if Look = T_LIBRARY then ! RaiseException(EFatalError.Create('Libraries not yet supported')) ! ! else ! // TODO: "Root keyword" should be replaced by the token we would automatically ! // expect after reading the file extension, e.g. "UNIT" for .pas files. ! RaiseException(EExpectedError.Create('Root keyword', TokenToString(fLexer.CurrToken))); ! ! if Look <> T_NULL then ! MessageEmitter.Emit(mtHint, E_TEXT_AFTER_END_IGNORED); end; ! procedure TDelphiParser.&Interface; begin ! try ! case Look of ! T_USES: ! begin ! Next; ! repeat ! Ident; ! case Look of ! T_COMMA: Next; ! T_SEMICOLON: begin Match(T_SEMICOLON); break; end; ! else ! RaiseException(EExpectedError.Create(TokensToString([T_COMMA, T_SEMICOLON]), ! TokenToString(fLexer.CurrToken))); ! end; ! until False; ! end; ! ! T_TYPE: ! begin ! end; ! ! T_VAR: ! begin ! end; ! ! T_CONST: ! begin ! end; ! ! T_RESOURCESTRING: ! begin ! end; ! ! // TODO: functions ! end; ! except ! on E: Exception do begin ! HandleException(E); ! SyncToken(InterfaceSync); &Interface; ! end; ! end; end; procedure TDelphiParser.&Implementation; begin ! end; ! procedure TDelphiParser.Block; ! begin ! Match(T_BEGIN); ! try ! // Statements ! except ! // We can continue with parsing and find more errors ! on E: Exception do HandleException(E); ! end; ! Match(T_END); Match(T_SEMICOLON); ! end; ! procedure TDelphiParser.Ident; ! begin ! Match(T_IDENT); ! while Look = T_DOT do begin ! Match(T_DOT); ! Match(T_IDENT); end; end; Index: fdcil.dpr =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.dpr,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** fdcil.dpr 9 Aug 2004 11:16:54 -0000 1.1 --- fdcil.dpr 15 Aug 2004 11:34:46 -0000 1.2 *************** *** 40,46 **** CommandLineParser: TCommandLineParser; Compiler: TDelphiCompiler; - - Lexer: TLexer; Input: TFileInput; SymbolTable: TSymbolTable; - i: Integer; begin CommandLineParser := TCommandLineParser.Create(True); --- 40,43 ---- *************** *** 51,72 **** end else Writeln('FileName is missing'); ! ! (* repeat ! i := Environment.TickCount; ! //Input := TFileInput.Create('F:\Developing\Projects\fdcil\dev\miracle2k\fdcil-test\fdcil.Lexer.pas'); //C:\Programme\Borland\BDS\2.0\source\rtl\Borland.Vcl.Windows.pas'); ! Input := TFileInput.Create('C:\Programme\Borland\BDS\2.0\source\rtl\Borland.Vcl.Windows.pas'); ! SymbolTable := TSymbolTable.Create; SymbolTable.Init; ! Lexer := TLexer.Create(Input, SymbolTable); ! try ! repeat Lexer.GetToken; (*Console.WriteLine(Lexer.CurrToken.Token.ToString()+ ':' + Lexer.CurrToken.Value) ! until Lexer.CurrToken.Token = T_NULL; ! except ! raise; ! end; ! Console.WriteLine(Environment.TickCount - i); ! ! Readln; ! until False;*) ! {$IFDEF IDE_DEBUG} Readln; --- 48,52 ---- end else Writeln('FileName is missing'); ! {$IFDEF IDE_DEBUG} Readln; Index: fdcil.bdsproj =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.bdsproj,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** fdcil.bdsproj 9 Aug 2004 11:16:54 -0000 1.1 --- fdcil.bdsproj 15 Aug 2004 11:34:46 -0000 1.2 *************** *** 157,198 **** <VersionInfo Name="Locale" Type="Integer">1031</VersionInfo> <VersionInfo Name="CodePage" Type="Integer">1252</VersionInfo> ! </VersionInfo> ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! <FileList> <File FileName="fdcil.CommandLine.pas" ContainerId="" ModuleName="fdcil.CommandLine"/> <File FileName="fdcil.Tokens.pas" ContainerId="" ModuleName="fdcil.Tokens"/> --- 157,161 ---- <VersionInfo Name="Locale" Type="Integer">1031</VersionInfo> <VersionInfo Name="CodePage" Type="Integer">1252</VersionInfo> ! </VersionInfo> <FileList> <File FileName="fdcil.CommandLine.pas" ContainerId="" ModuleName="fdcil.CommandLine"/> <File FileName="fdcil.Tokens.pas" ContainerId="" ModuleName="fdcil.Tokens"/> Index: test.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/test.pas,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** test.pas 9 Aug 2004 11:16:54 -0000 1.1 --- test.pas 15 Aug 2004 11:34:47 -0000 1.2 *************** *** 1,7 **** ! program test; ! uses test, test2; ! begin ! end; --- 1,14 ---- ! unit test; ! interface ! uses SysUtils ! uses Windows, ! ! uses Math, ! ! ! implementation ! ! end. Index: fdcil.Lexer.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.Lexer.pas,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** fdcil.Lexer.pas 9 Aug 2004 11:16:54 -0000 1.1 --- fdcil.Lexer.pas 15 Aug 2004 11:34:46 -0000 1.2 *************** *** 31,35 **** fdcil.Tokenizer; ! {$DEFINE AdRRAY_ACCESS} const --- 31,35 ---- fdcil.Tokenizer; ! {.$DEFINE ARRAY_ACCESS} const *************** *** 48,52 **** Column: Integer; &Index: Integer; ! Token: Integer; Value: string; end; --- 48,52 ---- Column: Integer; &Index: Integer; ! TokenID: Integer; Value: string; end; *************** *** 127,131 **** Ch, Ch2: Char; begin ! Result.Token := T_NULL; // local variables are faster than instance fields Idx := FIndex; --- 127,131 ---- Ch, Ch2: Char; begin ! Result.TokenID := T_NULL; // local variables are faster than instance fields Idx := FIndex; *************** *** 134,138 **** ! while (Result.Token = T_NULL) and (Idx < CodeLen) do begin --- 134,138 ---- ! while (Result.TokenID = T_NULL) and (Idx < CodeLen) do begin *************** *** 191,195 **** if Idx <= CodeLen then Inc(Idx); // include ending "'" ! Result.Token := T_STRING; end --- 191,195 ---- if Idx <= CodeLen then Inc(Idx); // include ending "'" ! Result.TokenID := T_STRING; end *************** *** 201,205 **** if Data[Idx] = '$' then begin ! Result.Token := T_DIRECTIVE; Inc(Idx); end; --- 201,205 ---- if Data[Idx] = '$' then begin ! Result.TokenID := T_DIRECTIVE; Inc(Idx); end; *************** *** 226,230 **** if Data[Idx] = '$' then begin ! Result.Token := T_DIRECTIVE; Inc(Idx); end; --- 226,230 ---- if Data[Idx] = '$' then begin ! Result.TokenID := T_DIRECTIVE; Inc(Idx); end; *************** *** 266,270 **** while (Idx <= CodeLen) and (System.Char.IsLetterOrDigit(Data[Idx]) or (Data[Idx] = '_')) {(AnsiChar(Data[Idx]) in IdentChars)} do Inc(Idx); ! Result.Token := T_IDENT; end --- 266,270 ---- while (Idx <= CodeLen) and (System.Char.IsLetterOrDigit(Data[Idx]) or (Data[Idx] = '_')) {(AnsiChar(Data[Idx]) in IdentChars)} do Inc(Idx); ! Result.TokenID := T_IDENT; end *************** *** 308,312 **** Inc(Idx); end; ! Result.Token := T_INT; end --- 308,312 ---- Inc(Idx); end; ! Result.TokenID := T_INT; end *************** *** 324,328 **** Inc(Idx); end; ! Result.Token := T_INT; end --- 324,328 ---- Inc(Idx); end; ! Result.TokenID := T_INT; end *************** *** 348,352 **** Inc(Idx); end; ! Result.Token := T_STRING; end --- 348,352 ---- Inc(Idx); end; ! Result.TokenID := T_STRING; end *************** *** 355,368 **** begin case Ch of ! '+': Result.Token := T_ADD_OP; ! '-': Result.Token := T_SUBTRACT_OP; ! '*': Result.Token := T_MULTIPLY_OP; ! '/': Result.Token := T_DIVIDE_OP; ! '(': Result.Token := T_LPAREN; ! ')': Result.Token := T_RPAREN; ! '[': Result.Token := T_LBRACKET; ! ']': Result.Token := T_RBRACKET; '<': begin ! Result.Token := T_LE_OP; // GetChar; // if Look = '=' then begin Result.Token := T_LE_OP; Value := Value + Look; end --- 355,368 ---- begin case Ch of ! '+': Result.TokenID := T_ADD_OP; ! '-': Result.TokenID := T_SUBTRACT_OP; ! '*': Result.TokenID := T_MULTIPLY_OP; ! '/': Result.TokenID := T_DIVIDE_OP; ! '(': Result.TokenID := T_LPAREN; ! ')': Result.TokenID := T_RPAREN; ! '[': Result.TokenID := T_LBRACKET; ! ']': Result.TokenID := T_RBRACKET; '<': begin ! Result.TokenID := T_LE_OP; // GetChar; // if Look = '=' then begin Result.Token := T_LE_OP; Value := Value + Look; end *************** *** 370,388 **** end; '>': begin ! Result.Token := T_LE_OP; // GetChar; // if Look = '=' then begin Result.Token := T_GE_OP; Value := Value + Look; end // else begin Result.Token := T_GT_OP; exit; end; end; ! '@': Result.Token := T_AT; ! '^': Result.Token := T_POINTER; ! '=': Result.Token := T_EQUAL; ! ':': Result.Token := T_COLON; ! ';': Result.Token := T_SEMICOLON; ! '.': Result.Token := T_DOT; ! ',': Result.Token := T_COMMA; ! '&': Result.Token := T_AMPERSAND; ! '#': Result.Token := T_SHARP; ! '''': Result.Token := T_HOCHKOMMA; // else raise Exception.Create('Unkown Symbol:' + Look); end; --- 370,388 ---- end; '>': begin ! Result.TokenID := T_LE_OP; // GetChar; // if Look = '=' then begin Result.Token := T_GE_OP; Value := Value + Look; end // else begin Result.Token := T_GT_OP; exit; end; end; ! '@': Result.TokenID := T_AT; ! '^': Result.TokenID := T_POINTER; ! '=': Result.TokenID := T_EQUAL; ! ':': Result.TokenID := T_COLON; ! ';': Result.TokenID := T_SEMICOLON; ! '.': Result.TokenID := T_DOT; ! ',': Result.TokenID := T_COMMA; ! '&': Result.TokenID := T_AMPERSAND; ! '#': Result.TokenID := T_SHARP; ! '''': Result.TokenID := T_HOCHKOMMA; // else raise Exception.Create('Unkown Symbol:' + Look); end; *************** *** 398,402 **** Console.WriteLine(Ch); Console.WriteLine(FLineNum); - sleep(1000); end; --- 398,401 ---- *************** *** 436,440 **** begin p := GetToken; ! Result := p.Token <> T_NULL; end; --- 435,439 ---- begin p := GetToken; ! Result := p.TokenID <> T_NULL; end; *************** *** 612,616 **** '}': begin ! // TODO: remove this! we need a real fix! GetChar; end; --- 611,615 ---- '}': begin ! // TODO: remove this! we need a real fix! this should never be executed GetChar; end; *************** *** 655,659 **** fCurrentToken.Line := Line; fCurrentToken.Column := Column; ! fCurrentToken.Token := Token; fCurrentToken.Value := Value; end; --- 654,658 ---- fCurrentToken.Line := Line; fCurrentToken.Column := Column; ! fCurrentToken.TokenID := Token; fCurrentToken.Value := Value; end; Index: fdcil.Tokens.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.Tokens.pas,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** fdcil.Tokens.pas 9 Aug 2004 11:16:54 -0000 1.1 --- fdcil.Tokens.pas 15 Aug 2004 11:34:46 -0000 1.2 *************** *** 24,27 **** --- 24,32 ---- interface + type + // It would probably be nicer to use a real set-type, but that would mean + // we can't use custom id values for our tokens (Delphi does not support this) + TTokenSet = array of Integer; + const // Special "null" token, indicating end of input *************** *** 47,50 **** --- 52,57 ---- T_VAR = 2011; T_RESOURCESTRING = 2012; + T_INITIALIZATION = 2013; + T_FINALIZATION = 2014; // Operators Index: fdcil.CommandLine.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.CommandLine.pas,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** fdcil.CommandLine.pas 9 Aug 2004 11:16:54 -0000 1.1 --- fdcil.CommandLine.pas 15 Aug 2004 11:34:46 -0000 1.2 *************** *** 248,252 **** otInt: Self.Value := System.Object(0); otString: Self.Value := ''; ! otArrayList: Self.Value := ArrayList.Create; end; Self.Name := Name; --- 248,252 ---- otInt: Self.Value := System.Object(0); otString: Self.Value := ''; ! otArrayList: Self.Value := ArrayList.Create; // TODO: the array list stuff does not yet work! end; Self.Name := Name; Index: fdcil.IO.Messages.Localize.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.IO.Messages.Localize.pas,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** fdcil.IO.Messages.Localize.pas 9 Aug 2004 11:16:54 -0000 1.1 --- fdcil.IO.Messages.Localize.pas 15 Aug 2004 11:34:46 -0000 1.2 *************** *** 23,29 **** interface ! resourcestring ! E_FILE_NOT_FOUND = 'File not found: ''{0}'''; implementation --- 23,37 ---- interface ! resourcestring ! E_FILE_NOT_FOUND = 'File not found: ''{0}'''; ! E_TEXT_AFTER_END_IGNORED = 'Text after final ''End.'' is ignored by compiler'; ! ! E_UNEXPECTED = '{0} expected but {1} found'; ! E_FIN_WITHOUT_INIT = 'Finalization requires initialization section'; ! ! S_END_OF_FILE = 'end of file'; ! S_IDENTIFIER = 'identifier'; ! S_OR = 'or'; implementation Index: fdcil.IO.Messages.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.IO.Messages.pas,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** fdcil.IO.Messages.pas 9 Aug 2004 11:16:54 -0000 1.1 --- fdcil.IO.Messages.pas 15 Aug 2004 11:34:46 -0000 1.2 *************** *** 31,35 **** function MessageTypeToString(MessageType: TMessageType): string; public ! procedure Emit(MessageType: TMessageType; Message: string); end; --- 31,37 ---- function MessageTypeToString(MessageType: TMessageType): string; public ! procedure Emit(MessageType: TMessageType; Message: string); overload; ! procedure Emit(MessageType: TMessageType; Line, Col: Integer; ! Message: string); overload; end; *************** *** 50,53 **** --- 52,57 ---- { TMessageEmitter } + // TODO: add a MessageEmitter.Emit(E: Exception) method? + procedure TMessageEmitter.Emit(MessageType: TMessageType; Message: string); begin *************** *** 55,58 **** --- 59,70 ---- end; + procedure TMessageEmitter.Emit(MessageType: TMessageType; Line, + Col: Integer; Message: string); + begin + // TODO: 'filename' needs to be passed + Console.WriteLine('[' + MessageTypeToString(MessageType) + '] ' + + 'FileName(' + Line.ToString() + '): ' + Message); + end; + function TMessageEmitter.MessageTypeToString( MessageType: TMessageType): string; Index: fdcil.SymbolTable.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.SymbolTable.pas,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** fdcil.SymbolTable.pas 9 Aug 2004 11:16:54 -0000 1.1 --- fdcil.SymbolTable.pas 15 Aug 2004 11:34:46 -0000 1.2 *************** *** 71,74 **** --- 71,77 ---- AddKeyword('library', MakeSymbol(True, T_LIBRARY)); AddKeyword('package', MakeSymbol(True, T_PACKAGE)); + AddKeyword('interface', MakeSymbol(True, T_INTERFACE)); + AddKeyword('implementation', MakeSymbol(True, T_IMPLEMENTATION)); + AddKeyword('uses', MakeSymbol(True, T_USES)); AddKeyword('begin', MakeSymbol(True, T_BEGIN)); AddKeyword('end', MakeSymbol(True, T_END)); *************** *** 78,82 **** AddKeyword('div', MakeSymbol(True, T_INT_DIVIDE_OP)); AddKeyword('mod', MakeSymbol(True, T_MODULO)); - AddKeyword('uses', MakeSymbol(True, T_USES)); AddKeyword('<', MakeSymbol(True, T_LT_OP)); --- 81,84 ---- Index: fdcil.ExceptionHandling.pas =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/fdcil-test/fdcil.ExceptionHandling.pas,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** fdcil.ExceptionHandling.pas 9 Aug 2004 11:16:54 -0000 1.1 --- fdcil.ExceptionHandling.pas 15 Aug 2004 11:34:46 -0000 1.2 *************** *** 24,31 **** interface type ! EParserError = class(System.Exception); implementation end. --- 24,64 ---- interface + uses + fdcil.IO.Messages.Localize, + fdcil.Tokens; + type ! EfdcilError = class(System.Exception) ! public ! fLine: Integer; ! fColumn: Integer; ! public ! property Line: Integer read fLine write fLine; ! property Column: Integer read fColumn write fColumn; ! end; ! ! EParserError = class(EfdcilError); ! // Raising this will pass by error recovery and stop parsing/compiling ! EFatalError = class(EfdcilError); ! ! EExpectedError = class(EfdcilError) ! public ! constructor Create(Expected, Found: string); ! end; ! ! const ! StatementSync: array[0..2] of Integer = ! (T_SEMICOLON, T_BEGIN, T_END); ! InterfaceSync: array[1..5] of Integer = ! (T_USES, T_TYPE, T_VAR, T_CONST, T_IMPLEMENTATION); implementation + { EExpectedError } + + constructor EExpectedError.Create(Expected, Found: string); + begin + inherited Create(System.String.Format(E_UNEXPECTED, [Expected, Found])); + end; + end. |
|
From: Michael E. <mir...@us...> - 2004-08-09 11:17:04
|
Update of /cvsroot/fdcil/dev/miracle2k/fdcil-test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9368/miracle2k/fdcil-test Added Files: .cvsignore fdcil.CommandLine.pas fdcil.Compiler.pas fdcil.ExceptionHandling.pas fdcil.IO.Input.pas fdcil.IO.Messages.Localize.pas fdcil.IO.Messages.pas fdcil.Lexer.pas fdcil.Parser.pas fdcil.SymbolTable.pas fdcil.Tokenizer.pas fdcil.Tokens.pas fdcil.bdsproj fdcil.cfg fdcil.dpr test.pas Log Message: created module structure for testing; simple parsing already working; --- NEW FILE: .cvsignore --- *.exe *.dcuil *.rsp *.pdb Model --- NEW FILE: fdcil.Compiler.pas --- {----------------------------------------------------------------------------- The contents of this file are subject to the GNU General Public License Version 1.1 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Michael Elsdörfer. All Rights Reserved. $Id: fdcil.Compiler.pas,v 1.1 2004/08/09 11:16:54 miracle2k Exp $ You may retrieve the latest version of this file at the fdcil homepage, located at http://fdcil.sourceforge.net Known Issues: -----------------------------------------------------------------------------} unit fdcil.Compiler; interface uses System.IO, fdcil.ExceptionHandling, fdcil.CommandLine, fdcil.IO.Messages, fdcil.IO.Input, fdcil.SymbolTable, fdcil.Lexer, fdcil.Parser; type TDelphiCompiler = class(System.Object) public constructor Create(CommandLineParser: TCommandLineParser); procedure CompileFile(FileName: string); end; implementation uses fdcil.IO.Messages.Localize; { TDelphiCompiler } procedure TDelphiCompiler.CompileFile(FileName: string); var Input: TFileInput; Lexer: TLexer; Parser: TDelphiParser; SymbolTable: TSymbolTable; begin try SymbolTable := TSymbolTable.Create; SymbolTable.Init; Input := TFileInput.Create(FileName); Lexer := TLexer.Create(Input, SymbolTable); Parser := TDelphiParser.Create(Lexer); Parser.Init; Parser.&Program; except on E: FileNotFoundException do MessageEmitter.Emit(mtFatal, System.String.Format(E_FILE_NOT_FOUND, FileName)); on E: EParserError do MessageEmitter.Emit(mtError, E.Message); end; end; constructor TDelphiCompiler.Create(CommandLineParser: TCommandLineParser); begin inherited Create; end; end. --- NEW FILE: fdcil.Parser.pas --- {----------------------------------------------------------------------------- The contents of this file are subject to the GNU General Public License Version 1.1 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Michael Elsdörfer. All Rights Reserved. $Id: fdcil.Parser.pas,v 1.1 2004/08/09 11:16:54 miracle2k Exp $ You may retrieve the latest version of this file at the fdcil homepage, located at http://fdcil.sourceforge.net Known Issues: -----------------------------------------------------------------------------} unit fdcil.Parser; interface uses fdcil.ExceptionHandling, fdcil.IO.Messages, fdcil.Tokens, fdcil.Lexer; type TDelphiParser = class(System.Object) private fLexer: TLexer; protected procedure Match(Token: Integer); procedure Next; procedure &Implementation; procedure Block; public function get_CurrentToken: Integer; public constructor Create(Lexer: TLexer); procedure &Program; procedure Init; property Look: Integer read get_CurrentToken; end; implementation { TDelphiParser } procedure TDelphiParser.&Program; begin if Look = T_PROGRAM then begin Match(T_PROGRAM); Match(T_IDENT); Match(T_SEMICOLON); &Implementation; Block; end else if Look = T_UNIT then begin //Match(T_UNIT); Match(T_IDENT); Match(T_SEMICOLON); //Match(T_END); Match(T_DOT); raise EParserError.Create('Units not yet supported'); end else if Look = T_PACKAGE then begin //Match(T_PACKAGE); Match(T_IDENT); Match(T_SEMICOLON); //Block; raise EParserError.Create('Packages not yet supported'); end else if Look = T_LIBRARY then begin //Match(T_LIBRARY); Match(T_IDENT); Match(T_SEMICOLON); //Block; raise EParserError.Create('Libraries not yet supported'); end else raise EParserError.Create('PROGRAM, UNIT, PACKAGE OR LIBRARY expected'); // TODO: make localizable if Look <> T_NULL then MessageEmitter.Emit(mtHint, 'Text after final ''End.'' is ignored by compiler'); end; procedure TDelphiParser.Block; begin try Match(T_BEGIN); Match(T_END); Match(T_SEMICOLON); except // We can continue with parsing and find more errors on E: EParserError do MessageEmitter.Emit(mtError, E.Message); end; end; constructor TDelphiParser.Create(Lexer: TLexer); begin inherited Create; fLexer := Lexer; end; procedure TDelphiParser.Init; begin fLexer.GetToken; end; procedure TDelphiParser.Match(Token: Integer); begin if fLexer.CurrToken.Token = Token then Next else raise EParserError.Create('Expected ' + Token.ToString()); end; procedure TDelphiParser.Next; begin fLexer.GetToken; end; function TDelphiParser.get_CurrentToken: Integer; begin Result := fLexer.CurrToken.Token; end; procedure TDelphiParser.&Implementation; begin case Look of T_USES: begin Next; repeat Match(T_IDENT); // TODO: Delphi for .NET supports namespaces; unit names may contain "." characters case Look of T_COMMA: Next; T_SEMICOLON: begin Match(T_SEMICOLON); break; end; else raise EParserError.Create('Expected ; or ,'); end; until False; end; T_TYPE: begin end; T_VAR: begin end; T_CONST: begin end; T_RESOURCESTRING: begin end; end; end; end. --- NEW FILE: fdcil.IO.Input.pas --- {----------------------------------------------------------------------------- The contents of this file are subject to the GNU General Public License Version 1.1 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Andreas Hausladen. All Rights Reserved. $Id: fdcil.IO.Input.pas,v 1.1 2004/08/09 11:16:54 miracle2k Exp $ You may retrieve the latest version of this file at the fdcil homepage, located at http://fdcil.sourceforge.net Known Issues: -----------------------------------------------------------------------------} unit fdcil.IO.Input; interface uses System.IO, System.Text; type TBaseInput = class(System.Object) protected Bytes: array of Byte; fEncoding: Encoding; fOffset: Integer; procedure DetectEncoding; public constructor Create; overload; function GetEverything: string; virtual; property Encoding: Encoding read FEncoding; end; TFileInput = class(TBaseInput) public constructor Create(FileName: string); overload; procedure LoadFromFile(FileName: string); function GetEverything: string; override; end; implementation { TBaseInput } constructor TBaseInput.Create; begin inherited Create; fEncoding := nil; end; function TBaseInput.GetEverything: string; begin if Encoding = nil then DetectEncoding; Result := Encoding.GetString(Bytes, fOffset, Length(Bytes) - fOffset) end; procedure TBaseInput.DetectEncoding; function IsPreamble(const Bytes, Preamble: array of Byte): Boolean; var Len, i: Integer; begin Result := False; Len := Length(Preamble); if Length(Bytes) >= Len then begin for i := 0 to Len - 1 do if (Bytes[i] <> Preamble[i]) then Exit; Result := True; end; end; begin if Length(Bytes) > 0 then begin if fEncoding = nil then begin if IsPreamble(Bytes, Encoding.Unicode.GetPreamble) then fEncoding := Encoding.Unicode else if IsPreamble(Bytes, Encoding.BigEndianUnicode.GetPreamble) then fEncoding := Encoding.BigEndianUnicode else if IsPreamble(Bytes, Encoding.UTF8.GetPreamble) then fEncoding := Encoding.UTF8 else if IsPreamble(Bytes, Encoding.UTF7.GetPreamble) then fEncoding := Encoding.UTF7 else fEncoding := Encoding.Default; fOffset := Length(Encoding.GetPreamble); end else begin fEncoding := Encoding; if IsPreamble(Bytes, fEncoding.GetPreamble) then fOffset := Length(fEncoding.GetPreamble) else fOffset := 0; end; end; end; { TFileInput } constructor TFileInput.Create(FileName: string); begin inherited Create; LoadFromFile(FileName); end; function TFileInput.GetEverything: string; begin Result := inherited GetEverything; end; procedure TFileInput.LoadFromFile(FileName: string); var SourceFile: FileStream; begin SourceFile := FileStream.Create(FileName, FileMode.Open); try SetLength(Bytes, SourceFile.Length - SourceFile.Position); SourceFile.Read(Bytes, 0, SourceFile.Length); finally SourceFile.Close; end; end; end. --- NEW FILE: fdcil.Tokenizer.pas --- {----------------------------------------------------------------------------- The contents of this file are subject to the GNU General Public License Version 1.1 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Andreas Hausladen. All Rights Reserved. $Id: fdcil.Tokenizer.pas,v 1.1 2004/08/09 11:16:54 miracle2k Exp $ You may retrieve the latest version of this file at the fdcil homepage, located at http://fdcil.sourceforge.net Known Issues: -----------------------------------------------------------------------------} unit fdcil.Tokenizer; interface {$REGION 'Interface uses'} uses System.Collections, fdcil.Tokens; {$ENDREGION} {$REGION 'class TDelphiTokenizer'} implementation { TDelphiTokenizer } {function TDelphiTokenizer.GetToken: TToken; // Delphi specific hint: System.String[index] is 1-based in Delphi means "idx<CodeLen" => "idx<=CodeLen" var Idx: Integer; IsDecimal: Boolean; IsExp: Boolean; IsExpSign: Boolean; Data: string; CodeLen: Integer; Ch, Ch2: Char; begin Result := TToken.Create; Result.Token := T_NULL; // local variables are faster than instance fields Idx := Index; CodeLen := FCodeLen; Data := FCode; // go to next token and skip white chars while Idx <= CodeLen do begin Ch := Data[Idx]; if not System.Char.IsWhiteSpace(Ch) (AnsiChar(Ch) in WhiteSpaces) then Break; if (Ch = #10) or (Ch = #13) then HandleLineFeed(Idx); Inc(Idx); end; if Idx > CodeLen then Exit; Result.Line := FLineNum; Result.Index := Idx; Result.Column := Idx - FLineStartIndex; FIndex := Idx; // start index for this token // preload two chars Ch := Data[Idx]; if Idx + 1 <= CodeLen then Ch2 := Data[Idx + 1] else Ch2 := #0; // ------------ string '...' ------------- if Ch = '''' then begin Inc(Idx); // string while Idx <= CodeLen do begin case Data[Idx] of '''': begin if (Idx <= CodeLen) and (Data[Idx + 1] = '''') then Inc(Idx) else Break; end; #10, #13: begin Dec(Idx); Break; // line end is string end in Delphi end; end; Inc(Idx); end; if Idx <= CodeLen then Inc(Idx); // include ending "'" Result.Token := T_STRING; end // ------------ comment { ... ------------- else if (Ch = '{') then begin // comment { ... -> find comment end Inc(Idx); if Data[Idx] = '$' then begin Result.Token := T_DIRECTIVE; Inc(Idx); end else Result.Token := T_COMMENT; // TODO: What to do here? I think will should just omit comments while Idx <= CodeLen do begin Ch := Data[Idx]; if Ch = '' then Break; if (Ch = #10) or (Ch = #13) then HandleLineFeed(Idx); Inc(Idx); end; if Idx <= CodeLen then Inc(Idx); // include ending "" end // ------------ comment (* ... *) ------------- else if (Ch = '(') and (Ch2 = '*') then begin // comment (* ... *) -> find comment end Inc(Idx, 2); if Data[Idx] = '$' then begin Result.Token := T_DIRECTIVE; Inc(Idx); end else Result.Token := T_COMMENT; // TODO: What to do here? I think will should just omit comments while Idx < CodeLen do // not "<=" begin Ch := Data[Idx]; if (Ch = '*') and (Data[Idx + 1] = ')') then Break; if (Ch = #10) or (Ch = #13) then HandleLineFeed(Idx); Inc(Idx); end; if Idx <= CodeLen then Inc(Idx, 2); // include ending "*)" end // ------------ comment // ... ------------- else if (Ch = '/') and (Ch2 = '/') then begin // comment "// ..." -> find comment end Inc(Idx, 2); while Idx <= CodeLen do begin Ch := Data[Idx]; if (Ch = #10) or (Ch = #13) then Break; Inc(Idx); end; Result.Token := T_COMMENT; // TODO: again: omit? end // ------------ identifier begin variablename ------------- else if System.Char.IsLetter(Ch) or (Ch = '_') {AnsiChar(Ch) in IdentFirstChars then begin // identifier Inc(Idx); while (Idx <= CodeLen) and (System.Char.IsLetterOrDigit(Data[Idx]) or (Data[Idx] = '_')) {(AnsiChar(Data[Idx]) in IdentChars) do Inc(Idx); Result.Token := T_IDENT; end // ------------ number +1 -1 10 1.3 -0.2e10 +0.3E10 ------------- else if System.Char.IsDigit(Ch) then begin // number Inc(Idx); IsDecimal := False; IsExp := False; IsExpSign := False; while Idx <= CodeLen do begin case Data[Idx] of '0'..'9': ; '.': if IsDecimal or IsExp then Break else IsDecimal := True; '+', '-': if not IsExp or IsExpSign then Break else IsExpSign := True; 'e', 'E': if IsDecimal or IsExp then Break else IsExp := True; else Break; end; Inc(Idx); end; if IsExp or IsDecimal then Result.Token := T_FLOAT else Result.Token := T_INT; end // ------------ number hex $xx ------------- else if (Ch = '$') and ((Word(Ch2) <= $FF) and (AnsiChar(Ch2) in HexNumberChars)) then begin // hex number Inc(Idx, 2); while Idx <= CodeLen do begin Ch := Data[Idx]; if (Word(Ch) > $FF) or not (AnsiChar(Ch) in HexNumberChars) then Break; Inc(Idx); end; Result.Token := T_INT; end // ------------ char #13 #$10 ------------- else if (Ch = '#') and ((Ch2 = '$') or System.Char.IsDigit(Ch2)) {(AnsiChar(Ch2) in NumberChars)) then begin // char Inc(Idx, 2); if (Idx > 1) and (Data[Idx - 1] = '$') then begin while Idx <= CodeLen do begin Ch := Data[Idx]; if (Word(Ch) > $FF) or not (AnsiChar(Ch) in HexNumberChars) then Break; Inc(Idx); end; end else begin while (Idx <= CodeLen) and System.Char.IsDigit(Data[idx]) {(AnsiChar(Data[Idx]) in NumberChars) do Inc(Idx); end; Result.Token := T_STRING; end // ------------ symbol (single char) ------------- else if (Word(Ch) <= $FF) and (AnsiChar(Ch) in OneSymbolChars) then begin Inc(Idx); Result.Token := T_ADD_OP; // TODO: merge detecting of operators into lexer end else // ------------ symbol (multiple chars) ------------- begin while (Word(Ch) <= $FF) and (AnsiChar(Data[Idx]) in SymbolChars) do Inc(Idx); Result.Token := T_ADD_OP; // TODO: merge detecting of operators into lexer end; Result.Length := Idx - Result.Index; // TODO: copy data into token //Result.FToken := Copy(Data, FIndex, Idx - FIndex); FIndex := Idx; end; { Some files have strange line breaks. } (*procedure TDelphiTokenizer.HandleLineFeed(var Idx: Integer); begin Inc(FLineNum); if Idx + 1 < FCodeLen then begin if FCode[Idx] = #10 then begin if FCode[Idx + 1] = #13 then Inc(Idx); end else if FCode[Idx] = #13 then begin if FCode[Idx + 1] = #10 then Inc(Idx); end end; FLineStartIndex := Idx + 1; end; *) end. --- NEW FILE: fdcil.dpr --- {----------------------------------------------------------------------------- The contents of this file are subject to the GNU General Public License Version 1.1 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Michael Elsdörfer. All Rights Reserved. $Id: fdcil.dpr,v 1.1 2004/08/09 11:16:54 miracle2k Exp $ You may retrieve the latest version of this file at the fdcil homepage, located at http://fdcil.sourceforge.net Known Issues: -----------------------------------------------------------------------------} program fdcil; {$APPTYPE CONSOLE} uses fdcil.CommandLine in 'fdcil.CommandLine.pas', fdcil.Tokens in 'fdcil.Tokens.pas', fdcil.Compiler in 'fdcil.Compiler.pas', fdcil.Tokenizer in 'fdcil.Tokenizer.pas', fdcil.Lexer in 'fdcil.Lexer.pas', fdcil.Parser in 'fdcil.Parser.pas', fdcil.IO.Input in 'fdcil.IO.Input.pas', fdcil.IO.Messages in 'fdcil.IO.Messages.pas', fdcil.IO.Messages.Localize in 'fdcil.IO.Messages.Localize.pas', fdcil.SymbolTable in 'fdcil.SymbolTable.pas', fdcil.ExceptionHandling in 'fdcil.ExceptionHandling.pas'; var CommandLineParser: TCommandLineParser; Compiler: TDelphiCompiler; Lexer: TLexer; Input: TFileInput; SymbolTable: TSymbolTable; i: Integer; begin CommandLineParser := TCommandLineParser.Create(True); with CommandLineParser.Options[oiSourceFiles] do if IsSet then begin Compiler := TDelphiCompiler.Create(CommandLineParser); Compiler.CompileFile(string(Value)); end else Writeln('FileName is missing'); (* repeat i := Environment.TickCount; //Input := TFileInput.Create('F:\Developing\Projects\fdcil\dev\miracle2k\fdcil-test\fdcil.Lexer.pas'); //C:\Programme\Borland\BDS\2.0\source\rtl\Borland.Vcl.Windows.pas'); Input := TFileInput.Create('C:\Programme\Borland\BDS\2.0\source\rtl\Borland.Vcl.Windows.pas'); SymbolTable := TSymbolTable.Create; SymbolTable.Init; Lexer := TLexer.Create(Input, SymbolTable); try repeat Lexer.GetToken; (*Console.WriteLine(Lexer.CurrToken.Token.ToString()+ ':' + Lexer.CurrToken.Value) until Lexer.CurrToken.Token = T_NULL; except raise; end; Console.WriteLine(Environment.TickCount - i); Readln; until False;*) {$IFDEF IDE_DEBUG} Readln; {$ENDIF} end. --- NEW FILE: fdcil.bdsproj --- (This appears to be a binary file; contents omitted.) --- NEW FILE: test.pas --- program test; uses test, test2; begin end; --- NEW FILE: fdcil.Lexer.pas --- {----------------------------------------------------------------------------- The contents of this file are subject to the GNU General Public License Version 1.1 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Andreas Hausladen. All Rights Reserved. $Id: fdcil.Lexer.pas,v 1.1 2004/08/09 11:16:54 miracle2k Exp $ You may retrieve the latest version of this file at the fdcil homepage, located at http://fdcil.sourceforge.net Known Issues: -----------------------------------------------------------------------------} unit fdcil.Lexer; interface uses System.Collections, fdcil.IO.Input, fdcil.SymbolTable, fdcil.Tokens, fdcil.Tokenizer; {$DEFINE AdRRAY_ACCESS} const Linebreaks = [#10, #13]; WhiteSpace = [#9, #32] + Linebreaks; NumberChars = ['0'..'9']; NumberFirstChars = NumberChars + ['$']; IdentFirstChars = ['a'..'z', 'A'..'Z', '_']; IdentChars = IdentFirstChars + NumberChars; SymbolChars = ['(', ')', '[', ']', ';', '@', '^', '/', '''', '+', '-', '<', '>', '=', ':', '.', ',', '&', '#']; type TToken = record Line: Integer; Column: Integer; &Index: Integer; Token: Integer; Value: string; end; {$IFDEF ARRAY_ACCESS} {$REGION 'ArrayAccess Lexer'} TLexer = class(System.Object) private fSymbolTable: TSymbolTable; protected FCode: string; FIndex: Integer; FCodeLen: Integer; FLineNum: Integer; FLineStartIndex: Integer; fCurrentToken: TToken; procedure HandleLineFeed(var Idx: Integer); public constructor Create(Input: TBaseInput; SymbolTable: TSymbolTable); function GetToken: TToken; overload; function GetToken(out p: TToken): Boolean; overload; property CurrToken: TToken read fCurrentToken; end; {$ENDREGION} {$ELSE} {$REGION 'GetChar Lexer'} TLexer = class(System.Object) private fSymbolTable: TSymbolTable; protected Data: string; Index, Line, Column: Integer; Look: Char; protected fCurrentToken: TToken; protected procedure GetChar; public constructor Create(Input: TBaseInput; SymbolTable: TSymbolTable); procedure GetToken; property CurrToken: TToken read fCurrentToken; end; {$ENDREGION} {$ENDIF} implementation { TLexer } {$IFDEF ARRAY_ACCESS} {$REGION 'ArrayAccess Lexer'} constructor TLexer.Create(Input: TBaseInput; SymbolTable: TSymbolTable); begin inherited Create; fSymbolTable := SymbolTable; FCode := Input.GetEverything; FCodeLen := FCode.Length; FIndex := 1; // Line := 1; // Column := 0; end; function TLexer.GetToken: TToken; // Delphi specific hint: System.String[index] is 1-based in Delphi means "idx<CodeLen" => "idx<=CodeLen" var Idx: Integer; IsDecimal: Boolean; IsExp: Boolean; IsExpSign: Boolean; Data: string; CodeLen: Integer; Ch, Ch2: Char; begin Result.Token := T_NULL; // local variables are faster than instance fields Idx := FIndex; CodeLen := FCodeLen; Data := FCode; while (Result.Token = T_NULL) and (Idx < CodeLen) do begin // go to next token and skip white chars while Idx <= CodeLen do begin Ch := Data[Idx]; if not System.Char.IsWhiteSpace(Ch) { (AnsiChar(Ch) in WhiteSpaces)} then Break; if (Ch = #10) or (Ch = #13) then HandleLineFeed(Idx); Inc(Idx); end; if Idx > CodeLen then begin FIndex := Idx; Exit; end; Result.Line := FLineNum; Result.Index := Idx; Result.Column := Idx - FLineStartIndex; FIndex := Idx; // start index for this token // preload two chars Ch := Data[Idx]; if Idx + 1 <= CodeLen then Ch2 := Data[Idx + 1] else Ch2 := #0; // ------------ string '...' ------------- if Ch = '''' then begin Inc(Idx); // string while Idx <= CodeLen do begin case Data[Idx] of '''': begin if (Idx <= CodeLen) and (Data[Idx + 1] = '''') then Inc(Idx) else Break; end; #10, #13: begin Dec(Idx); Break; // line end is string end in pascal end; end; Inc(Idx); end; if Idx <= CodeLen then Inc(Idx); // include ending "'" Result.Token := T_STRING; end // ------------ comment { ... } ------------- else if (Ch = '{') then begin // comment { ... } -> find comment end Inc(Idx); if Data[Idx] = '$' then begin Result.Token := T_DIRECTIVE; Inc(Idx); end; while Idx <= CodeLen do begin Ch := Data[Idx]; if Ch = '}' then Break; if (Ch = #10) or (Ch = #13) then HandleLineFeed(Idx); Inc(Idx); end; if Idx <= CodeLen then Inc(Idx); // include ending "}" end // ------------ comment (* ... *) ------------- else if (Ch = '(') and (Ch2 = '*') then begin // comment (* ... *) -> find comment end Inc(Idx, 2); if Data[Idx] = '$' then begin Result.Token := T_DIRECTIVE; Inc(Idx); end; while Idx < CodeLen do // not "<=" begin Ch := Data[Idx]; if (Ch = '*') and (Data[Idx + 1] = ')') then Break; if (Ch = #10) or (Ch = #13) then HandleLineFeed(Idx); Inc(Idx); end; if Idx <= CodeLen then Inc(Idx, 2); // include ending "*)" end // ------------ comment // ... ------------- else if (Ch = '/') and (Ch2 = '/') then begin // comment "// ..." -> find comment end Inc(Idx, 2); while Idx <= CodeLen do begin Ch := Data[Idx]; if (Ch = #10) or (Ch = #13) then Break; Inc(Idx); end; end // ------------ identifier begin variablename ------------- else if System.Char.IsLetter(Ch) or (Ch = '_') {AnsiChar(Ch) in IdentFirstChars} then begin // identifier Inc(Idx); while (Idx <= CodeLen) and (System.Char.IsLetterOrDigit(Data[Idx]) or (Data[Idx] = '_')) {(AnsiChar(Data[Idx]) in IdentChars)} do Inc(Idx); Result.Token := T_IDENT; end // ------------ number +1 -1 10 1.3 -0.2e10 +0.3E10 ------------- else if System.Char.IsDigit(Ch) then begin // number Inc(Idx); IsDecimal := False; IsExp := False; IsExpSign := False; while Idx <= CodeLen do begin case Data[Idx] of '0'..'9': ; '.': if IsDecimal or IsExp then Break else IsDecimal := True; '+', '-': if not IsExp or IsExpSign then Break else IsExpSign := True; 'e', 'E': if IsDecimal or IsExp then Break else IsExp := True; else Break; end; Inc(Idx); end; Result.Token := T_INT; end // ------------ number hex $xx ------------- else if (Ch = '$') and ((Word(Ch2) <= $FF) and (AnsiChar(Ch2) in ['0'..'9', 'A'..'Z','a'..'f'])) then begin // hex number Inc(Idx, 2); while Idx <= CodeLen do begin Ch := Data[Idx]; if (Word(Ch) > $FF) or not (AnsiChar(Ch) in ['0'..'9', 'A'..'Z','a'..'f']) then Break; Inc(Idx); end; Result.Token := T_INT; end // ------------ char #13 #$10 ------------- else if (Ch = '#') and ((Ch2 = '$') or System.Char.IsDigit(Ch2)) {(AnsiChar(Ch2) in NumberChars))} then begin // char Inc(Idx, 2); if (Idx > 1) and (Data[Idx - 1] = '$') then begin while Idx <= CodeLen do begin Ch := Data[Idx]; //if (Word(Ch) > $FF) or not (AnsiChar(Ch) in HexNumberChars) then // Break; Inc(Idx); end; end else begin while (Idx <= CodeLen) and System.Char.IsDigit(Data[idx]) {(AnsiChar(Data[Idx]) in NumberChars)} do Inc(Idx); end; Result.Token := T_STRING; end // ------------ symbol (single char) ------------- else if (Word(Ch) <= $FF) and (AnsiChar(Ch) in SymbolChars) then begin case Ch of '+': Result.Token := T_ADD_OP; '-': Result.Token := T_SUBTRACT_OP; '*': Result.Token := T_MULTIPLY_OP; '/': Result.Token := T_DIVIDE_OP; '(': Result.Token := T_LPAREN; ')': Result.Token := T_RPAREN; '[': Result.Token := T_LBRACKET; ']': Result.Token := T_RBRACKET; '<': begin Result.Token := T_LE_OP; // GetChar; // if Look = '=' then begin Result.Token := T_LE_OP; Value := Value + Look; end // else begin Result.Token := T_LT_OP; exit; end; end; '>': begin Result.Token := T_LE_OP; // GetChar; // if Look = '=' then begin Result.Token := T_GE_OP; Value := Value + Look; end // else begin Result.Token := T_GT_OP; exit; end; end; '@': Result.Token := T_AT; '^': Result.Token := T_POINTER; '=': Result.Token := T_EQUAL; ':': Result.Token := T_COLON; ';': Result.Token := T_SEMICOLON; '.': Result.Token := T_DOT; ',': Result.Token := T_COMMA; '&': Result.Token := T_AMPERSAND; '#': Result.Token := T_SHARP; '''': Result.Token := T_HOCHKOMMA; // else raise Exception.Create('Unkown Symbol:' + Look); end; Inc(Idx); end else // ------------ symbol (multiple chars) ------------- begin //while (Word(Ch) <= $FF) and (AnsiChar(Data[Idx]) in SymbolChars) do // Inc(Idx); //Result.Token := T_ADD_OP; Console.WriteLine(Ch); Console.WriteLine(FLineNum); sleep(1000); end; end; //Console.WriteLine(FIndex); //sleep(1000); Result.Value := Copy(Data, FIndex, Idx - FIndex); FIndex := Idx; fCurrentToken := Result; end; { Some files have strange line breaks. } procedure TLexer.HandleLineFeed(var Idx: Integer); begin Inc(FLineNum); if Idx + 1 < FCodeLen then begin if FCode[Idx] = #10 then begin if FCode[Idx + 1] = #13 then Inc(Idx); end else if FCode[Idx] = #13 then begin if FCode[Idx + 1] = #10 then Inc(Idx); end end; FLineStartIndex := Idx + 1; end; function TLexer.GetToken(out p: TToken): Boolean; begin p := GetToken; Result := p.Token <> T_NULL; end; {$ENDREGION} {$ELSE} {$REGION 'GetChar Lexer'} constructor TLexer.Create(Input: TBaseInput; SymbolTable: TSymbolTable); begin inherited Create; fSymbolTable := SymbolTable; Data := Input.GetEverything; Index := 0; Line := 1; Column := 0; Look := #0; GetChar; end; procedure TLexer.GetToken; var Token: Integer; Value: string; procedure HandleLineBreak; begin // TODO: Is this correct? if Look in Linebreaks then begin if Look = #13 then begin GetChar; if Look = #10 then GetChar; end else if Look = #10 then begin GetChar; if Look = #13 then GetChar; end; Inc(Line); Column := 0; end; end; procedure Comment; begin repeat GetChar; if Look in LineBreaks then HandleLineBreak; if Look = '*' then begin GetChar; if Look = ')' then break; end until False; GetChar; end; procedure LineComment; begin repeat GetChar; until Look in Linebreaks; HandleLineBreak; end; procedure CurlyComment; begin repeat GetChar; if Look = '}' then break else if Look in LineBreaks then HandleLineBreak; until False; GetChar; end; procedure CompilerDirective; // TODO: currently stops at the first whitespace; fix it begin Token := T_DIRECTIVE; GetChar; while (Look in IdentFirstChars) do begin GetChar; Value := Value + Look; end; end; procedure &Symbol; // TODO: use symbol table to load tokens begin Value := Look; case Look of '+': Token := T_ADD_OP; '-': Token := T_SUBTRACT_OP; '*': Token := T_MULTIPLY_OP; '/': Token := T_DIVIDE_OP; '(': Token := T_LPAREN; ')': Token := T_RPAREN; '[': Token := T_LBRACKET; ']': Token := T_RBRACKET; '<': begin GetChar; if Look = '=' then begin Token := T_LE_OP; Value := Value + Look; end else begin Token := T_LT_OP; exit; end; end; '>': begin GetChar; if Look = '=' then begin Token := T_GE_OP; Value := Value + Look; end else begin Token := T_GT_OP; exit; end; end; '@': Token := T_AT; '^': Token := T_POINTER; '=': Token := T_EQUAL; ':': Token := T_COLON; ';': Token := T_SEMICOLON; '.': Token := T_DOT; ',': Token := T_COMMA; '&': Token := T_AMPERSAND; '#': Token := T_SHARP; '''': Token := T_HOCHKOMMA; else raise Exception.Create('Unkown Symbol:' + Look); end; GetChar; end; procedure &String; begin Token := T_STRING; repeat GetChar; if Look = '''' then begin GetChar; if not (Look = '''') then break else Value := Value + ''''; end; Value := Value + Look; until False; GetChar; end; procedure Number; begin Token := T_INT; Value := Look; repeat GetChar; if not (Look in NumberChars) then break else Value := Value + Look; until False; end; procedure Ident; begin Value := Look; repeat GetChar; if not (Look in IdentChars) then break else Value := Value + Look; until False; Token := fSymbolTable.QueryKeyword(Value); if Token = T_NULL then Token := T_IDENT; end; begin Token := T_NULL; while (Token = T_NULL) and (Look <> #0) do begin // Whitespace while (Look in WhiteSpace) do begin if Look in Linebreaks then HandleLineBreak else GetChar; end; case Look of '}': begin // TODO: remove this! we need a real fix! GetChar; end; '(': begin GetChar; if Look = '*' then begin GetChar; if Look = '$' then CompilerDirective; Comment; end; end; '{': begin GetChar; if Look = '$' then CompilerDirective; CurlyComment; end; '/': begin GetChar; if Look = '/' then LineComment else Token := T_DIVIDE_OP; end; '''': &String; else begin if Look in IdentFirstChars then Ident else if Look in NumberFirstChars then Number else if Look in SymbolChars then Symbol //else raise Exception.Create('Invalid character'); end; end; end; fCurrentToken.Index := Index; fCurrentToken.Line := Line; fCurrentToken.Column := Column; fCurrentToken.Token := Token; fCurrentToken.Value := Value; end; procedure TLexer.GetChar; begin Inc(Index); if Index <= Data.Length then Look := Data[Index] else Look := #0; Inc(Column); end; {$ENDREGION} {$ENDIF} end. --- NEW FILE: fdcil.Tokens.pas --- {----------------------------------------------------------------------------- The contents of this file are subject to the GNU General Public License Version 1.1 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Michael Elsdörfer. All Rights Reserved. $Id: fdcil.Tokens.pas,v 1.1 2004/08/09 11:16:54 miracle2k Exp $ You may retrieve the latest version of this file at the fdcil homepage, located at http://fdcil.sourceforge.net Known Issues: -----------------------------------------------------------------------------} unit fdcil.Tokens; interface const // Special "null" token, indicating end of input T_NULL = 0000; // Root tokens T_PROGRAM = 1001; T_UNIT = 1002; T_LIBRARY = 1003; T_PACKAGE = 1004; // Basic tokens T_BEGIN = 2001; T_END = 2002; T_IF = 2003; T_THEN = 2004; T_ELSE = 2005; T_INTERFACE = 2006; T_IMPLEMENTATION = 2007; T_USES = 2008; T_TYPE = 2009; T_CONST = 2010; T_VAR = 2011; T_RESOURCESTRING = 2012; // Operators T_ADD_OP = 3001; T_SUBTRACT_OP = 3002; T_MULTIPLY_OP = 3003; T_INT_DIVIDE_OP = 3004; T_DIVIDE_OP = 3005; T_GT_OP = 3006; T_LT_OP = 3007; T_GE_OP = 3008; T_LE_OP = 3009; T_ASSIGN_OP = 3010; T_MODULO = 3011; // Symbols T_LPAREN = 4001; T_RPAREN = 4002; T_LBRACKET = 4003; T_RBRACKET = 4003; T_COLON = 4005; T_SEMICOLON = 4006; T_AT = 4007; T_POINTER = 4008; T_EQUAL = 4009; T_DOT = 4010; T_COMMA = 4011; T_SHARP = 4012; T_AMPERSAND = 4013; T_HOCHKOMMA = 4014; // Other tokens T_IDENT = 5001; T_STRING = 5002; T_INT = 5003; T_FLOAT = 5004; T_DIRECTIVE = 5010; implementation end. --- NEW FILE: fdcil.CommandLine.pas --- {----------------------------------------------------------------------------- The contents of this file are subject to the GNU General Public License Version 1.1 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Michael Elsdörfer. All Rights Reserved. $Id: fdcil.CommandLine.pas,v 1.1 2004/08/09 11:16:54 miracle2k Exp $ You may retrieve the latest version of this file at the fdcil homepage, located at http://fdcil.sourceforge.net Known Issues: -----------------------------------------------------------------------------} unit fdcil.CommandLine; interface uses System.Collections; type ECommandLineParser = class(Exception); TCommandLineOptionID = ( oiSourceFiles, // The list of source files to compile oiOutputFileName // Specify an output filename ); TCommandLineOptionType = ( otBool, // Either option is specified or missing otInt, // Option takes a numeric argument otString, // Option is a string agument otArrayList // Option can take multiple arguments ); // Represents an option; Stores not only definition related data (which is // initialized at start up), but also holds the Values of the option, after // the command line was parsed. TCommandLineOption = class public ID: TCommandLineOptionID; &Type: TCommandLineOptionType; Name: string; // Use '' to specify default option Value: System.Object; // Depends on type of option IsSet: boolean; // User has specified this option constructor Create(ID: TCommandLineOptionID; &Type: TCommandLineOptionType; Name: string); end; TCommandLineParser = class(System.Object) public // List of available options fOptions: System.Collections.ArrayList; // get/set accessors function get_Options(Option: TCommandLineOptionID): TCommandLineOption; function get_OptionsByIndex(Index: Integer): TCommandLineOption; function get_OptionCount: Integer; function get_OptionValues(Option: TCommandLineOptionID): System.Object; function get_OptionArrayListValues( Option: TCommandLineOptionID): System.Collections.ArrayList; function get_OptionBoolValues( Option: TCommandLineOptionID): Boolean; function get_OptionIntValues( Option: TCommandLineOptionID): Integer; function get_OptionStringValues( Option: TCommandLineOptionID): string; function GetDefaultOption: TCommandLineOption; protected procedure InitializeOptionList; procedure DefineOption(ID: TCommandLineOptionID; &Type: TCommandLineOptionType; Name: string); procedure AssertOptionType(Option: TCommandLineOptionID; RequiredType: TCommandLineOptionType); public constructor Create(AutoParse: Boolean = True); procedure ParseCommandLine; property OptionsByIndex[Index: Integer]: TCommandLineOption read get_OptionsByIndex; property OptionCount: Integer read get_OptionCount; property Options[Option: TCommandLineOptionID]: TCommandLineOption read get_Options; property DefaultOption: TCommandLineOption read GetDefaultOption; property OptionValues[Option: TCommandLineOptionID]: System.Object read get_OptionValues; property OptionBoolValues[Option: TCommandLineOptionID]: Boolean read get_OptionBoolValues; property OptionStringValues[Option: TCommandLineOptionID]: string read get_OptionStringValues; property OptionIntValues[Option: TCommandLineOptionID]: Integer read get_OptionIntValues; property OptionArrayListValues[Option: TCommandLineOptionID]: System.Collections.ArrayList read get_OptionArrayListValues; end; implementation { TCommandLineParser } procedure TCommandLineParser.AssertOptionType(Option: TCommandLineOptionID; RequiredType: TCommandLineOptionType); begin if Options[Option].&Type <> RequiredType then raise ECommandLineParser.Create('Option types do not match'); end; constructor TCommandLineParser.Create(AutoParse: Boolean); begin inherited Create; fOptions := ArrayList.Create; InitializeOptionList; if AutoParse then ParseCommandLine; end; procedure TCommandLineParser.DefineOption(ID: TCommandLineOptionID; &Type: TCommandLineOptionType; Name: string); var NewOption: TCommandLineOption; begin NewOption := TCommandLineOption.Create(ID, &Type, Name); fOptions.Add(NewOption); end; function TCommandLineParser.GetDefaultOption: TCommandLineOption; var i: Integer; begin Result := nil; for i := 0 to OptionCount - 1 do if OptionsByIndex[i].Name = '' then begin Result := OptionsByIndex[i]; break; end; end; function TCommandLineParser.get_OptionArrayListValues( Option: TCommandLineOptionID): ArrayList; begin AssertOptionType(Option, otArrayList); Result := ArrayList(OptionValues[Option]); end; function TCommandLineParser.get_OptionBoolValues( Option: TCommandLineOptionID): Boolean; begin AssertOptionType(Option, otBool); Result := Boolean(OptionValues[Option]); end; function TCommandLineParser.get_OptionCount: Integer; begin Result := fOptions.Count; end; function TCommandLineParser.get_OptionIntValues( Option: TCommandLineOptionID): Integer; begin AssertOptionType(Option, otInt); Result := Integer(OptionValues[Option]); end; function TCommandLineParser.get_Options(Option: TCommandLineOptionID): TCommandLineOption; var i: Integer; begin Result := nil; for i := 0 to OptionCount - 1 do if OptionsByIndex[i].ID = Option then begin Result := OptionsByIndex[i]; break; end; end; function TCommandLineParser.get_OptionsByIndex( Index: Integer): TCommandLineOption; begin Result := TCommandLineOption(fOptions[Index]); end; function TCommandLineParser.get_OptionStringValues( Option: TCommandLineOptionID): string; begin AssertOptionType(Option, otString); Result := string(OptionValues[Option]); end; function TCommandLineParser.get_OptionValues( Option: TCommandLineOptionID): System.Object; begin Result := Options[Option].Value; end; procedure TCommandLineParser.InitializeOptionList; begin DefineOption(oiSourceFiles, otString, ''); // '' = default option DefineOption(oiOutputFileName, otString, 'X'); end; procedure TCommandLineParser.ParseCommandLine; var i: Integer; Arguments: array of string; ArgName: string; begin Arguments := Environment.GetCommandLineArgs; i := 1; while i <= High(Arguments) do begin if Arguments[i][1] = '-' then begin // TODO: split into option name and option value + store the data ArgName := Arguments[i].Substring(2); end else if GetDefaultOption <> nil then begin GetDefaultOption.IsSet := True; case GetDefaultOption.&Type of otString: GetDefaultOption.Value := Arguments[i]; else raise ECommandLineParser.Create('Unsupported default argument'); end; end; Inc(I); end; end; { TCommandLineOption } constructor TCommandLineOption.Create(ID: TCommandLineOptionID; &Type: TCommandLineOptionType; Name: string); begin inherited Create; Self.ID := ID; Self.&Type := &Type; case &Type of otBool: Self.Value := System.Object(False); otInt: Self.Value := System.Object(0); otString: Self.Value := ''; otArrayList: Self.Value := ArrayList.Create; end; Self.Name := Name; Self.Value := nil; Self.IsSet := False; end; end. --- NEW FILE: fdcil.IO.Messages.Localize.pas --- {----------------------------------------------------------------------------- The contents of this file are subject to the GNU General Public License Version 1.1 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Michael Elsdörfer. All Rights Reserved. $Id: fdcil.IO.Messages.Localize.pas,v 1.1 2004/08/09 11:16:54 miracle2k Exp $ You may retrieve the latest version of this file at the fdcil homepage, located at http://fdcil.sourceforge.net Known Issues: -----------------------------------------------------------------------------} unit fdcil.IO.Messages.Localize; interface resourcestring E_FILE_NOT_FOUND = 'File not found: ''{0}'''; implementation end. --- NEW FILE: fdcil.IO.Messages.pas --- {----------------------------------------------------------------------------- The contents of this file are subject to the GNU General Public License Version 1.1 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Michael Elsdörfer. All Rights Reserved. $Id: fdcil.IO.Messages.pas,v 1.1 2004/08/09 11:16:54 miracle2k Exp $ You may retrieve the latest version of this file at the fdcil homepage, located at http://fdcil.sourceforge.net Known Issues: -----------------------------------------------------------------------------} unit fdcil.IO.Messages; interface type TMessageType = (mtFatal, mtError, mtHint); TMessageEmitter = class(System.Object) protected function MessageTypeToString(MessageType: TMessageType): string; public procedure Emit(MessageType: TMessageType; Message: string); end; function MessageEmitter: TMessageEmitter; implementation var InternalMessageEmitter: TMessageEmitter = nil; function MessageEmitter: TMessageEmitter; begin if InternalMessageEmitter = nil then InternalMessageEmitter := TMessageEmitter.Create; Result := InternalMessageEmitter; end; { TMessageEmitter } procedure TMessageEmitter.Emit(MessageType: TMessageType; Message: string); begin Console.WriteLine('[' + MessageTypeToString(MessageType) + '] ' + Message); end; function TMessageEmitter.MessageTypeToString( MessageType: TMessageType): string; begin case MessageType of mtFatal: Result := 'Fatal Error'; mtError: Result := 'Error'; mtHint: Result := 'Hint'; else raise Exception.Create('Description for message type is missing'); end; end; end. --- NEW FILE: fdcil.SymbolTable.pas --- {----------------------------------------------------------------------------- The contents of this file are subject to the GNU General Public License Version 1.1 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Michael Elsdörfer. All Rights Reserved. $Id: fdcil.SymbolTable.pas,v 1.1 2004/08/09 11:16:54 miracle2k Exp $ You may retrieve the latest version of this file at the fdcil homepage, located at http://fdcil.sourceforge.net Known Issues: -----------------------------------------------------------------------------} unit fdcil.SymbolTable; interface uses System.Collections; type TSymbol = record IsSpecial: Boolean; Token: Integer; end; TSymbolTable = class(System.Object) private fSymbols: HashTable; protected function MakeSymbol(IsSpecial: Boolean; Token: Integer): TSymbol; public constructor Create; procedure Init; procedure AddKeyword(Name: string; Symbol: TSymbol); function QueryKeyword(Keyword: string): Integer; end; implementation uses fdcil.Tokens; { TSymbolTable } procedure TSymbolTable.AddKeyword(Name: string; Symbol: TSymbol); begin fSymbols.Add(Symbol, Name); fSymbols.Add(Name, Symbol); end; constructor TSymbolTable.Create; begin inherited; fSymbols := Hashtable.Create; end; procedure TSymbolTable.Init; begin AddKeyword('program', MakeSymbol(True, T_PROGRAM)); AddKeyword('unit', MakeSymbol(True, T_UNIT)); AddKeyword('library', MakeSymbol(True, T_LIBRARY)); AddKeyword('package', MakeSymbol(True, T_PACKAGE)); AddKeyword('begin', MakeSymbol(True, T_BEGIN)); AddKeyword('end', MakeSymbol(True, T_END)); AddKeyword('if', MakeSymbol(True, T_IF)); AddKeyword('then', MakeSymbol(True, T_THEN)); AddKeyword('else', MakeSymbol(True, T_ELSE)); AddKeyword('div', MakeSymbol(True, T_INT_DIVIDE_OP)); AddKeyword('mod', MakeSymbol(True, T_MODULO)); AddKeyword('uses', MakeSymbol(True, T_USES)); AddKeyword('<', MakeSymbol(True, T_LT_OP)); AddKeyword('>', MakeSymbol(True, T_GT_OP)); end; function TSymbolTable.MakeSymbol(IsSpecial: Boolean; Token: Integer): TSymbol; begin Result.IsSpecial := IsSpecial; Result.Token := Token; end; function TSymbolTable.QueryKeyword(Keyword: string): Integer; var HashValue: System.Object; begin Result := T_NULL; HashValue := fSymbols.Item[Keyword]; if HashValue <> nil then Result := TSymbol(HashValue).Token; end; end. --- NEW FILE: fdcil.cfg --- -$A- -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I+ -$J- -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -vn -AWinTypes=Borland.Vcl.Windows;WinProcs=Borland.Vcl.Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M4096,1048576 -K$00400000 -DIDE_DEBUG -LU"" --- NEW FILE: fdcil.ExceptionHandling.pas --- {----------------------------------------------------------------------------- The contents of this file are subject to the GNU General Public License Version 1.1 or later (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.gnu.org/copyleft/gpl.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Michael Elsdörfer. All Rights Reserved. $Id: fdcil.ExceptionHandling.pas,v 1.1 2004/08/09 11:16:54 miracle2k Exp $ You may retrieve the latest version of this file at the fdcil homepage, located at http://fdcil.sourceforge.net Known Issues: -----------------------------------------------------------------------------} unit fdcil.ExceptionHandling; interface type EParserError = class(System.Exception); implementation end. |
|
From: Michael E. <mir...@us...> - 2004-08-09 11:15:40
|
Update of /cvsroot/fdcil/dev/miracle2k/fdcil-test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9183/fdcil-test Log Message: Directory /cvsroot/fdcil/dev/miracle2k/fdcil-test added to the repository |
|
From: Michael E. <mir...@us...> - 2004-08-04 10:04:16
|
Update of /cvsroot/fdcil/dev/miracle2k/exercises In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22765/miracle2k/exercises Removed Files: Cradle.pas Log Message: every submodule has now its own cradle --- Cradle.pas DELETED --- |
|
From: Michael E. <mir...@us...> - 2004-08-04 09:54:22
|
Update of /cvsroot/fdcil/dev/miracle2k/exercises/expression_parser In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21509/miracle2k/exercises/expression_parser Modified Files: test1.bdsproj test1.dpr Added Files: Cradle.pas Log Message: support for mutliple digits; whitespace is now ignored --- NEW FILE: Cradle.pas --- unit Cradle; interface uses SysUtils; var Input: string; Curr: Integer; Look: char; procedure GetChar; procedure Error (s: string); procedure Abort(s: string); procedure Expected(s: string); procedure Match(x: char); function IsAlpha(c: char): boolean; function IsDigit(c: char): boolean; function IsAlNum(c: char): boolean; function IsAddOp(c: char): boolean; function IsWhite ( c : char ): boolean ; procedure SkipWhite; function GetName: string; function GetNum: string; procedure Emit(s: string); procedure EmitLn(s: string); procedure Init; implementation procedure GetChar; begin Inc(Curr); if Curr <= Length(Input) then Look := Input[Curr] else Look := #0; end; procedure Error(s: string); begin WriteLn; WriteLn(^G, 'Error: ', s, '.'); end; procedure Abort(s: string); begin Error(s); raise Exception.Create; end; procedure Expected(s: string); begin if s = #0 then Abort('Invalid characters at end of input') else Abort ( s + ' was expected.'); end; procedure Match(x: char); begin if Look = x then begin GetChar; SkipWhite; end else Expected(x); end ; function IsAlpha(c: char): boolean; begin IsAlpha := UpperCase(c)[1] in [ 'A'..'Z' ] ; end; function IsDigit(c: char): boolean; begin IsDigit := c in [ '0'..'9' ] ; end; function IsAlNum(c: char): boolean; begin IsAlNum := IsAlpha(c) or IsDigit(c) ; end ; function IsAddOp(c: char): boolean; begin Result := c in ['+', '-']; end; function IsWhite ( c : char ): boolean ; begin Result := c in [ ' ' , #9 ] ; end; procedure SkipWhite; begin while IsWhite(Look) do GetChar; end; function GetName: string; var Token: string; begin Token := ''; if not IsAlpha (Look) then Expected('Name'); while IsAlpha(Look) do begin Token := Token + UpperCase(Look); GetChar; end; Result := Token; SkipWhite; end; function GetNum: string; var Value: string; begin Value := ''; if not IsDigit ( Look ) then Expected ('Integer'); while IsDigit(Look) do begin Value := Value + Look; GetChar; end; Result := Value; SkipWhite; end; procedure Emit(s: string); begin Write(#9 + s); end; procedure EmitLn(s: string); begin Emit(s); Writeln; end; procedure Init; begin Readln(Input); Curr := 0; GetChar; SkipWhite; end; end. Index: test1.dpr =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/exercises/expression_parser/test1.dpr,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** test1.dpr 3 Aug 2004 15:09:30 -0000 1.1 --- test1.dpr 4 Aug 2004 09:54:13 -0000 1.2 *************** *** 5,12 **** uses SysUtils, ! Cradle in '..\Cradle.pas'; procedure Expression; forward; procedure Factor; begin --- 5,25 ---- uses SysUtils, ! Cradle in 'Cradle.pas'; procedure Expression; forward; + procedure Ident; + var + Name: string; + begin + Name := GetName; + if Look = '(' then begin + Match('('); Match(')'); + Emitln('BSR ' + Name); + end + else + EmitLn ('MOVE ' + Name + '(PC), D0') + end; + procedure Factor; begin *************** *** 17,20 **** --- 30,35 ---- Match(')'); end + else if IsAlpha ( Look ) then + Ident else Emitln('MOVE #' + GetNum + ', D0'); *************** *** 83,91 **** end; begin while true do try Init; ! Expression; Match(#0); except --- 98,118 ---- end; + procedure Assignment; + var + Name: string; + begin + Name := GetName; + Match('='); + Expression; + Emitln('LEA ' + Name + '(PC), A0'); + Emitln('MOVE D0, (A0)'); + end; + begin while true do try Init; ! (*Expression;*) ! Assignment; Match(#0); except Index: test1.bdsproj =================================================================== RCS file: /cvsroot/fdcil/dev/miracle2k/exercises/expression_parser/test1.bdsproj,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** test1.bdsproj 3 Aug 2004 15:09:30 -0000 1.1 --- test1.bdsproj 4 Aug 2004 09:54:13 -0000 1.2 *************** *** 163,775 **** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <FileList> <File FileName="" ContainerId="" ModuleName="SysUtils"/> ! <File FileName="..\Cradle.pas" ContainerId="" ModuleName="Cradle"/> </FileList> </DelphiDotNet.Personality> --- 163,169 ---- <FileList> <File FileName="" ContainerId="" ModuleName="SysUtils"/> ! <File FileName="Cradle.pas" ContainerId="" ModuleName="Cradle"/> </FileList> </DelphiDotNet.Personality> |
|
From: Michael E. <mir...@us...> - 2004-08-04 09:53:24
|
Update of /cvsroot/fdcil/dev/miracle2k/exercises/interpreter In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21362/miracle2k/exercises/interpreter Added Files: .cvsignore Cradle.pas SymbolTable.pas test2.bdsproj test2.cfg test2.dpr Log Message: interpreter test program --- NEW FILE: .cvsignore --- *.exe *.dcuil *.rsp *.pdb Model --- NEW FILE: Cradle.pas --- unit Cradle; interface uses SysUtils; var Input: string; Curr: Integer; Look: char; procedure GetChar; procedure Error (s: string); procedure Abort(s: string); procedure Expected(s: string); procedure Match(x: char); function IsAlpha(c: char): boolean; function IsDigit(c: char): boolean; function IsAlNum(c: char): boolean; function IsAddOp(c: char): boolean; function IsWhite ( c : char ): boolean ; procedure SkipWhite; function GetName: string; function GetNum: Integer; procedure Emit(s: string); procedure EmitLn(s: string); procedure ReadCommand; implementation procedure GetChar; begin Inc(Curr); if Curr <= Length(Input) then Look := Input[Curr] else Look := #0; end; procedure Error(s: string); begin WriteLn(^G, 'Error: ', s); end; procedure Abort(s: string); begin Error(s); raise Exception.Create; end; procedure Expected(s: string); begin if s = #0 then Abort('Invalid characters at end of input') else Abort ( s + ' was expected.'); end; procedure Match(x: char); begin if Look = x then begin GetChar; SkipWhite; end else Expected(x); end ; function IsAlpha(c: char): boolean; begin IsAlpha := UpperCase(c)[1] in [ 'A'..'Z' ] ; end; function IsDigit(c: char): boolean; begin IsDigit := c in [ '0'..'9' ] ; end; function IsAlNum(c: char): boolean; begin IsAlNum := IsAlpha(c) or IsDigit(c) ; end ; function IsAddOp(c: char): boolean; begin Result := c in ['+', '-']; end; function IsWhite ( c : char ): boolean ; begin Result := c in [ ' ' , #9 ] ; end; procedure SkipWhite; begin while IsWhite(Look) do GetChar; end; function GetName: string; var Token: string; begin Token := ''; if not IsAlpha (Look) then Expected('Name'); while IsAlpha(Look) do begin Token := Token + UpperCase(Look); GetChar; end; Result := Token; SkipWhite; end; function GetNum: Integer; begin if not IsDigit ( Look ) then Expected ('Integer'); while IsDigit ( Look ) do begin Result := 10 * Result + Ord( Look ) - Ord( '0' ); GetChar; SkipWhite; end; end; procedure Emit(s: string); begin Write(#9 + s); end; procedure EmitLn(s: string); begin Emit(s); Writeln; end; procedure ReadCommand; begin Readln(Input); Curr := 0; GetChar; SkipWhite; end; end. --- NEW FILE: test2.cfg --- -$A- -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I+ -$J- -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -vn -AWinTypes=Borland.Vcl.Windows;WinProcs=Borland.Vcl.Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -NSBorland.Vcl -H+ -W+ -M -$M4096,1048576 -K$00400000 -LU"" --- NEW FILE: SymbolTable.pas --- unit SymbolTable; interface uses SysUtils, Classes; type TTableRow = record SymbolName: string; SymbolValue: Integer; end; var Table: TList = nil; procedure InitTable; procedure FreeTable; function SymbolByName(Name: string): TTableRow; procedure AddSymbol(Name: string; Value: Integer); procedure SetSymbol(Symbol: string; Value: Integer); implementation procedure InitTable; begin Table := TList.Create; end; procedure FreeTable; begin if Table <> nil then Table.Free; end; function SymbolByName(Name: string): TTableRow; var i: integer; Found: boolean; begin Found := False; for i := 0 to Table.Count - 1 do if TTableRow(Table[i]).SymbolName = Name then begin Found := True; Result := TTableRow(Table[i]); break; end; if not Found then raise Exception.Create('Symbol ' + Name + ' does not exist!'); end; procedure AddSymbol(Name: string; Value: Integer); var Row: TTableRow; begin Row.SymbolName := Name; Row.SymbolValue := Value; Table.Add(Row) end; procedure SetSymbol(Symbol: string; Value: Integer); var Row: TTableRow; begin try Row := SymbolByName(Symbol); Row.SymbolValue := Value; except AddSymbol(Symbol, Value); end; end; initialization finalization FreeTable; end. --- NEW FILE: test2.dpr --- program test2; {$APPTYPE CONSOLE} uses SysUtils, Cradle in 'Cradle.pas', SymbolTable in 'SymbolTable.pas'; function Expression: Integer; forward; procedure Ident; var Name: string; begin Name := GetName; if Look = '(' then begin Match('('); Match(')'); Emitln('BSR ' + Name); end else EmitLn ('MOVE ' + GetName + '(PC), D0') end; function Factor: Integer; begin if Look = '(' then begin Match('('); Result := Expression; Match(')'); end else if IsAlpha(Look) then Result := SymbolByName(GetName).SymbolValue else Result := GetNum; end; procedure Division; begin Match('/'); Factor; EmitLn('MOVE (SP) + , D1') ; EmitLn('DIVS D1, D0') ; end; procedure Multiply; begin Match('*'); Factor; Emitln('MULS (SP)+, D0'); end; function Term: Integer; begin Result := Factor; while Look in ['*', '/'] do case Look of '*': begin Match('*'); Result := Result * Factor; end; '/': begin Match('/'); Result := Result div Factor; end; end; end; procedure Add; begin Match('+'); Term; Emitln('ADD (SP)+, D0'); end; procedure Substract; begin Match('-'); Term; Emitln('SUB (SP)+, D0'); Emitln('NEG D0'); end; function Expression: Integer; begin if IsAddOp(Look) then Result := 0 else Result := Term; while IsAddOp(Look) do case Look of '+': begin Match('+'); Result := Result + Term; end; '-': begin Match('-'); Result := Result - Term; end; end; end; procedure Assignment; var Name: string; begin Name := GetName; Match('='); SetSymbol(Name, Expression); end; procedure Query; var Name: string; begin Match('?'); Name := GetName; try Writeln(SymbolByName(Name).SymbolValue.ToString()); except on E: Exception do Error(E.Message); end; end; begin Writeln('Usage: {var}={expression} | ?{var}'); InitTable; repeat try ReadCommand; case Look of '?': Query; '.': Exit; '0'..'9': Writeln(Expression.ToString()) else Assignment; end; Match(#0); except end; until False; Readln; end. --- NEW FILE: test2.bdsproj --- (This appears to be a binary file; contents omitted.) |
|
From: Michael E. <mir...@us...> - 2004-08-04 09:52:14
|
Update of /cvsroot/fdcil/dev/miracle2k/exercises/interpreter In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21206/interpreter Log Message: Directory /cvsroot/fdcil/dev/miracle2k/exercises/interpreter added to the repository |
|
From: Michael E. <mir...@us...> - 2004-08-03 15:09:38
|
Update of /cvsroot/fdcil/dev/miracle2k/exercises/expression_parser In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4526/miracle2k/exercises/expression_parser Added Files: .cvsignore test1.bdsproj test1.cfg test1.dpr Log Message: first tests --- NEW FILE: .cvsignore --- *.exe *.dcuil *.rsp *.pdb Model --- NEW FILE: test1.cfg --- -$A- -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I+ -$J- -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -vn -AWinTypes=Borland.Vcl.Windows;WinProcs=Borland.Vcl.Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M4096,1048576 -K$00400000 -LU"" --- NEW FILE: test1.dpr --- program test1; {$APPTYPE CONSOLE} uses SysUtils, Cradle in '..\Cradle.pas'; procedure Expression; forward; procedure Factor; begin if Look = '(' then begin Match('('); Expression; Match(')'); end else Emitln('MOVE #' + GetNum + ', D0'); end; procedure Division; begin Match('/'); Factor; EmitLn('MOVE (SP) + , D1') ; EmitLn('DIVS D1, D0') ; end; procedure Multiply; begin Match('*'); Factor; Emitln('MULS (SP)+, D0'); end; procedure Term; begin Factor; while Look in ['*', '/'] do begin EmitLn ('MOVE D0, -(SP)' ); case Look of '*': Multiply; '/': Division; else Expected('Mulop'); end; end; end; procedure Add; begin Match('+'); Term; Emitln('ADD (SP)+, D0'); end; procedure Substract; begin Match('-'); Term; Emitln('SUB (SP)+, D0'); Emitln('NEG D0'); end; procedure Expression; begin if IsAddOp(Look) then Emitln('CLR D0') else Term; while Look in ['+', '-'] do begin EmitLn ('MOVE D0, -(SP)' ); case Look of '+': Add; '-': Substract; else Expected('Addop'); end; end; end; begin while true do try Init; Expression; Match(#0); except end; Readln; end. --- NEW FILE: test1.bdsproj --- (This appears to be a binary file; contents omitted.) |
|
From: Michael E. <mir...@us...> - 2004-08-03 15:09:28
|
Update of /cvsroot/fdcil/dev/miracle2k/exercises In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4526/miracle2k/exercises Added Files: .cvsignore Cradle.pas Log Message: first tests --- NEW FILE: .cvsignore --- *.exe *.dcuil *.rsp *.pdb Model --- NEW FILE: Cradle.pas --- unit Cradle; interface uses SysUtils; var Input: string; Curr: Integer; Look: char; procedure GetChar; procedure Error (s: string); procedure Abort(s: string); procedure Expected(s: string); procedure Match(x: char); function IsAlpha(c: char): boolean; function IsDigit(c: char): boolean; function IsAddOp(c: char): boolean; function GetName: char; function GetNum: char; procedure Emit(s: string); procedure EmitLn(s: string); procedure Init; implementation procedure GetChar; begin Inc(Curr); if Curr <= Length(Input) then Look := Input[Curr] else Look := #0; end; procedure Error(s: string); begin WriteLn; WriteLn(^G, 'Error: ', s, '.'); end; procedure Abort(s: string); begin Error(s); raise Exception.Create; end; procedure Expected(s: string); begin if s = #0 then Abort('Invalid characters at end of input') else Abort ( s + ' was expected.'); end; procedure Match(x: char); begin if Look = x then GetChar else Expected(x); end ; function IsAlpha(c: char): boolean; begin IsAlpha := UpperCase(c)[1] in [ 'A'..'Z' ] ; end; function IsDigit(c: char): boolean; begin IsDigit := c in [ '0'..'9' ] ; end; function IsAddOp(c: char): boolean; begin Result := c in ['+', '-']; end; function GetName: char; begin if not IsAlpha ( Look ) then Expected ( 'Name' ); GetName := UpCase( Look ); GetChar; end; function GetNum: char; begin if not IsDigit ( Look ) then Expected ('Integer'); GetNum := Look; GetChar; end; procedure Emit(s: string); begin Write(#9 + s); end; procedure EmitLn(s: string); begin Emit(s); Writeln; end; procedure Init; begin Readln(Input); Curr := 0; GetChar; end; end. |
|
From: Michael E. <mir...@us...> - 2004-08-03 15:07:39
|
Update of /cvsroot/fdcil/dev/miracle2k/exercises/expression_parser In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4226/expression_parser Log Message: Directory /cvsroot/fdcil/dev/miracle2k/exercises/expression_parser added to the repository |
|
From: Michael E. <mir...@us...> - 2004-08-03 15:07:27
|
Update of /cvsroot/fdcil/dev/miracle2k/exercises In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4203/exercises Log Message: Directory /cvsroot/fdcil/dev/miracle2k/exercises added to the repository |
|
From: Andreas H. <ah...@us...> - 2004-08-03 09:32:56
|
Update of /cvsroot/fdcil/homepage In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15950 Modified Files: index.html Log Message: Update Index: index.html =================================================================== RCS file: /cvsroot/fdcil/homepage/index.html,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** index.html 29 Jul 2004 15:51:56 -0000 1.1 --- index.html 3 Aug 2004 09:32:48 -0000 1.2 *************** *** 1,5 **** <html> <head> ! <title>Free Delphi Compiler for IL</title> <style> <!-- --- 1,5 ---- <html> <head> ! <title>Free Pascal Compiler for IL</title> <style> <!-- *************** *** 27,39 **** </head> <body bgcolor=white> ! <h1>Free Delphi Compiler for IL</h1> ! <p>The aim of this project is to write a free Delphi compiler for the .NET environment. ! The aim is to support all language features Borland(R)'s compiler has. It is not the ! aim to write the best optimizing compiler.</p> <p> </p> <p><a href="http://www.sourceforge.net/projects/fdcil">The project at sourceforge.</a></p> <p> </p> - <p> </p> <!-- Sourceforge Logo --> <div align="right"> --- 27,39 ---- </head> <body bgcolor=white> ! <h1>Free Pascal Compiler for IL</h1> ! <p>The aim of this project is to write a free pascal compiler for the .NET environment. ! It is written in Delphi.NET and should compile itself in a later stage. The generated ! executables will work on MS.NET, Mono and Portable.NET.</p> ! <p>Status: <b>Planning</b> <p> </p> <p><a href="http://www.sourceforge.net/projects/fdcil">The project at sourceforge.</a></p> <p> </p> <!-- Sourceforge Logo --> <div align="right"> |
|
From: Andreas H. <ah...@us...> - 2004-08-01 08:01:45
|
Update of /cvsroot/fdcil/dev/ahuser/Lexer In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8308/ahuser/Lexer Added Files: Project1.res Log Message: Update --- NEW FILE: Project1.res --- (This appears to be a binary file; contents omitted.) |
|
From: Andreas H. <ah...@us...> - 2004-07-29 15:57:55
|
Update of /cvsroot/fdcil/dev/miracle2k In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32684/miracle2k Added Files: .cvsignore Log Message: initial release --- NEW FILE: .cvsignore --- *.exe *.dcuil *.rsp *.pdb Model |
|
From: Andreas H. <ah...@us...> - 2004-07-29 15:57:50
|
Update of /cvsroot/fdcil/dev/ahuser/Lexer In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32660/ahuser/Lexer Added Files: .cvsignore Compiler.IO.pas Compiler.Lexer.pas Compiler.Tokenizer.pas Project1.bdsproj Project1.cfg Project1.dpr tokens1.pas tokens2.pas tokens3.pas tokens4.pas tokens5.pas tokens6.pas Log Message: Lexer test --- NEW FILE: Project1.cfg --- -$A- -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I+ -$J- -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cc -vn -AWinTypes=Borland.Vcl.Windows;WinProcs=Borland.Vcl.Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M4096,1048576 -K$00400000 -U"c:\windows\microsoft.net\framework\v1.1.4322" -O"c:\windows\microsoft.net\framework\v1.1.4322" -I"c:\windows\microsoft.net\framework\v1.1.4322" -R"c:\windows\microsoft.net\framework\v1.1.4322" -LU"c:\windows\microsoft.net\framework\v1.1.4322\System.dll" --- NEW FILE: tokens6.pas --- Numbers of all kinds: begin invalid := .10; n := 1.0; invalid := 2e; n := 3e1; n := 3e-2 n := +10.2; invalid := -.1; invalid := e+1; n := 0e+100000000000000000000000001; invalid := 0x10; n := 1; n := -100; n := +34; n := $A; n := $0B n := $0ABCDEF1; end. --- NEW FILE: tokens1.pas --- Comment: {...} {}program {}Comments;{} {x}uses{x} {Text}SysUtils{Text};{Text} begin {Comment}{After Comment} end.{FileEnd} --- NEW FILE: tokens3.pas --- Comment: //... //program Comments; uses// SysUtils//; begin // // end.//FileEnd --- NEW FILE: tokens2.pas --- Comment: (*...*) (**)program (**)Comments;(**) (*x*)uses(*x*) (*Text*)SysUtils(*Text*);(*Text*) begin (*Comment*)(*After Comment*) end.(*FileEnd*) --- NEW FILE: Compiler.IO.pas --- unit Compiler.IO; interface {$REGION 'Interface uses'} uses System.Text, System.IO; {$ENDREGION} type {$REGION 'class TSourceFile'} TSourceFile = class(System.Object) private FFileName: string; FEncoding: Encoding; function GetName: string; function GetPath: string; protected FStream: Stream; public constructor Create(const AFileName: string; AStream: Stream; AEncoding: Encoding = nil); overload; function ReadFileContent: string; property FileName: string read FFileName; property Path: string read GetPath; property Name: string read GetName; end; {$ENDREGION} {$REGION 'class TDiskSourceFile'} TDiskSourceFile = class(TSourceFile) public constructor Create(const AFileName: string; AEncoding: Encoding = nil); overload; destructor Destroy; override; end; {$ENDREGION} implementation {$REGION 'class TSourceFile'} { TSourceFile } constructor TSourceFile.Create(const AFileName: string; AStream: Stream; AEncoding: Encoding); begin inherited Create; FFileName := AFileName; FStream := AStream; FEncoding := AEncoding; end; function TSourceFile.GetName: string; begin Result := System.IO.Path.GetFileName(FFileName); end; function TSourceFile.GetPath: string; begin Result := System.IO.Path.GetDirectoryName(FFileName); end; function TSourceFile.ReadFileContent: string; var Bytes: array of Byte; enc: Encoding; Offset: Integer; function IsPreamble(const Bytes, Preamble: array of Byte): Boolean; var Len, i: Integer; begin Result := False; Len := Length(Preamble); if Length(Bytes) >= Len then begin for i := 0 to Len - 1 do if (Bytes[i] <> Preamble[i]) then Exit; Result := True; end; end; begin SetLength(Bytes, FStream.Length - FStream.Position); FStream.Read(Bytes, 0, FStream.Length); if Length(Bytes) > 0 then begin if FEncoding = nil then begin if IsPreamble(Bytes, Encoding.Unicode.GetPreamble) then enc := Encoding.Unicode else if IsPreamble(Bytes, Encoding.BigEndianUnicode.GetPreamble) then enc := Encoding.BigEndianUnicode else if IsPreamble(Bytes, Encoding.UTF8.GetPreamble) then enc := Encoding.UTF8 else if IsPreamble(Bytes, Encoding.UTF7.GetPreamble) then enc := Encoding.UTF7 else enc := Encoding.Default; Offset := Length(enc.GetPreamble); end else begin enc := FEncoding; if IsPreamble(Bytes, enc.GetPreamble) then Offset := Length(enc.GetPreamble) else Offset := 0; end; Result := enc.GetString(Bytes, Offset, Length(Bytes) - Offset); end else Result := ''; end; {$ENDREGION} {$REGION 'class TDiskSourceFile'} { TDiskSourceFile } constructor TDiskSourceFile.Create(const AFileName: string; AEncoding: Encoding); begin inherited Create(AFileName, FileStream.Create(AFileName, FileMode.Open), AEncoding); end; destructor TDiskSourceFile.Destroy; begin FStream.Free; inherited Destroy; end; {$ENDREGION} end. --- NEW FILE: Project1.dpr --- program Project1; {%DelphiDotNetAssemblyCompiler '$(SystemRoot)\microsoft.net\framework\v1.1.4322\System.dll'} uses System.Reflection, System.Runtime.CompilerServices, SysUtils, Classes, Compiler.Tokenizer in 'Compiler.Tokenizer.pas', Compiler.Lexer in 'Compiler.Lexer.pas', Compiler.IO in 'Compiler.IO.pas'; {$R *.res} {$REGION 'Programm/Assemblierungs-Informationen'} // // Die allgemeinen Assemblierungsinformationen werden durch die folgenden // Attribute gesteuert. Ändern Sie die Attributwerte, um die zu einer // Assemblierung gehörenden Informationen zu modifizieren. // [assembly: AssemblyDescription('')] [assembly: AssemblyConfiguration('')] [assembly: AssemblyCompany('')] [assembly: AssemblyProduct('')] [assembly: AssemblyCopyright('')] [assembly: AssemblyTrademark('')] [assembly: AssemblyCulture('')] // Der Delphi-Compiler steuert AssemblyTitleAttribute via ExeDescription. // Sie können dies in der IDE über Projekt/Optionen festlegen. // Wenn Sie das Attribut AssemblyTitle wie unten gezeigt manuell festlegen, // wird die IDE-Einstellung überschrieben. // [assembly: AssemblyTitle('')] // // Die Versionsinformation einer Assemblierung enthält die folgenden vier Werte: // // Hauptversion // Nebenversion // Build-Nummer // Revision // // Sie können alle vier Werte festlegen oder für Revision und Build-Nummer die // Standardwerte mit '*' - wie nachfolgend gezeigt - verwenden: [assembly: AssemblyVersion('1.0.*')] // // Zum Signieren einer Assemblierung müssen Sie einen Schlüssel angeben. Weitere Informationen // über das Signieren von Assemblierungen finden Sie in der Microsoft .NET Framework-Dokumentation. // // Mit den folgenden Attributen steuern Sie, welcher Schlüssel für die Signatur verwendet wird. // // Hinweise: // (*) Wenn kein Schlüssel angegeben wird, ist die Assemblierung nicht signiert. // (*) KeyName verweist auf einen Schlüssel, der im Crypto Service Provider // (CSP) auf Ihrem Rechner installiert wurde. KeyFile verweist auf eine // Datei, die einen Schlüssel enthält. // (*) Wenn sowohl der KeyFile- als auch der KeyName-Wert angegeben ist, wird // die folgende Verarbeitung durchgeführt: // (1) Wenn KeyName in dem CSP gefunden wird, wird dieser Schlüssel verwendet. // (2) Wenn KeyName nicht, aber KeyFile vorhanden ist, wird der Schlüssel // in KeyFile im CSP installiert und verwendet. // (*) Ein KeyFile können Sie mit dem Utility sn.exe (Starker Name) erzeugen. // Der Speicherort von KeyFile sollte relativ zum Projektausgabeverzeichnis // angegeben werden. Wenn sich Ihr KeyFile im Projektverzeichnis befindet, // würden Sie das Attribut AssemblyKeyFile folgendermaßen festlegen: // [assembly: AssemblyKeyFile('mykey.snk')], vorausgesetzt, Ihr // Ausgabeverzeichnis ist das Projektverzeichnis (Vorgabe). // (*) Verzögerte Signatur ist eine erweiterte Option; nähere Informationen // dazu finden Sie in der Microsoft .NET Framework-Dokumentation. // [assembly: AssemblyDelaySign(false)] [assembly: AssemblyKeyFile('')] [assembly: AssemblyKeyName('')] {$ENDREGION} var Tokenizer: TPascalTokenizer; t: TTokenInfo; SrcFile: TSourceFile; Lexer: TLexer; sl: TStringList; I: Integer; ExeDir, FileName: string; begin ExeDir := ExtractFileDir(ParamStr(0)); sl := TStringList.Create; try if ParamStr(1) = '/hard' then begin sl.LoadFromFile('C:\Borland\Delphi7\Source\Rtl\Win\Windows.pas'); Tokenizer := TPascalTokenizer.Create(''); try sl.Clear; while Tokenizer.GetToken(t) do WriteLn(t.ToString); finally Tokenizer.Free; end; end else begin I := 1; repeat FileName := ExeDir + '\tokens' + IntToStr(i) + '.pas'; if not FileExists(FileName) then Break; sl.LoadFromFile(FileName); WriteLn('TEST-CASE: ', sl[0]); WriteLn('==============================================================================='); sl.Delete(0); try Tokenizer := TPascalTokenizer.Create(sl.Text); try while Tokenizer.GetToken(t) do WriteLn(t.ToString); WriteLn('---------------------------------------'); finally Tokenizer.Free; end; except on E: Exception do begin WriteLn('Exception: ', E.Message); end; end; Inc(I); WriteLn; until False; WriteLn('Testing Lexer:'); SrcFile := TDiskSourceFile.Create('C:\Borland\Delphi5\Source\Rtl\Win\Windows.pas'); try Lexer := TLexer.Create(SrcFile); Lexer.GetAllTokens(); for i := 0 to Lexer.Count - 1 do begin WriteLn(Lexer[i].ToString); end; finally SrcFile.Free; end; WriteLn('Tests finished.'); end; finally sl.Free; end; ReadLn; end. --- NEW FILE: tokens5.pas --- Identifiers: begin _MyIdent Your1Ident; M1Ident Ident1; for i := 0to 10do end. --- NEW FILE: Project1.bdsproj --- (This appears to be a binary file; contents omitted.) --- NEW FILE: tokens4.pas --- Strings: ' ' begin 'OpenEnd 'LineStart'; s :='Combined symbols'; WriteLn('Test''s '' in the string'''+s+''' end.'); WriteLn('c'); WriteLn(''); WriteLn(#13#10); WriteLn(#$0D); WriteLn(#$0DAA); WriteLn(#$0D#$0A); end.'FileEnd' --- NEW FILE: Compiler.Tokenizer.pas --- unit Compiler.Tokenizer; interface {$REGION 'Interface uses'} uses System.Collections; {$ENDREGION} {$REGION 'class TTokenInfo, class TPascalTokenizer'} const WhiteSpaces = [#1..#32]; OneSymbolChars = ['(', ')', '[', ']', '{', '}', ';', '@', '^', '/', '''']; NumberChars = ['0'..'9']; HexNumberChars = NumberChars + ['A'..'F', 'a'..'f']; IdentFirstChars = ['a'..'z', 'A'..'Z', '_']; IdentChars = IdentFirstChars + NumberChars; SymbolChars = [#1..#255] - (WhiteSpaces + IdentChars + OneSymbolChars); type TTokenKind = (tkNone, tkIdent, tkSymbol, tkComment, tkOption, tkString, tkNumber); TTokenExKind = (tekNone, tekHex, tekInt, tekFloat); TTokenInfo = class(System.Object) private FKind: TTokenKind; FExKind: TTokenExKind; FStartLine: Integer; FEndLine: Integer; FStartIndex: Integer; FEndIndex: Integer; FColumnIndex: Integer; FToken: string; public property Kind: TTokenKind read FKind; property ExKind: TTokenExKind read FExKind; property StartLine: Integer read FStartLine; property EndLine: Integer read FEndLine; property StartIndex: Integer read FStartIndex; property EndIndex: Integer read FEndIndex; property ColumnIndex: Integer read FColumnIndex; property Token: string read FToken; function ToString: string; {$IFDEF CLR}override;{$ENDIF CLR} end; TPascalTokenizer = class(System.Object) private FCode: string; FIndex: Integer; FCodeLen: Integer; FLineNum: Integer; FLineStartIndex: Integer; procedure HandleLineFeed(var Idx: Integer); public constructor Create(const ACode: string; StartLineNum: Integer = 1); function GetToken: TTokenInfo; overload; function GetToken(out p: TTokenInfo): Boolean; overload; function GetPlainText(StartIndex, EndIndex: Integer): string; overload; function GetPlainText(StartToken, EndToken: TTokenInfo): string; overload; property Index: Integer read FIndex; property Code: string read FCode; property LineNum: Integer read FLineNum; end; {$ENDREGION} implementation {$REGION 'class TPascalTokenizer'} { TPascalTokenizer } function TPascalTokenizer.GetToken: TTokenInfo; // Delphi specific hint: System.String[index] is 1-based in Delphi means "idx<CodeLen" => "idx<=CodeLen" var Idx: Integer; IsDecimal: Boolean; IsExp: Boolean; IsExpSign: Boolean; Data: string; CodeLen: Integer; Ch, Ch2: Char; begin Result := nil; // local variables are faster than instance fields Idx := Index; CodeLen := FCodeLen; Data := FCode; // go to next token and skip white chars while Idx <= CodeLen do begin Ch := Data[Idx]; if not System.Char.IsWhiteSpace(Ch) { (AnsiChar(Ch) in WhiteSpaces)} then Break; if (Ch = #10) or (Ch = #13) then HandleLineFeed(Idx); Inc(Idx); end; if Idx > CodeLen then Exit; Result := TTokenInfo.Create; Result.FStartLine := FLineNum; Result.FStartIndex := Idx; Result.FColumnIndex := Idx - FLineStartIndex; Result.FExKind := tekNone; FIndex := Idx; // start index for this token // preload two chars Ch := Data[Idx]; if Idx + 1 <= CodeLen then Ch2 := Data[Idx + 1] else Ch2 := #0; // ------------ string '...' ------------- if Ch = '''' then begin Inc(Idx); // string while Idx <= CodeLen do begin case Data[Idx] of '''': begin if (Idx <= CodeLen) and (Data[Idx + 1] = '''') then Inc(Idx) else Break; end; #10, #13: begin Dec(Idx); Break; // line end is string end in pascal end; end; Inc(Idx); end; if Idx <= CodeLen then Inc(Idx); // include ending "'" Result.FKind := tkString; end // ------------ comment { ... } ------------- else if (Ch = '{') then begin // comment { ... } -> find comment end Inc(Idx); if Data[Idx] = '$' then begin Result.FKind := tkOption; Inc(Idx); end else Result.FKind := tkComment; while Idx <= CodeLen do begin Ch := Data[Idx]; if Ch = '}' then Break; if (Ch = #10) or (Ch = #13) then HandleLineFeed(Idx); Inc(Idx); end; if Idx <= CodeLen then Inc(Idx); // include ending "}" end // ------------ comment (* ... *) ------------- else if (Ch = '(') and (Ch2 = '*') then begin // comment (* ... *) -> find comment end Inc(Idx, 2); if Data[Idx] = '$' then begin Result.FKind := tkOption; Inc(Idx); end else Result.FKind := tkComment; while Idx < CodeLen do // not "<=" begin Ch := Data[Idx]; if (Ch = '*') and (Data[Idx + 1] = ')') then Break; if (Ch = #10) or (Ch = #13) then HandleLineFeed(Idx); Inc(Idx); end; if Idx <= CodeLen then Inc(Idx, 2); // include ending "*)" end // ------------ comment // ... ------------- else if (Ch = '/') and (Ch2 = '/') then begin // comment "// ..." -> find comment end Inc(Idx, 2); while Idx <= CodeLen do begin Ch := Data[Idx]; if (Ch = #10) or (Ch = #13) then Break; Inc(Idx); end; Result.FKind := tkComment; end // ------------ identifier begin variablename ------------- else if System.Char.IsLetter(Ch) or (Ch = '_') {AnsiChar(Ch) in IdentFirstChars} then begin // identifier Inc(Idx); while (Idx <= CodeLen) and (System.Char.IsLetterOrDigit(Data[Idx]) or (Data[Idx] = '_')) {(AnsiChar(Data[Idx]) in IdentChars)} do Inc(Idx); Result.FKind := tkIdent; end // ------------ number +1 -1 10 1.3 -0.2e10 +0.3E10 ------------- else if System.Char.IsDigit(Ch) then begin // number Inc(Idx); IsDecimal := False; IsExp := False; IsExpSign := False; while Idx <= CodeLen do begin case Data[Idx] of '0'..'9': ; '.': if IsDecimal or IsExp then Break else IsDecimal := True; '+', '-': if not IsExp or IsExpSign then Break else IsExpSign := True; 'e', 'E': if IsDecimal or IsExp then Break else IsExp := True; else Break; end; Inc(Idx); end; Result.FKind := tkNumber; if IsExp or IsDecimal then Result.FExKind := tekFloat else Result.FExKind := tekInt; end // ------------ number hex $xx ------------- else if (Ch = '$') and ((Word(Ch2) <= $FF) and (AnsiChar(Ch2) in HexNumberChars)) then begin // hex number Inc(Idx, 2); while Idx <= CodeLen do begin Ch := Data[Idx]; if (Word(Ch) > $FF) or not (AnsiChar(Ch) in HexNumberChars) then Break; Inc(Idx); end; Result.FKind := tkNumber; Result.FExKind := tekHex; end // ------------ char #13 #$10 ------------- else if (Ch = '#') and ((Ch2 = '$') or System.Char.IsDigit(Ch2)) {(AnsiChar(Ch2) in NumberChars))} then begin // char Inc(Idx, 2); if (Idx > 1) and (Data[Idx - 1] = '$') then begin while Idx <= CodeLen do begin Ch := Data[Idx]; if (Word(Ch) > $FF) or not (AnsiChar(Ch) in HexNumberChars) then Break; Inc(Idx); end; end else begin while (Idx <= CodeLen) and System.Char.IsDigit(Data[idx]) {(AnsiChar(Data[Idx]) in NumberChars)} do Inc(Idx); end; Result.FKind := tkString; end // ------------ symbol (single char) ------------- else if (Word(Ch) <= $FF) and (AnsiChar(Ch) in OneSymbolChars) then begin Inc(Idx); Result.FKind := tkSymbol; end else // ------------ symbol (multiple chars) ------------- begin while (Word(Ch) <= $FF) and (AnsiChar(Data[Idx]) in SymbolChars) do Inc(Idx); Result.FKind := tkSymbol; end; Result.FEndLine := FLineNum; Result.FEndIndex := Idx - 1; Result.FToken := Copy(Data, FIndex, Idx - FIndex); FIndex := Idx; end; { Some files have strange line breaks. } procedure TPascalTokenizer.HandleLineFeed(var Idx: Integer); begin Inc(FLineNum); if Idx + 1 < FCodeLen then begin if FCode[Idx] = #10 then begin if FCode[Idx + 1] = #13 then Inc(Idx); end else if FCode[Idx] = #13 then begin if FCode[Idx + 1] = #10 then Inc(Idx); end end; FLineStartIndex := Idx + 1; end; constructor TPascalTokenizer.Create(const ACode: string; StartLineNum: Integer); begin inherited Create; FIndex := 1; FLineNum := StartLineNum; FCode := ACode; FCodeLen := FCode.Length; end; function TPascalTokenizer.GetToken(out p: TTokenInfo): Boolean; begin p := GetToken; Result := p <> nil; end; function TPascalTokenizer.GetPlainText(StartIndex, EndIndex: Integer): string; begin Result := Copy(FCode, StartIndex, EndIndex - StartIndex + 1); end; function TPascalTokenizer.GetPlainText(StartToken, EndToken: TTokenInfo): string; begin Result := GetPlainText(StartToken.StartIndex, EndToken.EndIndex); end; {$ENDREGION} {$REGION 'class TTokenInfo'} { TTokenInfo } function TTokenInfo.ToString: string; begin Result := ''; case Kind of tkIdent: Result := 'Identifier'; tkSymbol: Result := 'Symbol'; tkComment: Result := 'Comment'; tkOption: Result := 'Compiler directive'; tkString: Result := 'String'; tkNumber: case ExKind of tekHex: Result := 'Number (Hex)'; tekInt: Result := 'Number (Int)'; tekFloat: Result := 'Number (Float)'; end; end; Result := System.String.Format('{0} [{1},{2}]: {3}', [Result, StartLine, ColumnIndex, Token]); end; {$ENDREGION} end. --- NEW FILE: .cvsignore --- *.exe *.dcuil *.rsp *.pdb Model --- NEW FILE: Compiler.Lexer.pas --- unit Compiler.Lexer; interface {$REGION 'Interface uses'} uses System.Collections, Compiler.IO, Compiler.Tokenizer; {$ENDREGION} type {$REGION 'class TLexer'} TLexer = class(System.Object) private FTokenizer: TPascalTokenizer; FSourceFile: TSourceFile; FCurrentToken: Integer; FTokens: ArrayList; public function get_Tokens(Index: Integer): TTokenInfo; function get_Count: Integer; public constructor Create(ASourceFile: TSourceFile); procedure GetAllTokens(); function GetToken: TTokenInfo; overload; function GetToken(out Token: TTokenInfo): Boolean; overload; /// property Count returns the already parsed token count. property Count: Integer read get_Count; property Tokens[Index: Integer]: TTokenInfo read get_Tokens; default; property SourceFile: TSourceFile read FSourceFile; end; {$ENDREGION} implementation {$REGION 'class TLexer'} { TLexer } constructor TLexer.Create(ASourceFile: TSourceFile); begin inherited Create; FSourceFile := ASourceFile; FTokens := ArrayList.Create; FTokenizer := TPascalTokenizer.Create(FSourceFile.ReadFileContent()); end; procedure TLexer.GetAllTokens; begin while GetToken <> nil do ; end; function TLexer.GetToken(out Token: TTokenInfo): Boolean; begin Token := GetToken; Result := Token <> nil; end; function TLexer.GetToken: TTokenInfo; begin Inc(FCurrentToken); if FCurrentToken <= FTokens.Count then begin Result := TTokenInfo(FTokens[FCurrentToken - 1]); end else begin repeat Result := FTokenizer.GetToken; if Result = nil then Break; { if Result.Kind = TTokenKind.tkOption then begin // AHUser: Should we handle this here or should the compiler code do this? end; } until Result.Kind <> TTokenKind.tkComment; if Result <> nil then FTokens.Add(Result); end; end; function TLexer.get_Count: Integer; begin Result := FTokens.Count; end; function TLexer.get_Tokens(Index: Integer): TTokenInfo; var CurrentIndex: Integer; begin Result := nil; if Index >= FTokens.Count then begin CurrentIndex := FCurrentToken; try FCurrentToken := FTokens.Count; while Index >= FTokens.Count do if GetToken = nil then Exit; finally FCurrentToken := CurrentIndex; end; end else if Index < 0 then Exit; Result := TTokenInfo(FTokens[Index]); end; {$ENDREGION} end. |
|
From: Andreas H. <ah...@us...> - 2004-07-29 15:56:46
|
Update of /cvsroot/fdcil/dev/ahuser/Lexer In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32406/Lexer Log Message: Directory /cvsroot/fdcil/dev/ahuser/Lexer added to the repository |
|
From: Andreas H. <ah...@us...> - 2004-07-29 15:52:04
|
Update of /cvsroot/fdcil/homepage In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31633 Added Files: index.html Log Message: initial release --- NEW FILE: index.html --- <html> <head> <title>Free Delphi Compiler for IL</title> <style> <!-- body, p { font-family: verdana, arial, helvetica; line-height: 14pt; font-size: 10pt; text-align: justify; } h1 { font-family: verdana, arial, helvetica; font-size: 15pt; font-weight: bold; } a { text-decoration: none; color: #4444ff; } a:hover { text-decoration: underline; color: #ff0000; } //--> </style> </head> <body bgcolor=white> <h1>Free Delphi Compiler for IL</h1> <p>The aim of this project is to write a free Delphi compiler for the .NET environment. The aim is to support all language features Borland(R)'s compiler has. It is not the aim to write the best optimizing compiler.</p> <p> </p> <p><a href="http://www.sourceforge.net/projects/fdcil">The project at sourceforge.</a></p> <p> </p> <p> </p> <!-- Sourceforge Logo --> <div align="right"> <A href="http://sourceforge.net"><IMG src="http://sourceforge.net/sflogo.php?group_id=80168&type=5" width="210" height="62" border="0" alt="SourceForge.net Logo" /></A> </div> </body> </html> |
|
From: Andreas H. <ah...@us...> - 2004-07-29 15:30:08
|
Update of /cvsroot/fdcil/fdcil/rtl In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27856/rtl Added Files: readme.txt Log Message: initial release --- NEW FILE: readme.txt --- This directory contains the RTL code. |
|
From: Andreas H. <ah...@us...> - 2004-07-29 15:30:07
|
Update of /cvsroot/fdcil/fdcil/compiler In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27856/compiler Added Files: readme.txt Log Message: initial release --- NEW FILE: readme.txt --- This directory contains the compiler code. |
|
From: Andreas H. <ah...@us...> - 2004-07-29 15:29:19
|
Update of /cvsroot/fdcil/fdcil/rtl In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27697/rtl Log Message: Directory /cvsroot/fdcil/fdcil/rtl added to the repository |
|
From: Andreas H. <ah...@us...> - 2004-07-29 15:29:18
|
Update of /cvsroot/fdcil/fdcil/compiler In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27697/compiler Log Message: Directory /cvsroot/fdcil/fdcil/compiler added to the repository |
|
From: Andreas H. <ah...@us...> - 2004-07-29 15:27:19
|
Update of /cvsroot/fdcil/dev/miracle2k In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27352/miracle2k Added Files: readme.txt Log Message: initial release --- NEW FILE: readme.txt --- This directory contains test code. |
|
From: Andreas H. <ah...@us...> - 2004-07-29 15:27:18
|
Update of /cvsroot/fdcil/dev/ahuser In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27352/ahuser Added Files: readme.txt Log Message: initial release --- NEW FILE: readme.txt --- This directory contains test code. |
|
From: Andreas H. <ah...@us...> - 2004-07-29 15:26:46
|
Update of /cvsroot/fdcil/dev/miracle2k In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27216/miracle2k Log Message: Directory /cvsroot/fdcil/dev/miracle2k added to the repository |