如何将yytext从lex文件传递给yacc?

时间:2010-12-22 21:53:39

标签: yacc bison lex

请问我面临一个简单的问题..这是问题, 在我的lex文件中,我有类似的东西:

char *ptr_String;

"name = "  { BEGIN sName; }

<sName>.+   {
          ptr_String = (char *)calloc(strlen(yytext)+1, sizeof(char));
              strcpy(ptr_String, yytext);
              yylval.sValue = ptr_String;
              return NAME;
    }

现在在我的Yacc文件中,我有类似的内容:

stmt_Name:
    NAME
    {
        /*Now here i need to get the matched string of <sName>.+ and measure it's length. */
        /*The aim is simply outputing the name to the screen and storing the length in a global variable.
    }
    ;

请提出任何建议? 非常感谢您的所有时间和帮助。

1 个答案:

答案 0 :(得分:5)

修订问题

Yacc堆栈上的值由YYSTYPE或%union控制。当类型信息简单时使用YYSTYPE;当它很复杂时使用%union

我的一个语法包含:

struct Token
{
    int      toktype;
    char    *start;
    char    *end;
};
typedef struct Token Token;

#define YYSTYPE Token

出于各种原因(不一定是好的),我的语法使用手工制作的词法分析器而不是Lex。

在语法规则中,您将示例中的NAME等项称为$1(其中实际数字取决于令牌在构成规则的令牌或终端列表中出现的位置)。

例如(相同的语法):

disconnect
    :   K_DISCONNECT K_CURRENT
        { conn->ctype = CONN_CURRENT; }
    |   K_DISCONNECT K_ALL
        { conn->ctype = CONN_ALL; }
    |   K_DISCONNECT K_DEFAULT
        { conn->ctype = CONN_DEFAULT; }
    |   K_DISCONNECT string
        { conn->ctype = CONN_STRING;
          set_connection(conn, $2.start, $2.end);
        }
    ;

load
    :   K_LOAD K_FROM opt_file_pipe string load_opt_list K_INSERT
        {
            set_string("load file", load->file, sizeof(load->file),
                       $4.start, $4.end);
            load->stmt = $6.start;
        }
    ;

我不知道看到手工制作的yylex()的轮廓是否有帮助;在语法中,它是与yyparse()在同一文件中的函数。

static const char *c_token;     /* Where to start next token search */

static int yylex(void)
{
    char        buffer[MAX_LEXTOKENLENGTH];
    const char *start;

    if (c_token == 0)
        abort();

    if (bare_filename_ok)
        start = scan_for_filename(c_token, &c_token);
    else
        start = sqltoken(c_token, &c_token);

    yylval.start = CONST_CAST(char *, start);
    yylval.end = CONST_CAST(char *, c_token);
    if (*start == '\0')
    {
        yylval.toktype = 0;
        return yylval.toktype;
    }
    set_token(buffer, sizeof(buffer), start, c_token);
#ifdef YYDEBUG
    if (YYDEBUGVAR > 1)
        printf("yylex(): token = %s\n", buffer);
#endif /* YYDEBUG */

    /* printf("yylex(): token = %s\n", buffer); */
    if (isalpha((unsigned char)buffer[0]) || buffer[0] == '_')
    {
        Keyword  kw;
        Keyword *p;
        kw.keyword = buffer;
        p = (Keyword *)bsearch(&kw, keylist, DIM(keylist), sizeof(Keyword),
                                kw_compare);    /*=C++=*/
        if (p == 0)
            yylval.toktype = S_IDENTIFIER;
        else
            yylval.toktype = p->token;
    }
    else if (buffer[0] == '\'')
    {
        yylval.toktype = S_SQSTRING;
    }
    else if (buffer[0] == '"')
    {
        yylval.toktype = S_DQSTRING;
    }
    else if (isdigit((unsigned char)buffer[0]))
    {
        yylval.toktype = S_NUMBER;
    }
    else if (buffer[0] == '.' && isdigit((unsigned char)buffer[1]))
    {
        yylval.toktype = S_NUMBER;
    }

......识别出各种单字符符号......

    else if (buffer[0] == ':')
    {
        assert(buffer[1] == '\0');
        yylval.toktype = C_COLON;
    }
    else
    {
        yylval.toktype = S_ERROR;
    }
    return yylval.toktype;
}

原始问题

变量通常是一个全局变量 - 您的Yacc代码使用两种可能的声明之一:

extern char *yytext;    /* Correct for Flex */
extern char yytext[];   /* Correct for traditional Lex */

其中哪些是正确的取决于您的Lex版本如何定义它。

如果您想添加一个长度(可能是yytextlen),那么您可以定义这样一个变量并从yylex()获得每次返回,以确保设置yytextlen。或者,您可以安排语法拨打wwlex(),而wwlex()只需拨打:

int wwlex(void)
{
    int rc = yylex();
    yytextlen = strlen(yytext);
    return rc;
}

或者您可以安排Lex使用重命名生成代码,并让Yacc继续调用yylex()并将上面的代码提供为yylex()并让它调用重命名的Lex函数。无论哪种方式都有效。