모든 루핑 문과 분기 문을 제거하고 다른 문을 실행할 수있는 PHP 파서
PHP 코드 예 :-
입력
<?php
if(1){
echo "hello";
}
while(1){
echo "world";
}
산출
<?php
echo "hello";
echo "world";
이것은 완전한 언어 파서 없이는 매우 어렵습니다.
프로그램 변환 시스템 (PTS)으로 이를 수행 할 수 있습니다 . 이들은 소스 코드를 컴파일러 데이터 구조 (종종 추상 구문 트리 [AST])로 구문 분석하고 AST를 변경 한 다음 수정 된 컴파일러 데이터 구조에서 유효한 소스 텍스트를 다시 생성 할 수있는 도구입니다.
약한 PTS는 컴파일러가 수행하는 고전적인 방식으로 절차 적으로 트리를 걷거나 / 검사 / 변경할 수 있도록합니다. 이 접근 방식을 사용하면 데이터 구조에 대해 잘 알고 있어야합니다 (예 : 트리의 정확한 구조를 알아야 함). 실제 언어의 경우 알고 있어야 할 세부 사항이 많이 있습니다. 열정이 많으면 효과가 있습니다.
좋은 PTS를 사용하면 트리를 검색 / 변경하는 데 사용할 소스-소스 변환을 제공 할 수 있습니다. 이러한 재 작성은 다음과 같습니다.
when you see *thispattern*, replace it by *thatpattern*, if *condition*
여기서 thispattern 과 thatpattern 은 변환되는 소스 언어로 작성된 패턴입니다. PTS는 그것들을 상응하는 컴파일러 데이터 구조로 변환하는 것을 처리하므로 훨씬 적은 지식으로 얻을 수 있습니다.
OP의 경우 그는 PHP를 구문 분석하고 변환 할 수있는 PTS가 필요합니다.
내가 아는 유일한 "좋은"PTS 는 PHP 프론트 엔드 가있는 DMS 소프트웨어 리엔지니어링 툴킷 입니다 .
짧은 DMS 메타 프로그램을 작성하여 파일을 열고 읽고, 변환을 가져 와서 적용한 다음 결과를 예쁘게 인쇄해야합니다 (명확성을 위해 약간 단순화).
(define main
(action (procedure void)
(= AST (Registry:Parse PHPDomain `my_file.php'))
(Registry:ApplyTransforms AST (. `my_rewrite_rules.rsl') (. `strip_control_flow'))
(local (= [os OutputStream:Stream] (OutputSteam:Open `updated_my_file.php'))=
(Registry:PrettyPrint os PHPDomain AST))
(= os (OutputStream:Close os))
)local
)action
)define
대부분의 작업은 "my_rewrite_rules.rsl"파일의 DMS 재 작성 규칙에 의해 수행됩니다.
domain PHP~PHP5.
rule strip if_then(c: expression, s: statement):
statement -> statement =
" if (\c) \s" -> "\s".
rule strip if_then_else(c: expression, s1: statement, s2: statement):
statement -> statement =
" if (\c) \s1 else \s2" -> " { \s1 \s2 } ".
rule strip while(c: expression, s: statement):
statement -> statement =
" while (\c) \s" -> "\s".
rule strip catch( b1: statements, l: catch_clauses, t: type, e: expression, b2: statements):
statement -> statement =
" try { \b1 } \l catch ( \t \e ) { \b2 } "
-> " { try { \b1 } \l ; \b2 } ".
rule strip_trivial_try( b1: statements):
statement -> statement =
" try { \b1 } " -> "{ \b1 }".
rule strip_useless_block( b:statements, s: statements):
statements -> statements =
" { \b } \s " -> " \b \s ".
ruleset strip_control_flow = {
strip_if_then,
strip_if_then_else,
strip_while,
strip_catch,
strip_trivial_try,
strip_useless_block }
등. 모든 사례를 다루지는 않았지만 진행 방법이 분명해야합니다.
위의 설명 : DMS 다시 쓰기 규칙은 다음과 같은 형식을 취합니다.
rule rulename ( pattern_variable_declarations):
syntaxcategory -> syntaxcategory
"thispattern" -> "thatpattern".
thispattern 및 thatpattern 은 재 작성 규칙 언어 자체의 구문과 소스 프로그램 패턴 텍스트를 구별하는 메타 따옴표 "..." 안에 작성됩니다. 메타 따옴표 를 사용하면 패턴 변수 선언에서 구문 범주가 x : 범주 로 선언 된 패턴 변수 \ x 와 혼합 된 소스 언어 텍스트를 찾습니다 . 언어의 주요 구문 범주 (예 : "문"대 "문"대 "표현식")를 알아야하지만 while 루프의 모든 내부 구조에 대해서는 알지 못합니다.
규칙 집합 그룹을 일괄 적으로 적용 할 수있는 편리한 번들로 명명 규칙을 흥미의 세트; 이 규칙 세트가 DMS 메타 프로그램에서 어떻게 언급되는지 볼 수 있습니다.
이 규칙 세트를 작성할 때 사용되는 트릭은 각 규칙이 제어 된 콘텐츠 요소를 블록 {...}로 제거하는 것입니다. 블록은 문으로 허용되기 때문입니다. 정리 규칙 strip_useless_blocks는 생성 된 모든 심각한 블록을 제거합니다.
여기에서 DMS 다시 쓰기 규칙이 작성되는 방법에 대해 자세히 알아볼 수 있습니다 .
이러한 재 작성 규칙은 후속 단계를 통해 OP의 프로그램을 점진적으로 변환합니다 (각 변환 후 전체 AST를 예쁘게 인쇄하여이를 확인할 수 있음).
스타트:
<?php
if(1){
echo "hello";
}
while(1){
echo "world";
}
strip_if_then 이후 :
<?php
{
echo "hello";
}
while(1){
echo "world";
}
strip_while 이후 :
<?php
{
echo "hello";
}
{
echo "world";
}
strip_useless_block의 첫 번째 적용 후 :
<?php
echo "hello";
{
echo "world";
}
strip_useless_block의 두 번째 적용 후 :
<?php
echo "hello";
echo "world";
그리고 우리는 OP가 원하는 결과를 얻었습니다. 이것은 큰 파일에서 훨씬 더 훌륭합니다.
따라서 OP의 작업은 좋은 PTS로 수행하기가 매우 쉽습니다.
나는 누군가가 이와 같이 제어 흐름을 제거하기를 원하는 이유에 대한 단서가 없다는 것을 인정할 것입니다. 그러나 PTS의 요점은 직접 수행하기 어려운 임의의 코드 변경 작업을 수행하도록 구성 할 수 있다는 것입니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다