Lex/Yacc 整体做的能把 code -> tokens -> syntax tree
Lex会生成一个叫做词法分析器的程序。这是一个函数,它带有一个字符流传入参数,词法分析器函数看到一组字符就会去匹配一个关键字(key),采取相应措施。
YACC可以解析输入流中的标识符(token),同时可以根据标识符运行程序,对标识符进行处理,返回结果。
恒温控制器程序:
建议先看完链接,了解程序流程。
工程目录:
app
Main.cc
build
test
test.hh
test.cc
input.hh
LibertyExprLex.ll
LibertyExprParse.ll
CMakeLists.txt
CmakeLists:
cmake_minimum_required (VERSION 3.9)
project(STA VERSION 2.3.2
LANGUAGES CXX
)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(STA_HOME ${PROJECT_SOURCE_DIR})
message(STATUS "STA version: ${PROJECT_VERSION}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE DEBUG)
endif()
find_package(FLEX)
find_package(BISON)
flex_target(LibertyExprLex ${STA_HOME}/test/LibertyExprLex.ll ${CMAKE_CURRENT_BINARY_DIR}/LibertyExprLex.cc
COMPILE_FLAGS --prefix=LibertyExprLex_)
bison_target(LibertyExprParser ${STA_HOME}/test/LibertyExprParse.yy ${CMAKE_CURRENT_BINARY_DIR}/LibertyExprParse.cc
COMPILE_FLAGS --name-prefix=LibertyExprParse_
)
add_flex_bison_dependency(LibertyExprLex LibertyExprParser)
add_library(OpenSTA
${STA_HOME}/test/test.cc
${FLEX_LibertyExprLex_OUTPUTS}
${BISON_LibertyExprParser_OUTPUTS}
)
target_include_directories(OpenSTA
PUBLIC
${STA_HOME}/test
PRIVATE
${STA_HOME}
)
target_compile_features(OpenSTA PUBLIC cxx_std_11)
add_executable(sta app/Main.cc)
target_link_libraries(sta
OpenSTA
)
add_custom_target(sta_tags etags -o TAGS
*/*.hh
WORKING_DIRECTORY ${STA_HOME}
)
LibertyExprLex.ll
%{
#include <stdio.h>
#include "LibertyExprParse.hh"
#include "input.hh"
extern Test* test;
%}
%option noyywrap
%%
[0-9]+ { test->print("num"); return NUMBER; }
heat { test->print("heat");return TOKHEAT;}
on|off { test->print("on|off");return STATE; }
target { test->print("target"); return TOKTARGET; }
temperature { test->print("temperature");return TOKTEMPERATURE;}
\n /* ignore end of line */;
[ \t]+ /* ignore whitespace */
%%
LibertyExprParse.yy
%{
#include <stdio.h>
#include <string.h>
#include "test.hh"
//在lex.yy.c里定义,会被yyparse()调用。在此声明消除编译和链接错误。
extern int yylex(void);
extern Test* test;
int LibertyExprLex_lex();
#define LibertyExprParse_lex LibertyExprLex_lex
void yyerror(const char *s)
{
printf("[error] %s\n", s);
}
%}
%token NUMBER TOKHEAT STATE TOKTARGET TOKTEMPERATURE
%%
commands: /* empty */
| commands command
;
command: heat_switch | target_set ;
heat_switch:
TOKHEAT STATE
{
test->printState();
};
target_set:
TOKTARGET TOKTEMPERATURE NUMBER
{
test->printSetTem($3);
};
%%
test.hh
#include<string>
class Test
{
public:
void printState();
void printSetTem(int t);
void print(const std::string& data);
};
test.cc
#include <stdio.h>
#include "test.hh"
Test *test;
void Test::printState()
{
printf("\tHeat turned on or off\n");
}
void Test::printSetTem(int t)
{
printf("\tTemperature set %d\n", t);
}
void Test::print(const std::string &data)
{
printf("\t%s\n", data.c_str());
}
input.hh
#include "test.hh"
#include "../build/LibertyExprParse.hh"
extern Test *test;
static void intput()
{
Test t;
test = &t;
LibertyExprParse_parse();
}
Main.cc
#include <stdio.h>
#include <string.h>
#include "input.hh"
int main()
{
intput();
return 0;
}
可输入指令:
heat on
heat off
target temperature 10
测试:
heat on //输入
heat //lex分词输出
on|off //lex分词输出
Heat turned on or off //yacc输出
heat off //输入
heat //lex分词输出
on|off //lex分词输出
Heat turned on or off //yacc输出
target temperature 10 //输入
target //lex分词输出
temperature //lex分词输出
num //lex分词输出
Temperature set 0 //yacc输出