我最近一直在试验Jison,我想我会尝试创建一个能够(至少部分地)解析一些数学表达式的语法。
但是,现在我对如何创建一个允许7a
形式(例如)a
是先前定义的变量的乘法的规则感到困惑。我尝试在代码中使用adjmul
执行此操作,但除非7
和a
之间存在空格,否则解析器不起作用。简而言之,我如何创建一个规则/规则,如果它们在程序中相邻,则允许数字和变量之间的相乘?
由于我对Jison这样的解析器很新,我也想知道是否有办法简化我现有的规则。
代码:
/* description: Parses math files. */
/* lexical grammar */
%lex
%%
[\n;] {return 'NL';}
\s+ {/* skip whitespace */}
"=" {return '=';}
[0-9]+("."[0-9]+)?\b {return 'NUMBER';}
"*" {return '*';}
"/" {return '/';}
"-" {return '-';}
"+" {return '+';}
"^" {return '^';}
"(" {return '(';}
")" {return ')';}
[a-zA-Z]+ {return 'ID';}
"," {return ',';}
"|" {return '|';}
"!" {return '!';}
<<EOF>> {return 'EOF';}
/lex
/* operator associations and precedence */
%left '|'
%left ','
%left '+' '-'
%left '*' '/'
%left '^'
%left UMINUS
%left '!'
%start program
%% /* language grammar */
program
: statement 'NL' program
{$$ = "";}
| statement EOF
{$$ = "";}
;
statement
: e
{$$ = $1;}
| ID '=' e
{identifiers[$1] = $3;}
;
e
: block '+' block
{$$ = $1 + $3;}
| block '-' block
{$$ = $1 - $3;}
| block '*' block
{$$ = $1 * $3;}
| block '/' block
{$$ = $1 / $3;}
| block '^' block
{$$ = Math.pow($1, $3);}
| '-' block %prec UMINUS
{$$ = -$2;}
| block '!'
{$$ = util.factorial($1);}
| ID '(' csv ')'
{$$ = identifiers[$1].apply(null, $3);}
| ID '(' ')'
{$$ = identifiers[$1]();}
| ID
{$$ = identifiers[$1];}
| adjmul
| block
;
block
: term
| NUMBER
{$$ = Number(yytext);}
;
term
: '(' e ')'
{$$ = $2;}
;
adjmul
: block term
{$$ = $1 * $2;}
| block ID
{$$ = $1 * identifiers[$2];}
;
答案 0 :(得分:0)
数字的正则表达式不正确。最后它不应该有\ b。词法分析过程通常应该纯粹是将字符输入流标记为词汇组件,而不考虑这些标记是否出现在有效序列中。包含有效令牌序列的是语法规则的任务。在你的代码中,空格通常也会在词法分析阶段被丢弃,除非它有意义,在这种情况下你也要标记它。因此,流'123 foo'或'123foo'都会产生NUMBER后跟ID的标记序列,该空格与否,通常在表达式中无效。所以在你的情况下删除\ b可以解决问题,但是你的语法可能会允许'7a'(没有空格)和'7 a'有空格。如果你不想允许这个空间,我会想要引入一个由数字和单词组成的新词汇标记,然后你的语法会适当地处理。这使得空格的概念保持在你的语法之外。