Delphi로 만들어본 자바분석기

Programming/Delphi 2009.09.22 02:03 Posted by 파란크리스마스

Antlr 도구를 이용해서 만들어본 자바파서입니다.
간단하게 샘플 Grammer 을 이용해서 만들어 보았습니다.
 
파싱하는 자바 소스는 컴파일 가능한 소스가 아니면
Grammer에 어긋나기 때문에 파싱이 되지 않습니다.
(사용된 Grammer가 최신 JDK에 만족하지 않을 수 있으므로 최신 JDK 문법도 파싱이 안 될수 있음)
 
Package, Import, Class, Method을 몇번째 라인, 열, 사용된 이름을 객체화해서 담아 두었습니다.
 
더 자세한 정보를 담으려 했으나,
Delphi로 자바 파싱에 관심이 있는 사람이 있는지 궁금하네요. (손들어 보세요.)
 
파싱한 결과를
객체화 하기 위해서 클래스를 설계하는 일도 만만치 않는 일이라 여기에서 중단합니다.
(누가 클래스를 설계주시면 객체에 담아 보겠습니다. JavaSourceUnit.pas)
 
Grammer 파일은 제외한 컴파일 하는 한 소스 파일은 제 블로그에서 받으실 수 있으며,
배포시 제 블로그의 주소와 함께 배포해주세요.
(Delphi 2090이상에서만 컴파일 가능)

신고

Delphi - Coco/R DCocoR 로 간단한 계산기 만들기

Programming/Delphi 2009.05.14 18:24 Posted by 파란크리스마스

출처 - http://cc.embarcadero.com/Item/26667

DCocoR 예제를 간단하게 수정하여 만들어 보았습니다.


ExprUnit.atg
----------------------------------------
COMPILER ExprUnit

FRAME "delphi.frm"

header = (.
.)

uses = (.SysUtils,Variants,StrUtils.)

private = (.
.)
protected = (.
.)
public = (.
  function Evaluate(const str: String): integer;
.)
publicProps = (.
.)

precreate = (.
.)

implementation =
(.
function TExprUnit.Evaluate(const str: String): integer;
var rez: Variant;
begin
  SetSource(str);
  _expr(rez);
  //Result := Successful and rez;
  Result := rez;
end;
.)

END

IGNORECASE

CHARACTERS
letter="ABCDEFGHIJKLMNOPQRSTUVWXYZ_".
digit="0123456789".
hexdigit = digit + "ABCDEF".
special = "+-*/=<>[].,():;^@{}$#".
ctrl=CHR(1)..CHR(31).
tab=CHR(9).
eol=CHR(13).
lf=CHR(10).
noquote=ANY-"'" -ctrl.

TOKENS
ident = letter{letter|digit}.
number = digit{digit} | digit { digit } CONTEXT ( ".." ).
string = ("'" {noquote}"'"| "#"(digit{digit}|"$"hexdigit{hexdigit}))
         {"'" {noquote}"'"| "#"(digit{digit}|"$"hexdigit{hexdigit})}.
float = digit{digit}
        (  "." {digit}
           [ "E"
            ["+" |"-"]
            digit{digit}
           ]
          |"E"["+"|"-"]digit{digit}
        ).
hexnumber = "$" hexdigit {hexdigit}.
eq    = '='.
gr    = '>'.
les   = '<'.
lesEq = '<='.
grEq  = '>='.
noeq  = '<>'.

add = "+". 
sub = "-". 
or  = "OR".
xor = "XOR".

mult = "*"  .
divd = "/"  .
div  = "DIV".
mod  = "MOD".
and  = "AND".
shl  = "SHL".
shr  = "SHR".

IGNORE tab+lf+eol

PRODUCTIONS

ExprUnit
(. var rez: Variant; .)=
 expr<rez>
.

expr<var Value: Variant>
(. var v2: Variant; sign: Integer; AddOp: Integer; .) =
  (.sign := 1;.)
  ['+' | '-' (.sign := -1;.) ]
  Term<Value> (. if sign<0 then value := -value;.)
  {
   ( "+" | "-" | "OR" | "XOR" )
   (. AddOp := Symbols[0]^.id; .)
    Term<v2>
   (. case AddOp of
      addSym: Value := Value +   v2;
      subSym: Value := Value -   v2;
      orSym : Value := Value or  v2;
      xorSym: Value := Value xor v2;
      end;
   .)
  }
.

Term<var Value: Variant>
(. var v2: Variant; MulOp: Integer; .) =
 Factor<Value>
 {
  ("*" | "/" | "DIV" | "MOD" | "AND" | "SHL" | "SHR" )
  (. MulOp := Symbols[0]^.id; .)
  Factor<v2>
   (. case MulOp of
      multSym: Value := Value *   v2;
      divdSym: Value := Value /   v2;
      divSym:  Value := Value div v2;
      modSym:  Value := Value mod v2;
      andSym:  Value := Value and v2;
      shlSym:  Value := Value shl v2;
      shrSym:  Value := Value shr v2;
      end;
   .)
 }
.

Factor<var Value: Variant> =
 | Number<Value>
.

Number<out Value: Variant> =
   number     (. Value := StrToInt(LexString); .)
 | float      (. Value := StrToFloat(LexString); .)
 | hexnumber  (. Value := StrToInt(LexString); .)
.

END ExprUnit.
----------------------------------------

ExprApp.dpr
----------------------------------------
program ExprApp;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  CocoAncestor,
  FileLoader,
  ExprUnit in 'ExprUnit.pas';

var
  comp: TExprUnit;
  meth: TMethod;
  errProc: TErrorEvent absolute meth;
  int1: String;
  rez: Variant;

procedure ErrorHandler(this: TExprUnit; Sender: TObject; ErrorType,ErrorCode, line,col: Integer; const Msg, data: string);
begin
  WriteLn(Format('Error in "%s"(%d,%d): %s',[int1,Line,Col,Msg,data]));
end;

begin
  try
    if (ParamCount=0) then begin
      WriteLn(Format('Usage: %s "1 + 2"',[ChangeFileExt(ExtractFileName(ParamStr(0)),'')]));
      Exit;
    end;
    comp := TExprUnit.Create(nil);
    try
      meth.Data := comp;
      meth.Code := @ErrorHandler;
      comp.OnError := errProc;

      int1 := ParamStr(1);
      WriteLn(int1);
      rez := comp.Evaluate(int1);
      WriteLn(rez);
    finally
      comp.Free;
    end;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.
----------------------------------------

실행결과

신고

초간단 java2delphi

Programming/Delphi 2007.08.23 15:42 Posted by 파란크리스마스

java 소스를 Delphi로 변환 프로그램을 간단하게 만들어 보았습니다.

원래 필요로 했던 것은 사칙연산이나 제어문 정도라서 일주일 투자해서 간단하게 만들어 보았습니다.

JavaCC을 이용했으며, jj 파일을 제외하고 Java 소스를 첨부합니다.

 

사용법:

java -jar java2delphi.jar Formatter.java

 

위와 같이 명령을 하시면 Formatter.pas의 결과물을 얻을 수 있습니다.

아래에 일부 변환된 예를 입니다.

  public int sum(int s1, int s2) {
    return s1 + s2;
  }
  function TFormatter.sum(s1 : integer; s2 : integer): int;
  begin
   result := s1+s2;
  end;
------------------------------------------------------------------
  public boolean checkSELECT(String s1) {
    if (s1.equalsIgnoreCase("select")) {
      return true;
    } else {
      return false;
    }
  }
  function TFormatter.checkSELECT(s1 : String): boolean;
  begin
    if ((UpperCase(s1)='SELECT')) then
    begin
      result := true;
    end else begin
      result := false;
    end;
  end;
------------------------------------------------------------------
  public static int testFor() {
    int sum = 0;
    for (int i=0; i<100; i++)
      sum = sum + 1;
  }
  function TFormatter.testFor(): int;
  var
    i : integer;
    sum : integer;
  begin
    sum:=0;
    i:=0;
    while (i<100) do begin
      sum:=sum+1;
      inc(i);
    end;
  end;
------------------------------------------------------------------
  private void doEscape2Space() {
    for (aD = 1; aD <= queryTokenCount; aD++) {
      if (isTokenQuoteLiterals[aD])
        continue;
      if (queryToken[aD].equals("\t")
          || queryToken[aD].equals("\f")
          || queryToken[aD].equals("\r")
          || queryToken[aD].equals("\b"))
        queryToken[aD] = " ";
      if (queryToken[aD].equals("\r"))
        queryToken[aD] = "\\n";
    }
  }
  procedure TFormatter.doEscape2Space();
  begin
    aD:=1;
    while (aD<=queryTokenCount) do begin
      if (isTokenQuoteLiterals[aD]) then
      begin
        continue;
      end;
      if ((queryToken[aD]=#9)
        or  (queryToken[aD]=#12)
        or  (queryToken[aD]=#13)
        or  (queryToken[aD]=#8)) then
      begin
        queryToken[aD]:=' ';
      end;
      if ((queryToken[aD]=#13)) then
      begin
        queryToken[aD]:='\\n';
      end;
      inc(aD);
    end;
  end;  
                                    
신고

Lex&Yacc으로 SQL 파서를 만들어 보자

Programming/Delphi 2007.08.17 01:04 Posted by 파란크리스마스

정규표현식이나, Lex&Yacc을 델파이만 개발 하신 분이라면 처음 들어 보신 분들도 계실 것이라고 생각됩니다.
저도 6년 넘게 개발하면서 최근에 알게 되었고, 그 활용 범위가 무궁무진 하다는 것도 알게 되었죠.
이 글을 있는 개발자 분들도 이 글을 계기로 Lex&Yacc에 대해서 관심을 가졌으면 합니다.

Lex&Yacc은 컴파일러를 만들기 위한 도구로 GCC나 대부분의 컴파일러가 Lex&Yacc을 사용하고 있습니다.
Lex&Yacc의 활용 범위는 소스를 분석하거나, 소스에서 주석만 제거하거나, 간단한 스크립트 언어를 만들 수도 있습니다.

C언어나 JAVA의 경우 많은 Lex&Yacc 도구가 많이 있지만 Delphi의 경우 2개 정도 있는 것 같고,
제가 사용하고 있는 Delphi Lex&Yacc은 Tuber Pascal로 만들어 진 것을 델파이용으로 수정한 것으로 버전은 1.3을 사용했습니다.

아래의 예제는 데이터베이스에서 SQL을 파싱하는 아주 간단한 Sample을 만들어 보았습니다.

select aa, bb from tab;
select aa, bb, cc from tab1, tab2;

위의 SQL 문장에서 컬럼과 테이블 명을 구하는 Lex&Yacc 소스입니다.
위의 SQL 문장의 컬럼과 테이블 명을 구하는 것을 Lex&Yacc을 사용하지 않고도 쉽게 얻어 낼 수 있겠지만, 굉장히 긴 문장의 SQL문장에서 컬럼, 테이블, 함수, 문자열을 분리하는 것을 어려울 것입니다. 이와 같은 SQL문 처리를 위해서 여러분들이 Lex&Yacc문장을 추가 하시기 바랍니다. (인터넷에 SQL grammar 찾아서 추가하면 될 듯......)

▶ Delphi Lex & Yccc Download

http://www.grendelproject.nl/dyacclex/

▶ Lex 파일

- sqllex.l 파일

%start

%%
 
[F|f][R|r][O|o][M|m] begin return(FROM); end;
[S|s][E|e][L|l][E|e][C|c][T|t] begin return(SELECT); end;

[A-Za-z][A-Za-z0-9_]* begin
yylval.yyString := yytext;
return (NAME);  end;

[ \t\n] ;

. |
\n returnc(yytext[1]);

- sqllex.pas 만들기

C:\Delphi\dyacclex-1.3\test\sql>dlex.exe sqllex.l
Delphi Lex - Copyright (c) 2003,2004 by Michiel Rook
Based on Turbo Pascal Lex 4.1, Copyright (c) 1990-2000 Albert Graef
parse ... DFA construction ... code generation ... DONE
15 lines, 6 rules, 27/1200 p, 29/600 s, 58/1200 t.

▶ Yacc 파일

- sqlparser.y 파일

%{
program sqlpser;
{$APPTYPE CONSOLE}


uses
SysUtils,
dlib,
yacclib,
lexlib;

var x : array [1..26] of Real;

%}

%token NAME
%token FROM SELECT /* illegal token */

%%

query_spec:
SELECT selection table_exp ';'
;

table_exp:
from_clause
;

from_clause:
FROM table_ref_commalist
;

table_ref_commalist:
table_ref
| table_ref_commalist ',' table_ref
;

table_ref:
table
| table range_variable
;

range_variable: NAME
;

table:
NAME { writeln('Table : ', $1); }
| NAME '.' NAME
;

selection:
scalar_exp_commalist
| '*'
;

scalar_exp_commalist:
scalar_exp
| scalar_exp_commalist ',' scalar_exp
;

scalar_exp:
column_ref
;

column_ref:
NAME { writeln('Column : ', $1); }
| NAME '.' NAME /* needs semantics */
| NAME '.' NAME '.' NAME
;

%%

{$I sqllex.pas}

var
lexer : TLexer;
parser : TParser;
i : Integer;

begin
for i := 1 to 26 do
x[i] := 0.0;

lexer := TLexer.Create();
  
parser := TParser.Create();
parser.lexer := lexer;
parser.parse();
end.

- sqlparser.dpr 만들기

C:\Delphi\dyacclex-1.3\test\sql>dyacc.exe sqlparser.y sqlparser.dpr
Delphi Yacc - Copyright (c) 2003,2004 by Michiel Rook
Based on Turbo Pascal Yacc 4.1, Copyright (c) 1990-2000 Albert Graef
parse ... sort ... closures ... first sets ... LR0 set ... lookaheads ...
code generation ... DONE
89 lines, 18/900 rules, 29/1200 s, 41/9600 i, 33/9600 t, 19/1200 r.

▶ 컴파일, 실행

- 컴파일

위의 lex, yacc 절차를 따르셨다면 sqlparser.dpr, sqllex.pas 파일이 생겼을 것입니다.
sqlparser.dpr, sqllex.pas 한 폴더에 두고 델파이에서 sqlparser.dpr을 열어서 컴파일 하고 sqlparser.exe 실행 하면 됩니다.

C:\Delphi\dyacclex-1.3\test\sql>sqlparser
select aa, bb from tab;
Column : aa
Column : bb
Table : tab
신고


 

티스토리 툴바