有没有更好的方法在CFG规则中指定可选元素?

时间:2013-09-03 20:53:45

标签: grammar bison context-free-grammar

考虑为其设计和开发的语言和编译器。 在这种语言中,有一个特定的语句是语法的一部分:(=<identifier>)。编译器可以识别此部分。但是括号和等号以及标识符之间允许有空格。所以我有这些可能性:

(=<identifier>)
( = <identifier> )
(=identifier )
( =identifier )
...

不考虑整个语法而只考虑处理这种语言特性的规则,我有类似的东西(用于语法规则的类似Bison的语法):

statement: OBRCKT EQ ID CBRCKT
         | OBRCKT S EQ S ID S CBRCKT
         | OBRCKT S EQ ID S CBRCKT
         | OBRCKT S EQ S ID CBRCKT
         | OBRCKT S EQ ID CBRCKT
         | OBRCKT EQ S ID S CBRCKT
         | OBRCKT EQ ID S CBRCKT
         | OBRCKT EQ S ID CBRCKT
         | ...

空间终端S可以出现。但是规则的方式,我需要指定所有可能的组合......有没有更好的方法来实现这个结果?

1 个答案:

答案 0 :(得分:3)

正如Jim评论的那样,使用你的词汇工具来处理这些案例,而不是将它们写入你的语法产品中。

例如,我通常使用Flex进行词法分析,使用Bison来定义我的语法(可能就像你所做的那样)。

您可以使用以下内容获得您想要的结果(这只是一个示例,因此它非常简单且不能做太多):

lexicalAnalyzer.l

 /* lexicalAnalyzer.l
    Specifications of tokens for some language.
 */
%{

%}

/*
 *  Definitions of regular expressions
 *  Note: You capture whitespace here...
*/

WSPACE      [ \t\r]+ //We take care of the spaces here...

/*
 *  Tokens
*/
%%

"=" {
        printf("TOKEN: EQ   LEXEME: %s\n", yytext);             
        return T_EQ;
    }
"(" {
        printf("TOKEN: OBRCKT   LEXEME: %s\n", yytext);
        return T_OBRCKT;
    }
")" {
        printf("TOKEN: CBRCKT   LEXEME: %s\n", yytext);
        return T_CBRCKT;
    }
"<" {
        printf("TOKEN: LT   LEXEME: %s\n", yytext);
        return T_LT;
    }
">" {
        printf("TOKEN: GT   LEXEME: %s\n", yytext);
        return T_GT;
    }
"identifier"    {
                printf("TOKEN: IDENT   LEXEME: %s\n", yytext);
            return T_IDENT;
             }  
{WSPACE}    { }
.       {
                 printf("TOKEN: UNKNOWN   LEXEME: %s\n", yytext);
                 return T_UNKNOWN;
            }
%%

syntaxAnalyzer.y

/*
      syntaxAnalyzer.y

      To create syntax analyzer:
        flex file.l
        bison file.y
        g++ file.tab.c -o file_parser
        file_parser < inputFileName
 */

/*
 *  Declaration section.
 */

%{

    #include <stdio.h>
    void printRule(const char *lhs, const char *rhs);
    int yyerror(const char *s) {
        printf("Error!");
    }
    extern "C" {
        int yyparse(void);
        int yylex(void);
        int yywrap() {return 1;}
    }
%}

/*
 *  Token declarations
*/
%token  T_OBRCKT T_CBRCKT
%token  T_LT T_GT T_EQ   
%token  T_IDENT T_UNKNOWN

/*
 *  Starting point.
 */
%start  N_START

/*
 *  Translation rules.
 */
%%
N_START     : N_STATEMENT
            {
                printRule("START", "STATEMENT");
                printf("\n---- Completed parsing ----\n\n");
                return 0;
            }
            ;

N_STATEMENT : T_OBRCKT T_EQ T_LT T_IDENT T_GT T_CBRCKT
            {
            printRule("EXPR", "T_OBRCKT T_EQ T_LT T_IDENT T_GT T_CBRCKT");

            }
            ;
%%

#include "lex.yy.c"
extern FILE *yyin;

void printRule(const char *lhs, const char *rhs) {
  printf("%s -> %s\n", lhs, rhs);
  return;
}

int main() {
  do {
    yyparse();
  } while (!feof(yyin));
  return 0;
}