2009-04-26 20 views
5

Tôi tự dạy mình sử dụng JavaCC trong một dự án sở thích và có một ngữ pháp đơn giản để viết một trình phân tích cú pháp. Một phần của phân tích cú pháp bao gồm:Giải thích và giải pháp cho cảnh báo của JavaCC "Lựa chọn biểu thức chính quy: FOO không bao giờ có thể được so khớp như: BAR"?

TOKEN : { < DIGIT : (["0"-"9"]) > } 
TOKEN : { < INTEGER : (<DIGIT>)+ > } 
TOKEN : { < INTEGER_PAIR : (<INTEGER>){2} > } 
TOKEN : { < FLOAT : (<NEGATE>)? <INTEGER> | (<NEGATE>)? <INTEGER> "." <INTEGER> | (<NEGATE>)? <INTEGER> "." | (<NEGATE>)? "." <INTEGER> > } 
TOKEN : { < FLOAT_PAIR : (<FLOAT>){2} > } 
TOKEN : { < NUMBER_PAIR : <FLOAT_PAIR> | <INTEGER_PAIR> > } 
TOKEN : { < NEGATE : "-" > } 

Khi biên dịch với javacc tôi nhận được kết quả:

Warning: Regular Expression choice : FLOAT_PAIR can never be matched as : NUMBER_PAIR 

Warning: Regular Expression choice : INTEGER_PAIR can never be matched as : NUMBER_PAIR 

Tôi chắc chắn đây là một khái niệm đơn giản nhưng tôi không hiểu cảnh báo, là một người mới trong cả việc tạo trình phân tích cú pháp và các biểu thức chính quy.

Cảnh báo này có ý nghĩa gì (ở dạng người mới sử dụng như bạn có thể nhận được)?

Trả lời

4

Tôi không biết JavaCC, nhưng tôi là kỹ sư biên dịch.

Quy tắc FLOAT_PAIR không rõ ràng. Hãy xem xét văn bản sau:

0.0 

Đây có thể là FLOAT 0 theo sau là FLOAT .0; hoặc có thể là FLOAT 0., tiếp theo là FLOAT 0; cả hai kết quả trong FLOAT_PAIR. Hoặc nó có thể là một FLOAT 0.0.

Quan trọng hơn, mặc dù, bạn đang sử dụng phân tích từ vựng với bố cục theo cách không bao giờ có khả năng hoạt động. Hãy xem xét số này:

12345 

Điều này có thể được phân tích cú pháp là INTEGER 12, INTEGER 345 dẫn đến INTEGER_PAIR. Hoặc có thể được phân tích cú pháp là INTEGER 123, INTEGER 45, một số khác là INTEGER_PAIR. Hoặc có thể là INTEGER 12345, một mã thông báo khác. Vấn đề tồn tại vì bạn không cần khoảng trắng giữa các thành phần từ vựng của INTEGER_PAIR (hoặc FLOAT_PAIR).

Bạn hầu như không bao giờ cố gắng xử lý các cặp như thế này trong lexer. Thay vào đó, bạn nên xử lý các số đơn giản (INTEGERFLOAT) làm mã thông báo và xử lý những thứ như phủ định và ghép nối trong trình phân tích cú pháp, trong đó khoảng trắng đã được xử lý và loại bỏ.

(Ví dụ: bạn sẽ xử lý "----42" như thế nào?Đây là một biểu thức hợp lệ trong hầu hết các ngôn ngữ lập trình, mà sẽ tính toán chính xác nhiều từ khóa, nhưng sẽ không được xử lý bởi lexer của bạn.)

Ngoài ra, lưu ý rằng các số nguyên đơn trong lexer của bạn sẽ không được kết hợp là INTEGER, chúng sẽ xuất hiện dưới dạng DIGIT. Tôi không biết cú pháp chính xác cho JavaCC để sửa lỗi đó cho bạn. Những gì bạn muốn là để xác định DIGIT không phải là một mã thông báo, nhưng chỉ đơn giản là một cái gì đó bạn có thể sử dụng trong các định nghĩa của các thẻ khác; cách khác, nhúng định nghĩa của DIGIT ([0-9]) trực tiếp vào bất cứ nơi nào bạn đang sử dụng DIGIT trong các quy tắc của bạn.

0

Tôi chưa sử dụng JavaCC, nhưng có thể là NUMBER_PAIR không rõ ràng.

Tôi nghĩ rằng vấn đề đi kèm với thực tế là cùng một điều chính xác có thể được kết hợp với cả FLOAT_PAIR và INTEGER_PAIR vì FLOAT có thể khớp với INTEGER.

Nhưng đây chỉ là một dự đoán có bao giờ nhìn thấy cú pháp javacc :)

+0

Tôi không chắc chắn về điều đó, tôi đã thay đổi Float để nó không thể khớp với Integer - {)? "." | ()? "." | ()? "." >} và vẫn nhận được cảnh báo. Tôi ngạc nhiên bởi điều đó, gây ra những gì bạn nói dường như hoàn toàn hợp lý :) – Grundlefleck

+0

Hmm ... Tôi vẫn nghĩ rằng đó là mơ hồ liên quan nhưng trung thực, kể từ khi tôi đã không thử JavaCC tôi không sử dụng thực sự cho bạn ở đây ... Tôi sẽ trì hoãn và hy vọng ai đó biết nó sẽ trả lời. – Uri

0

Nó có thể có nghĩa rằng cứ mỗi FLOAT_PAIR bạn sẽ chỉ nhận được một mã thông báo FLOAT_PAIR, không bao giờ một mã thông báo NUMBER_PAIR. Quy tắc FLOAT_PAIR đã khớp với tất cả đầu vào và JavaCC sẽ không cố gắng tìm các quy tắc phù hợp hơn nữa. Đó sẽ là cách giải thích của tôi, nhưng tôi không biết JavaCC, vì vậy hãy dùng nó với một hạt muối.

Có thể bạn có thể chỉ định bằng cách nào đó rằng NUMBER_PAIR là sản phẩm chính và bạn không muốn nhận bất kỳ mã thông báo nào khác làm kết quả.

0

Nhờ câu trả lời Barry Kelly, giải pháp tôi đã đưa ra là:

SKIP : { < #TO_SKIP : " " | "\t" > } 
    TOKEN : { < #DIGIT : (["0"-"9"]) > } 
    TOKEN : { < #DIGITS : (<DIGIT>)+ > } 
    TOKEN : { < INTEGER : <DIGITS> > } 
    TOKEN : { < INTEGER_PAIR : (<INTEGER>) (<TO_SKIP>)+ (<INTEGER>) > } 
    TOKEN : { < FLOAT : (<NEGATE>)?<DIGITS>"."<DIGITS> | (<NEGATE>)?"."<DIGITS> > } 
    TOKEN : { < FLOAT_PAIR : (<FLOAT>) (<TO_SKIP>)+ (<FLOAT>) > } 
    TOKEN : { < #NUMBER : <FLOAT> | <INTEGER> > } 
    TOKEN : { < NUMBER_PAIR : (<NUMBER>) (<TO_SKIP>)+ (<NUMBER>) >} 
    TOKEN : { < NEGATE : "-" > } 

tôi đã hoàn toàn quên bao gồm các không gian được sử dụng để tách hai thẻ, tôi cũng đã sử dụng Biểu tượng '#' dừng mã thông báo được khớp, và chỉ được sử dụng trong định nghĩa của các mã thông báo khác. Ở trên được biên dịch bởi JavaCC mà không có cảnh báo hoặc lỗi.

Tuy nhiên, theo ghi nhận của Barry, có nhiều lý do để thực hiện việc này.

Các vấn đề liên quan