在野牛中调用c函数

时间:2015-02-13 02:01:29

标签: c bison

我正在尝试一个来自.y文件

的C文件中的函数

lex文件看起来像这样

%{


#include "Expression.h"
#include "Parser.h"

#include <stdio.h>

%}

%option outfile="Lexer.c" header-file="Lexer.h"
%option warn nodefault

%option reentrant noyywrap never-interactive nounistd
%option bison-bridge

LPAREN      "("
RPAREN      ")"
PLUS        "+"
MULTIPLY    "*"


ALPHABET    [a-z]+
NUMBER      [0-9]+
WS          [ \r\n\t]*

%%
 /* Rules */
{WS}            { /* Skip blanks. */ }
{NUMBER}        { sscanf_s(yytext, "%d", &yylval->value); return TOKEN_NUMBER; }
{ALPHABET}      { sscanf_s(yytext, "%c", &yylval->value);printf("%s",yytext); return TOKEN_ALPHABET;}
{MULTIPLY}      { return TOKEN_MULTIPLY; }
{PLUS}          { return TOKEN_PLUS; }
{LPAREN}        { return TOKEN_LPAREN; }
{RPAREN}        { return TOKEN_RPAREN; }
.               {  }

%%

int yyerror(const char *msg) {
    fprintf(stderr,"Error:%s\n",msg);
    return 0;
}

yacc文件是

%{

/*
 * Parser.y file
 * To generate the parser run: "bison Parser.y"
 */

#include "Expression.h"
#include "Parser.h"
#include "Lexer.h"

int yyerror(SExpression **expression, yyscan_t scanner, const char *msg);

%}

%code requires {

#ifndef YY_TYPEDEF_YY_SCANNER_T
#define YY_TYPEDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif

}

%output  "Parser.c"
%defines "Parser.h"

%define api.pure
%lex-param   { yyscan_t scanner }
%parse-param { SExpression **expression }
%parse-param { yyscan_t scanner }
%parse-param { char **str}
%union {

    int value;
    SExpression *expression;
}

%left '+' TOKEN_PLUS
%left '*' TOKEN_MULTIPLY

%token <value> TOKEN_ALPHABET
%token TOKEN_LPAREN
%token TOKEN_RPAREN
%token TOKEN_PLUS
%token TOKEN_MULTIPLY
%token <value> TOKEN_NUMBER

%type <expression> expr
%type <expression> l
%%
letters: l {}
    l: TOKEN_ALPHABET {printf("alphabet",$1); $$ = createAlphabet( $1);}
    ;

input
    : letters { printf("alphabet"); }
    ;

expr
    : expr TOKEN_PLUS expr { $$ = createOperation( ePLUS, $1, $3 ); }
    | expr TOKEN_MULTIPLY expr { $$ = createOperation( eMULTIPLY, $1, $3 ); }
    | TOKEN_LPAREN expr TOKEN_RPAREN { $$ = $2; }
    | TOKEN_NUMBER { $$ = createNumber($1); }
    ;


%%

我试图调用的函数在expression.h中声明并包含在yacc文件中。 功能是

char **createAlphabet(char str[])
{
    char b[100];
    b[0] = str[0];

    if (b == NULL)
        return NULL;

    //b->left = left;

    return &b;

}

但是当我在这个函数中放置一个断点时,正式的参数不会有正确的值。它说错误读取字符串的字符。

有谁可以告诉我可能出现的问题?我很确定有很多错误,我想它有点模糊,但我想知道从.y文件中调用c文件中的函数的正确方法

谢谢!

2 个答案:

答案 0 :(得分:0)

首先,您必须使用正确的参数类型调用它。我确定你忽略了编译器警告。

您已将TOKEN_ALPHABET声明为类型为value的类型标记int,并且您的扫描程序代码会尝试填写value yylval成员1}}与单个字符结合。 (虽然你几乎以最复杂的方式做到这一点。yylval->value = yytext[0]可以正常工作,而你的方式也不正确,因为sscanf期望char*而不是{{} 1}}。你的编译器也应该警告过你。)

但是,在您的野兔行动中,您可以拨打int*,其中createAlphabet($1)$1令牌(因此TOKEN_ALPHABET},但是int是声明接收createAlphabet参数。在C中,用作形式参数的数组会衰减为指针,因此您有效地声明char[]获取指向字符串(createAlphabet)的指针并为其赋予整数。将一个小整数作为指针处理是官方未定义的行为,但我可以告诉你事情将如何表现:你的程序会因为段错误而死亡。 (通常的UB免责声明适用。)

即使没有发生这种情况,你也会立即返回一个局部变量的地址,这是一个悬空指针;任何使用char*的返回值的尝试也都是未定义的行为,但其后果更不可预测,因而更危险。

顺便说一句,createAlphabet不可能是b。如果您的编译器没有警告您,那是因为您没有使用正确的编译器标志进行编译;你应该始终启用所有警告,并注意它们。

除了所有这些之外,你试图从你的野牛生成的解析器调用C函数是没有错的。问题实际上几乎都与C编程有关。

答案 1 :(得分:0)

使用%c和sscanf,它会期望一个char参数,而不是一个int。所以我希望它能在第一个字节写一个字符,而其他3个字节将是未初始化的。

为什么不在你的%union中添加一个char缓冲区,而是用sscanf代替%s?

你将createAlphabet的参数声明为char []而不是char,这也有点奇怪。