2010-01-25 22 views
22

Tôi muốn thực hiện một quy tắc trong flex để tiêu thụ một lời nhận xét c kiểu như/* */khó khăn trong việc bình luận c-style trong flex/lex

tôi đã sau

c_comment "/*"[\n.]*"*/" 

Nhưng nó không bao giờ được kết hợp. Bất kỳ ý tưởng tại sao? nếu bạn cần thêm mã của tôi, vui lòng cho tôi biết và tôi sẽ gửi toàn bộ nội dung. Nhờ bất cứ ai trả lời.

+1

Tôi không chắc chắn lý do tại sao bạn không nhận được trận đấu đó, nhưng biểu hiện của bạn sẽ ăn tất cả mọi thứ trong file giữa người đầu tiên "/* "và" */"cuối cùng. Biểu thức của bạn để khớp với nội dung của nhận xét phải loại trừ "* /" khỏi bị tiêu thụ. Một cách để thực hiện việc này: http://flex.sourceforge.net/manual/How-can-I-match-C_002dstyle-comments_003f.html –

+1

cảm ơn, trang web đó hữu ích – adhanlon

Trả lời

35

Tôi khuyên bạn nên sử dụng start conditions để thay thế.

%x C_COMMENT 

"/*"   { BEGIN(C_COMMENT); } 
<C_COMMENT>"*/" { BEGIN(INITIAL); } 
<C_COMMENT>\n { } 
<C_COMMENT>. { } 

Do lưu ý rằng có phải không được bất kỳ khoảng trắng giữa <condition> và nguyên tắc.

%x C_COMMENT xác định trạng thái C_COMMENT và quy tắc /* bắt đầu. Khi nó bắt đầu, */ sẽ quay trở lại trạng thái ban đầu (INITIAL được xác định trước) và mọi ký tự khác sẽ chỉ được sử dụng mà không có bất kỳ hành động cụ thể nào. Khi hai quy tắc khớp với nhau, Flex làm mất hiệu lực bằng cách lấy một đối số có kết quả khớp dài nhất, do đó quy tắc chấm không ngăn không cho */ khớp với. Quy tắc \n là cần thiết vì a dot matches everything except a newline.

Định nghĩa %x làm C_COMMENT một độc quyền nhà nước, có nghĩa là lexer sẽ chỉ phù hợp với quy tắc được "gắn thẻ" <C_COMMENT> khi nó đi vào nhà nước.

Đây là một tiny example lexer thực hiện câu trả lời này bằng cách in mọi thứ ngoại trừ những gì bên trong /* comments */.

+0

cảm ơn sự giúp đỡ, đó là những gì tôi đã làm và nó đã làm việc – adhanlon

+2

Tôi hiểu rằng tôi đã quá muộn để đảng, nhưng regex này sẽ nhận dạng không chính xác '/ * rác */* /' như là một nhận xét khối hoàn chỉnh (từ '/ *' đến 2nd '* /'), như trái ngược với các nhận xét khối kiểu C trong đó mở '/ *' được kết thúc bằng cách đóng '* /' gần nhất và '* /' khác được xác định là ký tự đi lạc trong chương trình. Regex sau (cho flex/lex) xử lý trường hợp này là '"/* "(((" * "[^ /])?) | [^ *]) *" */"' Nguồn - [link] (http://stackoverflow.com/questions/16160190/regular-expression-to-find-c-style-block-comments) – Shobhit

+0

Vấn đề ở đây là với '. {} ', Nếu @zneak đã sử dụng follopwing, nó sẽ được giải quyết' [^ * \ n] * "*" + [^ */\ n] * '. nó sẽ ăn hết mọi thứ trừ * theo sau là /. Vì vậy, trong trường hợp này, nó sẽ kết thúc trong * đầu tiên theo sau là /. vì vậy '/ * rác */foolosh * /', nó sẽ nhận xét '/ * rác * /' và làm theo mã thông báo tiếp theo cho 'ngu ngốc * /' –

6

Không chắc chắn lý do tại sao nó không được chọn nhưng tôi biết rằng một mô hình của loại đó có thể tạo ra các yếu tố từ vựng lớn. Việc phát hiện chỉ đánh dấu nhận xét bắt đầu và quăng tất cả mọi thứ trong bitbucket hiệu quả hơn cho đến khi bạn tìm thấy điểm đánh dấu kết thúc.

This site có mã mà sẽ làm điều đó:

"/*" { 
    for (;;) { 
     while ((c = input()) != '*' && c != EOF) 
      ; /* eat up text of comment */ 
     if (c == '*') { 
      while ((c = input()) == '*') 
       ; 
      if (c == '/') 
       break; /* found the end */ 
     } 
     if (c == EOF) { 
      error ("EOF in comment"); 
      break; 
     } 
    } 
} 
+1

Tôi không chắc chắn nó thực sự tốt để tiêu thụ đầu vào theo cách đó. =/Đó không phải là một sự pha trộn của mối quan tâm? – zneak

+0

Tôi thường có xu hướng theo chủ nghĩa thực dụng hơn chủ nghĩa giáo điều :-) – paxdiablo

+0

Tôi chỉ thấy một mối quan tâm ở đây, và đó là ăn ý kiến ​​để bạn có thể tiếp tục với các thẻ thực sự lexing. Tuy nhiên, bạn có thể cho rằng ví dụ này không tận dụng các cơ chế trừu tượng mà flex cung cấp để làm cho những gì bạn đang làm rõ ràng hơn. –

2

Tôi tin rằng giải pháp này là đơn giản:

"/*"((\*+[^/*])|([^*]))*\**"*/" 
+0

Ngay cả khi nó là chính xác (khó khăn cho tôi thấy), nó không hiệu quả kể từ khi một từ vựng khá dài có thể cần phải được đệm trong 'yytext'. – wcochran

8

Dưới đây là một ví dụ chỉ trong trường hợp bất cứ ai là nhầm lẫn về cách làm việc trả lời zneak của:

(Về cơ bản, bạn đặt "% x C_COMMENT" trong phần đầu tiên và phần còn lại trong phần thứ hai, như được giải thích bằng liên kết hữu ích của mình)

foo.l 

%{ 
// c code.. 
%} 
%x C_COMMENT 

%% 
"/*"   { BEGIN(C_COMMENT); } 
<C_COMMENT>"*/" { BEGIN(INITIAL); } 
<C_COMMENT>. { } 

%% 
// c code.. 

Hy vọng rằng sẽ giúp ai đó! Tiff

0

Các hoạt động ví dụ là:

\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/ 

mà tìm thấy trong ostermiller.org

+0

Trong Flex, '[^ *]' bao gồm cả '\ r' và' \ n' (và mọi mã 8 bit khác ngoại trừ '*'), vì thế '| [\ r \ n]' là không cần thiết. (Giống như hầu hết các môi trường regex khác trong bài viết được liên kết, ngoại trừ 'nedit'.) – rici

0

Tôi đã thử một số các giải pháp đề xuất và đây là kết quả.

  • tôi không thể có được giải pháp C_COMMENT, trong đó có nhiều nhất up-phiếu và sẽ rất tốt, làm việc tại tất cả trong thực tế (một trong những ý kiến ​​để nó giải thích ít nhất một lý do tại sao). Nó nên được downvoted và chắc chắn không nên là giải pháp được bầu chọn cao nhất
  • Giải pháp từ Mugen dường như hoạt động trong tất cả mã tôi đã chạy trên
  • Không thể lấy giải pháp từ Andrey để biên dịch cả trong lex . Tôi đã xem trang web được tham chiếu và sử dụng các mẫu từ đó đã không giúp đỡ
  • câu trả lời từ paxdiablo đã hoạt động và có lợi thế là dễ đọc. Tôi cũng được sửa đổi như sau:

     
    "/*" { int c1 = 0, c2 = input(); 
         for(;;) { 
         if(c2 == EOF) break; 
         if(c1 == '*' && c2 == '/') 
          break; 
         c1 = c2; 
         c2 = input(); 
         } 
        } 
    
+0

Nó không hoàn toàn rõ ràng với tôi tại sao giải pháp trong câu trả lời của tôi không hiệu quả với bạn. Trong trường hợp hai quy tắc flex khớp nhau, quy tắc dài nhất sẽ được ưu tiên. Điều này có nghĩa là quy tắc '.' sẽ không bao giờ tiêu thụ' * 'của một dấu hiệu' */'. [Lexer] (http://pastebin.com/8WT5i2nZ) không bị vấn đề mà bạn mô tả: đầu vào '/ * hello */world * /' tạo đầu ra 'world * /' như mong đợi. – zneak

+0

Tôi đã thêm nhận xét vào câu trả lời của bạn giải thích vấn đề tôi gặp phải, có liên quan đến các dòng mới được nhúng trong khối nhận xét – mwag

-2

"/*"(.|\n)"*/" thay đổi biểu hiện thường xuyên của bạn vào đó, nó sẽ làm việc cho chắc chắn.

1

Có một ví dụ cách trong the Flex manual, mà được các trường hợp cạnh gnarly phải:

<INITIAL>"/*"   BEGIN(IN_COMMENT); 
<IN_COMMENT>"*/"  BEGIN(INITIAL); 
<IN_COMMENT>[^*\n]+ // eat comment in chunks 
<IN_COMMENT>"*"  // eat the lone star 
<IN_COMMENT>\n  yylineno++;