ANTLR Verilog @ ( * ) совпадение двух лексем


Я пытаюсь использовать ANTLR4 для разбора кода Verilog. Я использую грамматику Verilog, найденную здесь https://github.com/antlr/grammars-v4/blob/master/verilog/Verilog2001.g4

Пример кода

module blinker(
        input clk,
        input rst,
        output blink
    );

    reg [24:0] counter_d, counter_q;

    assign blink = counter_q[24];

    always @(*) begin
        counter_d = counter_q + 1'b1;
    end

    always @(posedge clk) begin
        if (rst) begin
            counter_q <= 25'b0;
        end else begin
            counter_q <= counter_d;
        end
    end

endmodule

Проблема заключается в линии

always @(*) begin

( * ) разбивается на лексемы ' (*' и ')'.

В строке 723 файла грамматики есть

event_control :
'@' event_identifier
| '@' '(' event_expression ')'
| '@' '*'
| '@' '(' '*' ')'
;

Который должен соответствовать строке @ ( * ), если бы не строка 1329

attribute_instance : '(*' attr_spec ( ',' attr_spec )* '*)' ;

Я новичок во всем этом. это, но я предполагаю, что маркер '(*' из этой строки соответствует (* в коде и все портит.

Прочитав немного из окончательной ссылки ANTLR 4, я подумал, что правило, впервые определенное, будет иметь приоритет. Однако, я думаю, что это делает жадный матч?

Есть идеи, как исправить грамматику?

2 2

2 ответа:

Я новичок во всем этом, но я предполагаю, что маркер '(*' из этой строки соответствует (* в коде и все портит.

Вы правы.

Прочитав немного из окончательной ссылки ANTLR 4, я подумал, что правило, впервые определенное, будет иметь приоритет. Однако, я думаю, что это делает жадный матч?

Несмотря на то, что они определены в правилах синтаксического анализа, литеральные токены на самом деле являются правилами лексера, которые имеют приоритет в том порядке, в котором они определены , только, если они совпадают с одинаковым количеством символов. Если правило лексера может соответствовать большему числу, оно так и делает (как вы заметили).

Я не знаю никакого Verilog, но быстрое решение для этого было бы позволить attribute_instance выглядеть так:

attribute_instance : '(' '*' attr_spec ( ',' attr_spec )* '*' ')' ;
Однако, если лексер отбрасывает символы, такие как пробелы, то вход "( *" (скобка, пробел, звезда) также будет соответствовать началу attribute_instance. Если это нежелательно, вы можете позволить своему event_control выглядеть так это:
event_control 
 : '@' event_identifier
 | '@' '(' event_expression ')'
 | '@' '*'
 | '@' ( '(' '*' | '(*' ) ')'
 ;

Обратите внимание на ( '(' '*' | '(*' ) в последней альтернативе, которая соответствует двум одиночным токенам, '(' и '*' (с возможными пробелами между ними!), или единственный маркер '(*'.

Я просто подправил грамматику, как предложил Барт. Вроде бы разбираю. Я также удалил некоторые дополнительные фигурные скобки, которые вызывали предупреждения. пожалуйста, попробуйте потянуть вниз и сделать это снова. Ter