C 전 처리기 생성


18

목표는 원하는 언어로 소스 코드 크기 (바이트 단위) 로 가능한 작은 C 언어 용 프리 프로세서를 작성하는 것입니다 . 입력은 C 소스 파일이되고 출력은 사전 처리 된 소스 코드가됩니다.

처리 할 수있는 항목은 다음과 같습니다. 주석 제거 (라인 / 블록), #include 지시문 ( 상대 경로에서 파일 열고 필요한 지점에서 텍스트를 대체하여), #define, #undef, #if, #elif, #else, #endif, #ifdef, #ifndef 및 defined (). #pragmas 또는 #errors와 같은 다른 C 전 처리기 지시문은 무시해도됩니다.

#if 지시문에서 산술 표현식이나 비교 연산자를 계산할 필요가 없습니다.식이 0 이외의 정수를 포함하는 한 표현식이 true로 평가된다고 가정합니다 (주로 사용하는 것은 defined () 지시문에 사용됨). 가능한 입력 및 출력의 예는 다음과 같습니다 (출력 파일에 추가 공백이 더 잘 보이도록 잘려서 코드를 작성할 필요가 없습니다). 다음 예제를 올바르게 처리 할 수있는 프로그램이면 충분합니다.

----Input file: foo.c (main file being preprocessed)

#include "bar.h" // Line may or may not exist

#ifdef NEEDS_BAZZER
#include "baz.h"
#endif // NEEDS_BAZZER

#ifdef _BAZ_H_

int main(int argc, char ** argv)
{
    /*  Main function.
        In case that bar.h defined NEEDS_BAZ as true,
        we call baz.h's macro BAZZER with the length of the
        program's argument list. */
    return BAZZER(argc);
}

#elif defined(_BAR_H_)

// In case that bar.h was included but didn't define NEEDS_BAZ.
#undef _BAR_H_
#define NEEDS_BARRER
#include "bar.h"

int main(int argc, char ** argv)
{
    return BARRER(argc);
}

#else

// In case that bar.h wasn't included at all.
int main()
{return 0;}

#endif // _BAZ_H_

----Input file bar.h (Included header)

#ifndef _BAR_H_
#define _BAR_H_

#ifdef NEEDS_BARRER

int bar(int * i)
{
    *i += 4 + *i;
    return *i;
}

#define BARRER(i) (bar(&i), i*=2, bar(&i))

#else
#define NEEDS_BAZZER // Line may or may not exist
#endif // NEEDS_BARRER

#endif // _BAR_H_

----Input file baz.h (Included header)

#ifndef _BAZ_H_
#define _BAZ_H_

int baz(int * i)
{
    *i = 4 * (*i + 2);
    return *i;
}

#define BAZZER(i) (baz(&i), i+=2, baz(&i))

#endif // _BAZ_H_

----Output file foopp.c (no edits)

int baz(int * i)
{
    *i = 4 * (*i + 2);
    return *i;
}

int main(int argc, char ** argv)
{
    return (baz(&argc), argc+=2, baz(&argc));
}

----Output file foopp2.c (with foo.c's first line removed)

int main()
{return 0;}

----Output file foopp3.c (with bar.h's line "#define NEEDS_BAZZER" removed)

int bar(int * i)
{
    *i += 4 + *i;
    return *i;
}

int main(int argc, char ** argv)
{
    return (bar(&argc), argc*=2, bar(&argc));
}

입력 / 출력 샘플을 제공 할 수 있습니까?
Florent

테스트 코드를 제공해주세요. 예가 없으면 거의 불가능합니다.
Ismael Miguel

물론 이죠 시간과 작업량 제약으로 인해 매우 빠를 수 없으므로 조금 인내심을 가지십시오.
Thanasis Papoutsidakis

1
얼마나 #if지원해야합니까? 즉, 전처리 기는 산술, 비트 연산 등의 식을 지원해야합니까?
Hasturkun

좋아, 입 / 출력 예제와 추가 설명 추가
Thanasis Papoutsidakis

답변:


8

플렉스, 1170 + 4 = 1174

플렉스 코드의 1170 자 + 컴파일 플래그의 경우 4 자 실행 파일을 생성하려면을 실행하십시오 flex pre.l ; gcc lex.yy.c -lfl. 이 항목은 체처럼 메모리를 누출시키고 포함 된 파일을 닫지 않습니다. 그러나 그렇지 않으면 사양에 따라 완벽하게 작동해야합니다.

%{
#define M malloc
#define X yytext
#define A a=X
#define B(x) BEGIN x;
#define Y YY_CURRENT_BUFFER
*a,*b,**v,**V,**t,**T,i,s=1,o;
g(){t=M(++s);T=M(s);for(i=1;i<s-1;i++)t[i]=v[i],T[i]=V[i];free(v);free(V);v=t;V=T;}
f(){for(i=1;i<s;i++)if(!strcmp(v[i],a))return i;return 0;}
d(y){X[yyleng-y]=0;}
%}
%x D F I
N .*\n
%%
"//".*
"/*"([^\*]|\*[^\/])*"*/"
\"(\\.|[^\\"])*\" ECHO;
^"#include "\"[^\"]*\" d(1),yypush_buffer_state(yy_create_buffer(fopen(X+10,"r"),YY_BUF_SIZE));
^"#define "[^ ]* {B(D)strcpy(a=M(yyleng),X+8);}
<D>" "?{N} {b=M(yyleng);d(1);f(strcpy(b,X+(X[0]==32)))?free(V[i]),V[i]=b:g(),v[s-1]=a,V[s-1]=b;B(0)}
^"#undef "{N} d(1),v[f(A+7)][0]=0;
^"#if defined(".*")\n" h(2,12);
^"#ifdef "{N} h(1,7);
^"#if "{N} {d(1);if(!atoi(X+4))B(F)}
^"#ifndef "{N} {d(1);if(f(A+8))B(F)}
<F>^"#if"{N} o++;
<F>^"#endif"{N} if(!o--)B(++o)
<F>^"#else"{N} if(!o)B(0)
<F>^"#elif defined(".*")\n" if(!o){d(2);if(f(A+14))B(0)}
<F>^"#elif "{N} if(!o){d(1);if(atoi(X+6))B(0)}
<F>{N}
^"#endif"{N}
^"#el"("se"|"if"){N} B(I)
<I>^"#endif"{N} B(0)
<I>{N}
[a-zA-Z_][a-zA-Z_0-9]* printf(f(A)?V[i]:a);
<<EOF>> {a=Y;yypop_buffer_state();if(!Y)exit(0);fclose(a);}
%%
h(x,y){d(x);if(!f(A+y))B(F)}

몇 가지 설명 :

  • ab상기 입력 문자열에서 유지하는 임시 직원이다. a기능 할 매개 변수로도 사용됩니다 f.
  • v매크로의 이름을 V보유하고 매크로 의 'V'alues를 보유
  • t그리고 T우리가 자랄 때에 대한 t'emporary 홀더가 '있다 vV
  • i 'i'ncrementer for loops입니다.
  • s 매크로 배열의 's'ize
  • oif거짓 조건부 안의 'o'pen 의 개수입니다.
  • g() 'g'매크로 배열을 행합니다
  • f()'f'는 같은 값을 가진 매크로 va
  • d(y)'d' y현재 입력에서 마지막 문자를 잘라 냅니다
  • 상태 D는 'D' efine 내부입니다
  • 상태 F는 'F'alse 조건부 무시
  • 상태 I는 진정한 조건이 발견 된 후 'I'무시 else/ ' elif입니다.

EDIT1 : 많은 메모리 누수를 정리하고 파일 닫기를 구현했습니다.

EDIT2 : 중첩 된 매크로를보다 정확하게 처리하도록 수정 된 코드

EDIT3 : 미친 양의 골프

EDIT4 : 더 많은 골프

EDIT5 : 더 많은 골프; fclose ()를 호출하면 일부 컴퓨터에서 문제가 발생한다는 것을 알았습니다.


대부분의 경우 지금까지 매우 잘 작동합니다 ... 어떤 이유로 든 내가 #include물건을 만들 때 세그먼테이션 오류가 발생 하지만 편집 # 5의 버그와 관련이 있다고 생각합니다. 또한 #if 블록을 성공적으로 처리하더라도 매크로를 대체하지 않습니다. 내가 잘못하고 있지 않는 한 일반적으로 매우 좋아 보이며 렉서가 할 수있는 일에 대한 대략적인 아이디어를 제공합니다. 골프 형태로도 이해할 수 있습니다. 코드가 잘 설명되어있는 것처럼 버그가 수정 될 수 있는지 확인하십시오. 아니면 괜찮습니다. 아마도 다른 항목이 없으므로 답변이 선택 될 것입니다.
Thanasis Papoutsidakis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.