Dan*_*cci 4 vhdl flex-lexer grammar-kit
在VHDL中,'字符可以用于封装字符标记ie '.',也可以用作属性分隔符(类似于CPP的:: token)ie string'("hello").
解析包含字符的属性名称时会出现此问题ie string'('a','b','c').在这种情况下,一个天真的词法分析器会错误地将第'('一个标记为一个字符,并且所有下面的实际字符都将被搞砸.
从2007年开始comp.lang.vhdl google group中有一个帖子,它提出了一个类似的问题,题为" Lexing the'char ",其中有一个用户diogratia的答案
Run Code Online (Sandbox Code Playgroud)case '\'': /* IR1045 check */ if ( last_token == DELIM_RIGHT_PAREN || last_token == DELIM_RIGHT_BRACKET || last_token == KEYWD_ALL || last_token == IDENTIFIER_TOKEN || last_token == STR_LIT_TOKEN || last_token == CHAR_LIT_TOKEN || ! (buff_ptr<BUFSIZ-2) ) token_flag = DELIM_APOSTROPHE; else if (is_graphic_char(NEXT_CHAR) && line_buff[buff_ptr+2] == '\'') { CHARACTER_LITERAL: buff_ptr+= 3; /* lead,trailing \' and char */ last_token = CHAR_LIT_TOKEN; token_strlen = 3; return (last_token); } else token_flag = DELIM_APOSTROPHE; break;见问题报告IR1045:http://www.eda-twiki.org/isac/IRs-VHDL-93/IR1045.txt
从上面的代码片段中可以看出,最后一个令牌可以被捕获并用于"消除"类似的东西:
Run Code Online (Sandbox Code Playgroud)foo <= std_logic_vector'('a','b','c');没有大的前瞻或回溯.
但是,据我所知,flex不会跟踪解析的最后一个令牌.
无需手动跟踪最后解析的令牌,有没有更好的方法来完成这个lexing任务?
如果有帮助,我正在使用IntelliJ GrammarKit.
IR1045背后的想法是能够判断单个引号/撇号是否是字符文字的一部分,如果没有向前看,或者在出错时回溯,请尝试:
library ieee;
use ieee.std_logic_1164.all;
entity foo is
port (
a: in std_logic;
b: out std_logic_vector (3 downto 0)
);
end entity;
architecture behave of foo is
begin
b <= std_logic_vector'('0','1','1','0') when a = '1' else
(others =>'0') when a = '0' else
(others => 'X');
end architecture behave;
Run Code Online (Sandbox Code Playgroud)
你愿意看多远?
然而,有一个关于VHDL的撇号和字符文字的弹性消歧的实际例子.
Nick Gasson的nvc使用flex,他在其中实施了问题报告1045解决方案.
请参阅GPLv3许可的nvc/src/lexer.l.
搜索last_token:
#define TOKEN(t) return (last_token = (t))
Run Code Online (Sandbox Code Playgroud)
和
#define TOKEN_LRM(t, lrm) \
if (standard() < lrm) { \
warn_at(&yylloc, "%s is a reserved word in VHDL-%s", \
yytext, standard_text(lrm)); \
return parse_id(yytext); \
} \
else \
return (last_token = (t));
Run Code Online (Sandbox Code Playgroud)
一个额外的功能来检查它:
static int resolve_ir1045(void);
static int last_token = -1;
Run Code Online (Sandbox Code Playgroud)
这是:
%%
static int resolve_ir1045(void)
{
// See here for discussion:
// http://www.eda-stds.org/isac/IRs-VHDL-93/IR1045.txt
// The set of tokens that may precede a character literal is
// disjoint from that which may precede a single tick token.
switch (last_token) {
case tRSQUARE:
case tRPAREN:
case tALL:
case tID:
// Cannot be a character literal
return 0;
default:
return 1;
}
}
Run Code Online (Sandbox Code Playgroud)
自comp.lang.vhdl发布以来,IR1045的位置发生了变化
您还需要在lexer.l中搜索resolve_ir1045.
static int resolve_ir1045(void);
Run Code Online (Sandbox Code Playgroud)
和
{CHAR} { if (resolve_ir1045()) {
yylval.s = strdup(yytext);
TOKEN(tID);
Run Code Online (Sandbox Code Playgroud)
我们发现nvc使用该函数来过滤检测字符文字的第一个单引号.
这最初是Ada问题.IR-1045从未被采用,但普遍使用.可能有Ada flex lexers也表现出消歧.
在2006年9月的Ada User Journal第27卷第3 期中,在PDF页面30和31(第27卷第159和160页)的文章词汇分析中讨论了消除歧义的要求,其中我们看到解决方案并不为人所知.
字符文字不在单引号之前的注释是不准确的:
entity ir1045 is
end entity;
architecture foo of ir1045 is
begin
THIS_PROCESS:
process
type twovalue is ('0', '1');
subtype string4 is string(1 to 4);
attribute a: string4;
attribute a of '1' : literal is "TRUE";
begin
assert THIS_PROCESS.'1''a /= "TRUE"
report "'1''a /= ""TRUE"" is FALSE";
report "This_PROCESS.'1''a'RIGHT = " &
integer'image(This_PROCESS.'1''a'RIGHT);
wait;
end process;
end architecture;
Run Code Online (Sandbox Code Playgroud)
首次使用具有选定名称前缀的属性,其后缀为字符文字,表明不准确,第二个报告语句显示它可能很重要:
Run Code Online (Sandbox Code Playgroud)ghdl -a ir1045.vhdl ghdl -e ir1045 ghdl -r ir1045 ir1045.vhdl:13:9:@0ms:(assertion error): '1''a /= "TRUE" is FALSE ir1045.vhdl:15:9:@0ms:(report note): This_PROCESS.'1''a'RIGHT = 4
除了包含带有字符文字后缀的选定名称的属性名称前缀之外,还要求属性规范在同一声明区域中"装饰"声明的实体(entity_class,参见IEEE Std 1076-2008 7.2属性规范)实体在中宣布.
此示例在语法和语义上是有效的VHDL.您可以注意到,nvc不允许使用实体类文字装饰命名实体.这不符合7.2.
枚举文字在类型声明中声明,此处类型为twovalue.枚举类型至少有一个字符文字作为枚举文字是字符类型(5.2.2.1).