2010-03-11 7 views
5

tôi đang tìm kiếm một công cụ có thể chuyển đổi biểu thức mã C cho các hình thức:C: Chuyển đổi A? B: C vào if (A) B khác C

a = (A) ? B : C; 

vào cú pháp 'mặc định' với if/else báo cáo:

if (A) 
    a = B 
else 
    a = C 

Có ai đó biết một công cụ có khả năng thực hiện chuyển đổi đó không?

Tôi làm việc với GCC 4.4.2 và tạo tệp được xử lý trước với -E nhưng không muốn các cấu trúc như vậy trong đó.

Edit: mã sau đây nên được chuyển đổi, quá:

a = ((A) ? B : C)->b; 
+0

Điều này kêu la "macro tuyệt vời, sơ sài!" với tôi. –

+1

Chỉ có một tệp? Nếu có thể bạn có thể làm điều đó với một biểu thức chính quy phức tạp và chức năng tìm kiếm thay thế của một trình soạn thảo có thể làm điều này. –

+23

Tại sao? Bạn nên xem xét có những tình huống mà không có tương đương ngữ nghĩa. Không có gì sai với toán tử ternary. – GManNickG

Trả lời

12

Coccinelle có thể làm được điều này khá dễ dàng.

Coccinelle là một kết hợp chương trình và cơ chuyển đổi cung cấp ngôn ngữ SmPL (Semantic patch Language) để xác định mong muốn trận đấu và sự biến đổi trong mã C. Coccinelle ban đầu được nhắm mục tiêu theo hướng thực hiện tài sản thế chấp diễn biến trong Linux. diễn biến như vậy bao gồm những thay đổi cần thiết trong mã khách hàng để đáp ứng với diễn biến trong API thư viện, và có thể bao gồm sửa đổi như đổi tên một chức năng, thêm một chức năng lập luận có giá trị là bằng cách nào đó bối cảnh phụ thuộc, và tổ chức lại a cấu trúc dữ liệu. Ngoài tài sản thế chấp diễn biến, Coccinelle thành công được sử dụng (bởi chúng tôi và những người khác) để tìm kiếm và sửa lỗi trong mã hệ thống.

EDIT: Một ví dụ về bản vá ngữ nghĩa:

@@ expression E; constant C; @@ 
(
    !E & !C 
| 
- !E & C 
+ !(E & C) 
) 

Từ các tài liệu:

Các mô hình x & y. Biểu thức của biểu mẫu này hầu như luôn vô nghĩa, bởi vì nó kết hợp toán tử boolean với toán tử bit. Cụ thể, nếu bit ngoài cùng bên phải của y là 0, kết quả sẽ luôn là 0. Bản vá ngữ nghĩa này tập trung vào trường hợp y là hằng số.

Bạn có một bộ ví dụ tốt here.

Danh sách gửi thư thực sự hoạt động và hữu ích.

0

Tôi không biết điều như toán tử bậc ba được tích hợp các đặc tả ngôn ngữ làm lối tắt cho logic if ... cách duy nhất tôi có thể nghĩ là thực hiện tìm kiếm theo cách thủ công viết lại nó dưới dạng if được sử dụng ...như một sự đồng thuận chung, các nhà điều hành ternary làm việc như thế này

 
expr_is_true ? exec_if_expr_is_TRUE : exec_if_expr_is_FALSE; 

Nếu biểu thức được đánh giá đến mức khó tin, thực hiện phần giữa ?:, nếu không thực hiện phần cuối cùng giữa :;. Nó sẽ ngược lại nếu cụm từ được đánh giá là sai

 
expr_is_false ? exec_if_expr_is_FALSE : exec_if_expr_is_TRUE; 
0

Nếu câu lệnh rất thường xuyên như thế này tại sao không chạy tệp của bạn thông qua một tập lệnh Perl nhỏ? Logic cốt lõi để làm việc tìm và biến đổi là đơn giản cho dòng ví dụ của bạn. Dưới đây là một cách tiếp cận xương trần:

use strict; 
while(<>) { 
    my $line = $_; 
    chomp($line); 
    if ($line =~ m/(\S+)\s*=\s*\((\s*\S+\s*)\)\s*\?\s*(\S+)\s*:\s*(\S+)\s*;/) { 
     print "if(" . $2 . ")\n\t" . $1 . " = " . $3 . "\nelse\n\t" . $1 . " = " . $4 . "\n"; 
    } else { 
     print $line . "\n"; 
    } 
} 
exit(0); 

Bạn muốn chạy nó như vậy:

perl transformer.pl <foo.c> foo.c.new 

Tất nhiên nó được khó khăn hơn nếu mẫu văn bản không phải là thường xuyên như một trong những bạn đăng. Nhưng miễn phí, nhanh chóng và dễ dàng để thử.

+0

Điều này không làm việc cho: a = ((A)? B: C) -> b; – tur1ng

+0

Tôi đã cảnh báo bạn rằng nó chỉ dành cho ví dụ bạn cung cấp. :) Thay vì cố gắng viết một số biểu thức chính quy uber bạn có thể làm cho trường hợp elsif thứ hai khá dễ dàng: m/(\ S +) \ s * = \ s * \ (\ s * \ ((\ s * \ S + \ s *) \) \ s * \? \ s * (\ S +) \ s *: \ s * (\ S +) \ s * \) \ s * -> \ s * (\ S +) \ s *;/- - cuộc gọi dereference là nhóm đối sánh $ 4 ngay bây giờ. –

+1

@ tur1ng: Tôi nghĩ rằng ví dụ với-> có thể không thể bedone mà không có biến tạm thời. –

3

Bản vá ngữ nghĩa sau cho Coccinelle sẽ thực hiện chuyển đổi.

@@ 
expression E1, E2, E3, E4; 
@@ 

- E1 = E2 ? E3 : E4; 
+ if (E2) 
+ E1 = E3; 
+ else 
+ E1 = E4; 

@@ 
type T; 
identifier E5; 
T *E3; 
T *E4; 
expression E1, E2; 
@@ 

- E1 = ((E2) ? (E3) : (E4))->E5; 
+ if (E2) 
+ E1 = E3->E5; 
+ else 
+ E1 = E4->E5; 


@@ 
type T; 
identifier E5; 
T E3; 
T E4; 
expression E1, E2; 
@@ 

- E1 = ((E2) ? (E3) : (E4)).E5; 
+ if (E2) 
+ E1 = (E3).E5; 
+ else 
+ E1 = (E4).E5; 
1

DMS Software Reengineering Toolkit có thể thực hiện việc này bằng cách áp dụng biến đổi chương trình.

Một chuyển đổi DMS cụ thể để phù hợp với ví dụ cụ thể của bạn:

domain C. 

rule ifthenelseize_conditional_expression(a:lvalue,A:condition,B:term,C:term): 
stmt -> stmt 
= " \a = \A ? \B : \C; " 
-> " if (\A) \a = \B; else \a=\C ; ". 

Bạn sẽ cần một quy tắc để xử lý trường hợp khác của bạn, nhưng nó cũng không kém phần dễ dàng để bày tỏ.

Các phép biến đổi hoạt động trên cấu trúc mã nguồn thay vì văn bản, do đó bố cục và nhận xét sẽ không ảnh hưởng đến nhận dạng hoặc ứng dụng. Dấu ngoặc kép trong quy tắc không phải là trích dẫn chuỗi truyền thống, mà đúng hơn là các dấu ngoặc kép về ngôn ngữ học, tách biệt ngôn ngữ cú pháp quy tắc khỏi độ tuổi mẫu được sử dụng để chỉ định cú pháp cụ thể được thay đổi.

Có một số vấn đề với chỉ thị tiền xử lý nếu bạn định giữ lại chúng. Vì bạn đã sẵn sàng làm việc với mã mở rộng tiền xử lý, bạn có thể yêu cầu DMS thực hiện tiền xử lý như là một phần của bước chuyển đổi; nó có đầy đủ các bộ tiền xử lý tương thích với GCC4 và GCC4 được xây dựng ngay.

Như những người khác đã quan sát, đây là một trường hợp khá dễ dàng vì bạn đã chỉ định nó hoạt động ở cấp một câu lệnh đầy đủ. Nếu bạn muốn loại bỏ mã của bất kỳ phép gán nào tương tự như câu lệnh này, với các nhiệm vụ được nhúng trong các ngữ cảnh khác nhau (khởi tạo, v.v.), bạn có thể cần một bộ biến đổi lớn hơn để xử lý các nhóm trường hợp đặc biệt khác nhau. cần phải sản xuất các cấu trúc mã khác (ví dụ, các biến tạm thời của loại thích hợp). Điều tốt về một công cụ như DMS là nó có thể tính toán một cách rõ ràng một loại biểu tượng cho một biểu thức tùy ý (do đó khai báo kiểu của bất kỳ temps cần thiết) và bạn có thể viết một tập lớn hơn khá đơn giản và áp dụng tất cả chúng.

Tất cả những gì đã nói, tôi không chắc chắn về giá trị thực của việc thực hiện thao tác loại bỏ biểu thức bậc ba điều kiện của bạn. Khi trình biên dịch được giữ kết quả, bạn có thể nhận được mã đối tượng tương tự như thể bạn đã không thực hiện các phép biến đổi chút nào. Xét cho cùng, trình biên dịch cũng có thể áp dụng các phép biến đổi bảo toàn tương đương.

Rõ ràng là có giá trị trong việc thực hiện các thay đổi thông thường nói chung.

(DMS có thể áp dụng các biến đổi chương trình nguồn thành nguồn cho nhiều langauges, bao gồm C, C++, Java, C# và PHP).