Tạo tiền xử lý C


18

Mục tiêu là tạo ra một bộ tiền xử lý cho ngôn ngữ C, càng nhỏ càng tốt về kích thước mã nguồn theo byte , bằng ngôn ngữ ưa thích của bạn. Đầu vào của nó sẽ là một tệp nguồn C và đầu ra của nó sẽ là mã nguồn được xử lý trước.

Các mục mà nó sẽ cần để có thể xử lý sẽ là: Xóa nhận xét (dòng / khối), #include chỉ thị (bằng cách mở tệp tại các đường dẫn tương đối và thay thế văn bản tại điểm cần thiết), #define, #undef, #if, #elif, #else, #endif, #ifdef, #ifndef và được xác định (). Các chỉ thị tiền xử lý C khác như #pragmas hoặc #errors có thể bị bỏ qua.

Không cần tính toán các biểu thức số học hoặc toán tử so sánh trong các lệnh #if, chúng tôi giả sử biểu thức sẽ đánh giá là đúng miễn là nó chứa một số nguyên khác 0 (sử dụng chính của nó sẽ là chỉ thị () được xác định). Ví dụ về các đầu vào và đầu ra có thể theo sau (các khoảng trắng bổ sung có thể có trong các tệp đầu ra đã được cắt bớt để xuất hiện tốt hơn, không cần mã của bạn để làm như vậy). Một chương trình có thể xử lý các ví dụ sau đúng sẽ được coi là đủ.

----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));
}

Bạn có thể cung cấp mẫu đầu vào / đầu ra?
Florent

Cung cấp cho chúng tôi một mã kiểm tra. Nó gần như không thể nếu không có ví dụ.
Ismael Miguel

Uh chắc chắn, tôi sẽ. Hãy kiên nhẫn một chút vì tôi không thể rất nhanh do hạn chế về thời gian và khối lượng công việc.
Thanocation Papoutsidakis

1
Bao nhiêu #ifnhu cầu cần được hỗ trợ? tức là bộ tiền xử lý có cần hỗ trợ các biểu thức với các phép toán số học, bitwise, v.v. không?
Hasturkun

ok, ví dụ đầu vào / đầu ra và giải thích thêm được thêm vào
Thanocation Papoutsidakis

Câu trả lời:


8

Linh hoạt, 1170 + 4 = 1174

1170 ký tự trong mã flex + 4 ký tự cho cờ biên dịch. Để sản xuất một thực thi, chạy flex pre.l ; gcc lex.yy.c -lfl. Mục nhập rò rỉ bộ nhớ như một cái sàng và không đóng các tệp được bao gồm. Nhưng nếu không, nó sẽ hoàn toàn hoạt động theo thông số kỹ thuật.

%{
#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)}

Một số giải thích:

  • ablà temps để giữ chuỗi từ đầu vào. acũng được sử dụng làm tham số cho chức năng f.
  • vgiữ tên của macro và Vgiữ 'V'alues ​​của macro
  • tTlà những người nắm giữ tạm thời khi chúng ta phát triển vV
  • i là một 'i'ncrementer cho các vòng lặp
  • s là 's'ize của mảng macro
  • olà số lượng 'o'pen ifs bên trong một điều kiện sai
  • g() 'G'row các mảng macro
  • f()'tìm một macro có cùng giá trị vnhưa
  • d(y)'Các yký tự cuối cùng từ đầu vào hiện tại
  • trạng thái Dlà bên trong một 'Define
  • trạng thái Flà để bỏ qua một điều kiện 'F'alse
  • trạng thái Ilà cho 'Tôi nhận biết else/ elifsau khi tìm thấy một điều kiện thực sự.

EDIT1: dọn sạch nhiều rò rỉ bộ nhớ và thực hiện đóng tệp

EDIT2: mã được sửa đổi để xử lý các macro lồng nhau chính xác hơn

EDIT3: số lượng golf điên cuồng

EDIT4: chơi gôn nhiều hơn

EDIT5: chơi gôn nhiều hơn; Tôi cũng nhận thấy rằng cuộc gọi của tôi tới fclose () gây ra sự cố trên một số máy tính ... đang xem xét vấn đề này.


Nó hoạt động rất tốt cho đến nay trên hầu hết các trường hợp ... vì một số lý do, nó gây ra lỗi phân đoạn khi tôi #includenhét, nhưng tôi đoán điều này có liên quan đến lỗi trong chỉnh sửa # 5. Ngoài ra, nó không thay thế các macro, mặc dù nó xử lý thành công các khối #if - trừ khi tôi làm sai điều gì đó ... nhưng nói chung nó trông rất tốt, và nó cho một ý tưởng sơ bộ về những gì một người làm từ vựng có thể làm, vì Tôi có thể hiểu nó ngay cả ở dạng chơi gôn. Hãy thử xem các lỗi có thể được sửa hay không, nếu không ổn, vì mã giải thích rõ, có lẽ đây sẽ là câu trả lời được chọn vì không có mục nào khác.
Thanocation Papoutsidakis
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.