我正在致力于将 Swift 与在 Xcode 16.1 项目中使用 lex 和 bison 生成的简单解析器集成。
下面是我当前的代码:
calc.l
%{
#include "calc.tab.h"
#include <stdlib.h>
%}
%%
[0-9]+ { yylval.num = atoi(yytext); return NUMBER; }
[ \t\n]+ ;
"+" return '+';
"-" return '-';
"*" return '*';
"/" return '/';
"(" return '(';
")" return ')';
. return yytext[0];
%%
calc.y
%{
#include <stdio.h>
#include <stdlib.h>
#include "calc.h"
void yyerror(const char *s);
int result;
%}
%union {
int num;
}
/* Define tokens with types */
%token <num> NUMBER
%left '+' '-'
%left '*' '/'
/* Use %type to declare the type of non-terminal symbols */
%type <num> expr
%%
expr:
expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr { $$ = $1 / $3; }
| '(' expr ')' { $$ = $2; }
| NUMBER { $$ = $1; }
;
%%
int main(void) {
return yyparse();
}
void yyerror(const char *s) {
fprintf(stderr, "Error: %s\n", s);
}
calc.h
#ifndef CALC_H
#define CALC_H
extern int yylex(void);
extern int yyparse(void);
void yyerror(const char *s);
int parseExpression(void);
#endif
calc.c
#include "calc.h"
#include <stdio.h>
int result;
int parseExpression(void) {
if (yyparse() == 0) {
return result;
} else {
return -1; // Error
}
}
void yyerror(const char *s) {
fprintf(stderr, "Error: %s\n", s);
}
桥接标头.h
#import "calc.h"
这是一个调用解析器的简单 SwiftUI 视图:
struct ContentView: View {
@State var result: Int32 = 0
var body: some View {
VStack {
Text("\(result)")
Button("Calculate") {
let expression = "3 + 5 * (10 - 4)"
result = evaluate(expression: expression)
print("Result: \(result)")
}
}
.padding()
}
func evaluate(expression: String) -> Int32 {
expression.withCString { cString in
freopen("/dev/stdin", "r", stdin)
fputs(cString, stdin)
}
return parseExpression()
}
}
我从终端手动运行这些命令:
flex -o lex.yy.c calc.l
bison -d calc.y -o calc.tab.c
当我在Xcode中编译项目时,遇到以下错误,但我无法解决:
Undefined symbols for architecture arm64:
"_yywrap", referenced from:
_yylex in lex.yy.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
有人可以提供一些指导或指出我正确的方向吗?
我的问题不是重复现有问题,只是添加选项:
%option noyywrap
按照建议并没有解决问题。事实上,由于重复的变量和函数定义,它引入了多个错误。
这是因为在 Xcode 项目中同时包含 .l (Flex) 和 .y (Bison) 文件会在幕后自动触发 Flex 和 Bison。
解决方案是更新分词器和解析器定义以避免引用不可用的 calc.tab.h。
以下是最终的工作文件:
calc.l
%option noyywrap
%{
#include <stdio.h>
#include <stdlib.h>
enum {
NUMBER = 258,
PLUS,
MINUS,
MULTIPLY,
DIVIDE,
LEFTPAR,
RIGHTPAR
};
union YYSTYPE {
int num;
};
extern union YYSTYPE yylval;
extern int expression_value;
extern void yyerror(const char *s);
%}
%%
[0-9]+ { yylval.num = atoi(yytext); return NUMBER; }
[ \t\n]+ ;
"+" return PLUS;
"-" return MINUS;
"*" return MULTIPLY;
"/" return DIVIDE;
"(" return LEFTPAR;
")" return RIGHTPAR;
. return yytext[0];
%%
calc.y
%{
#include <stdio.h>
#include <stdlib.h>
void yyerror(const char *s);
int yylex(void);
int expression_value;
%}
%union {
int num;
}
%token <num> NUMBER
%token PLUS
%token MINUS
%token MULTIPLY
%token DIVIDE
%token LEFTPAR
%token RIGHTPAR
%left PLUS MINUS
%left MULTIPLY DIVIDE
%type <num> expr
%%
input:
| expr { expression_value = $1; }
;
expr:
expr PLUS expr { $$ = $1 + $3; }
| expr MINUS expr { $$ = $1 - $3; }
| expr MULTIPLY expr { $$ = $1 * $3; }
| expr DIVIDE expr { $$ = $1 / $3; }
| LEFTPAR expr RIGHTPAR { $$ = $2; }
| NUMBER { $$ = $1; }
;
%%
void yyerror(const char *s) {
fprintf(stderr, "Error: %s\n", s);
}
calc.h
#ifndef CALC_H
#define CALC_H
int evaluate_expression(const char *expression, int *result);
#endif
calc.c
#include "calc.h"
#include <stdio.h>
extern int yyparse(void);
extern void yy_scan_string(const char *str);
extern void yylex_destroy(void);
extern int expression_value;
int evaluate_expression(const char *expression, int *result) {
yy_scan_string(expression);
// Parse and evaluate the expression
int status = yyparse();
yylex_destroy();
if (status == 0) {
*result = expression_value;
}
return status;
}
这是调用解析器的 Swift(UI) 代码:
struct ContentView: View {
@State var expression: String = ""
@State var result: Int32?
var body: some View {
VStack {
TextEditor(text: $expression)
if let result {
Text("\(result)")
}
Button("Calculate") {
result = evaluate(expression: expression)
}
}
.padding()
}
func evaluate(expression: String) -> Int32? {
var result: Int32 = 0
let status = expression.withCString { cString in
evaluate_expression(UnsafeMutablePointer(mutating: cString), &result)
}
if status != 0 {
// The parse returned an error
return nil
}
return result
}
}
请注意,调用evaluate_expression函数需要Swift-Bridging.h文件。