1

我正在尝试使用 flex/bison 为类似 verilog 的语言创建一个解析器(或者更具体地说是带有一些额外结构的 verilog,用于生成 verilog 代码),但我无法弄清楚如何构建我的 bison 规则来处理语言中可用的一般类型的构造。

这个结构的一个一般例子是这样的:

(
output wire          up_o,
input  wire [4:0]    up_i,
///////////////////////////////////////////////////////////
// A comment
///////////////////////////////////////////////////////////
`my_if (`$a eq `$b)
  input  wire        a_{n}_clk_i,
  output wire        a_{n}_rst_o,
`my_endif
output wire                                           out_o
);

原则上 themy_if可以嵌套,并且( );一切都可以在一个my_if块内,没有任何my_if. 这让我相信我目前的想法是有缺陷的,我根本不明白如何进行这种相互递归。

似乎引起我问题的是,,除了最后一行之外,它正在终止块中的每一行。我的词法分析器忽略注释并对行进行标记,我还my_if专门解析了行。

以下是我现在拥有的相关野牛规则,

portdecla:
'(' ports ')' ';'
;

ports:
port
| ports ',' port
| ports ',' ifs
| ifs
;

ifs:
ifhead ports TENDIF
| if
;

和解析ifhead和输入/输出行罚款。portmy_if

任何关于如何创建这些规则的想法将不胜感激

4

1 回答 1

3

我在理解你的问题时遇到了一些麻烦。如果您描述了问题,而不是仅仅含糊地断言它可能与逗号有关,那会容易得多。当然,它确实与逗号有关:您的语法坚持在 afterifs和 after中都有逗号port。(另外,要么你没有正确复制和粘贴,要么真的很奇怪ifs。)

实际上,您不需要ifs,但您需要区分if声明末尾的 an 和任何其他if

port_declaration: tail_ports;

ports:  port ','
     |  port ',' ports
     |  if
     |  if ports
     ;
tail_ports
     :  port
     |  tail_if
     |  port ',' tail_ports
     |  if tail_ports
     ;
if   :  IF '(' condition ')' ports END_IF
     ;
tail_if
     :  IF '(' condition ')' tail_ports END_IF
     ;

(我写的是右递归,因为它更容易理解,恕我直言,而且从右递归列表中构建 AST 也更容易。参见 Levine,第 66 页。在现代机器上,解析堆栈确实没有问题增长;默认的最大堆栈深度为 10,000;如果这还不够,您可以增加它。)

编辑:我想我终于得到了上面的权利。

这类问题通常通过两遍解析来解决;首先是预处理过程,其输出被馈送到真正的解析器中。标记化只进行一次;预处理解析器不区分语言标记;它只关心它自己的令牌。(C 预处理器可以将标记与##运算符融合,但它从不拆分标记;这通常被证明是一种合理的方法。)这可以用 bison 来实现,尽管让数据流正确有点挑战;我个人更喜欢lemon词法分析器将标记推送到解析器的方法,因为这更容易扩展。

但是,在您的特定情况下,您希望预处理器只接受完整的短语 ( port),因此正如您所说,挑战是,正确的,即使最后一个port被深埋在if结构中。因此,上述区分if和的方法tail_if

构建 AST 有多种方法,具体取决于您是否可以在解析时评估条件。如果可以,那么您可以将不需要的端口完全排除在外,这可能是最简单的解决方案。

如果您需要在应用条件之前进行整个解析,那么您仍然有几个选择:明显的一种选择是构建一个节点为portor的树conditional_list,或者您有效地构建操作向量的代码生成样式build-portjump-if-condition-false。这两个选项都需要某种形式的标记联合。

/Edit(以下仍然不正确。)

typedef struct PortList {
  Port* port;
  struct PortList* next;
} PortList;

typedef struct ConditionalPortList {
  Condition* cond;  /* Optional condition; if absent, unconditional */
  PortList*  ports;
} ConditionalPortList;

typedef struct PortDeclaration {
  ConditionalPortList* clause;
  struct PortDeclaration *next;
} PortDeclaration;

这很容易构建(它可能比这个片段更容易,我有点不习惯。)(警告:未尝试):

%union {
   PortList*            port_list;
   ConditionalPortList* conditional;
   PortDeclaration*     port_declaration;
   /* ... */
}
%type <port_list> ports
%type <conditional> if always
%type <port_declaration> port_tail port_declaration
/* ... */

%%

ports:  port             { $$ = NewPortList($1, NULL); }
     |  port ',' ports   { $$ = NewPortList($1, $3); }
     ;

if: IF '(' condition ')' ports ENDIF
                         { $$ = NewConditionalPortList($3, $5); }
  ;

always: ports            { $$ = NewConditionalPortList(NULL, $1); }
      ;

port_tail: if
         | if port_tail  { $$ = NewPortDeclaration($1, $2); }
         | if always port_tail
                         { $$ = NewPortDeclaration($1, NewPortDeclaration($2, $3); }
         ;

port_declaration:
           '(' always ')' ';'    { $$ = $2; }
         | '(' port_tail ')' ';' { $$ = $2; }
         | '(' always port_tail ')' ';'
                                 { $$ = NewPortDeclaration($2, $3); }
         ;
于 2012-11-12T16:09:01.083 回答