在野牛中调用c函数
calling c function in 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",); $$ = createAlphabet( );}
;
input
: letters { printf("alphabet"); }
;
expr
: expr TOKEN_PLUS expr { $$ = createOperation( ePLUS, , ); }
| expr TOKEN_MULTIPLY expr { $$ = createOperation( eMULTIPLY, , ); }
| TOKEN_LPAREN expr TOKEN_RPAREN { $$ = ; }
| TOKEN_NUMBER { $$ = createNumber(); }
;
%%
我尝试调用的函数在 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 文件中的函数的正确方法
谢谢!
第一件事是你必须用正确的参数类型调用它。我确定您忽略了有关此的编译器警告。
您已声明 TOKEN_ALPHABET
具有 int
类型的类型标记 value
,并且您的扫描代码尝试填写 value
的成员yylval
与单个字符并集。 (虽然你以几乎可以想象的最复杂的方式做到这一点。yylval->value = yytext[0]
会工作得很好,但你这样做的方式是不正确的,因为 sscanf
期望 char*
而不是 int*
。你的编译器也应该警告过你。)
但是,在您的 bison 操作中,您随后调用 createAlphabet()
,其中 </code> 是一个 <code>TOKEN_ALPHABET
标记(因此是一个 int
),但是 createAlphabet
被声明为接收 char[]
参数。在 C 语言中,用作形式参数的数组会衰减为指针,因此您实际上是在声明 createAlphabet
以获取指向字符串 (char*
) 的指针并为其提供一个整数。将小整数视为指针是官方未定义的行为,但我可以告诉你事情将如何表现:你的程序将因段错误而死。 (通常的 UB 免责声明适用。)
即使那没有发生,您也会立即 return 局部变量的地址,这是一个悬空指针;任何使用 createAlphabet
的 return 值的尝试也是未定义的行为,但其后果更不可预测,因此更危险。
顺便说一句,b
不可能是NULL
。如果您的编译器没有警告您,那是因为您没有使用正确的编译器标志进行编译;您应该始终启用所有警告,并留意它们。
除此之外,您尝试从 bison 生成的解析器调用 C 函数的方式没有任何问题。这些问题几乎都是关于C编程的。
将 %c 与 sscanf 结合使用,它需要一个 char 参数,而不是 int。所以我希望它将一个字符写入第一个字节,而其他 3 个字节将未初始化。
为什么不向您的 %union 添加一个字符缓冲区,而是将 %s 与 sscanf 一起使用?
您将 createAlphabet 的参数声明为 char[] 而不是 char 也有点奇怪。
我正在尝试 .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",); $$ = createAlphabet( );}
;
input
: letters { printf("alphabet"); }
;
expr
: expr TOKEN_PLUS expr { $$ = createOperation( ePLUS, , ); }
| expr TOKEN_MULTIPLY expr { $$ = createOperation( eMULTIPLY, , ); }
| TOKEN_LPAREN expr TOKEN_RPAREN { $$ = ; }
| TOKEN_NUMBER { $$ = createNumber(); }
;
%%
我尝试调用的函数在 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 文件中的函数的正确方法谢谢!
第一件事是你必须用正确的参数类型调用它。我确定您忽略了有关此的编译器警告。
您已声明 TOKEN_ALPHABET
具有 int
类型的类型标记 value
,并且您的扫描代码尝试填写 value
的成员yylval
与单个字符并集。 (虽然你以几乎可以想象的最复杂的方式做到这一点。yylval->value = yytext[0]
会工作得很好,但你这样做的方式是不正确的,因为 sscanf
期望 char*
而不是 int*
。你的编译器也应该警告过你。)
但是,在您的 bison 操作中,您随后调用 createAlphabet()
,其中 </code> 是一个 <code>TOKEN_ALPHABET
标记(因此是一个 int
),但是 createAlphabet
被声明为接收 char[]
参数。在 C 语言中,用作形式参数的数组会衰减为指针,因此您实际上是在声明 createAlphabet
以获取指向字符串 (char*
) 的指针并为其提供一个整数。将小整数视为指针是官方未定义的行为,但我可以告诉你事情将如何表现:你的程序将因段错误而死。 (通常的 UB 免责声明适用。)
即使那没有发生,您也会立即 return 局部变量的地址,这是一个悬空指针;任何使用 createAlphabet
的 return 值的尝试也是未定义的行为,但其后果更不可预测,因此更危险。
顺便说一句,b
不可能是NULL
。如果您的编译器没有警告您,那是因为您没有使用正确的编译器标志进行编译;您应该始终启用所有警告,并留意它们。
除此之外,您尝试从 bison 生成的解析器调用 C 函数的方式没有任何问题。这些问题几乎都是关于C编程的。
将 %c 与 sscanf 结合使用,它需要一个 char 参数,而不是 int。所以我希望它将一个字符写入第一个字节,而其他 3 个字节将未初始化。
为什么不向您的 %union 添加一个字符缓冲区,而是将 %s 与 sscanf 一起使用?
您将 createAlphabet 的参数声明为 char[] 而不是 char 也有点奇怪。