当前位置: 首页 > news >正文

同信.长春网站建设南宁市网站维护与推广公司

同信.长春网站建设,南宁市网站维护与推广公司,建程网怎么样,wordpress加中文字体总结 无意发现一个非常有意思的简单语法解析器#xff0c;不依赖lex/yacc#xff0c;本文对其中比较难理解的表达式解析#xff08;带优先级#xff09;部分做一些分析和记录。 #xff08;理解本文需要调试后面的代码部分#xff0c;have fun#xff01;#xff09;…总结 无意发现一个非常有意思的简单语法解析器不依赖lex/yacc本文对其中比较难理解的表达式解析带优先级部分做一些分析和记录。 理解本文需要调试后面的代码部分have fun 理解表达式解析部分 这段代码的功能是解析ab(cd)*e*fg;包含符号优先级处理的功能。 static ExprAST *ParseBinOpRHS(int ExprPrec, ExprAST *LHS) {// If this is a binop, find its precedence.while (1) {int TokPrec GetTokPrecedence();// If this is a binop that binds at least as tightly as the current binop,// consume it, otherwise we are done.if (TokPrec ExprPrec)return LHS;// Okay, we know this is a binop.int BinOp CurTok;getNextToken(); // eat binop// Parse the primary expression after the binary operator.ExprAST *RHS ParsePrimary();if (!RHS) return 0;// If BinOp binds less tightly with RHS than the operator after RHS, let// the pending operator take RHS as its LHS.int NextPrec GetTokPrecedence();if (TokPrec NextPrec) {RHS ParseBinOpRHS(TokPrec1, RHS);if (RHS 0) return 0;}// Merge LHS/RHS.LHS new BinaryExprAST(BinOp, LHS, RHS);} }解析流程 解析ab(cd)*e*fg;进入函数时ExprPrec为0LHS是a。第一轮解析b TokPrec ExprPrec 即 20 0不退出递归TokPrec NextPrec 即 20 20不进入递归符号、RHSb被合入LHSaLHS变为ab 第二轮解析(cd) TokPrec ExprPrec 即 20 0不退出递归TokPrec NextPrec 即 20 40进入递归当前RHS(cd)、符号为 递归ParseBinOpRHS第一轮当前LHS被设为外面的RHS(cd)也就是(cd)被当做后面乘号的左值了。 解析*e进入后ExprPrec21因为加1后面在遇到可以退出递归后面在遇到比加号高的不会退出递归很巧妙的做法TokPrec ExprPrec 即 40 21不进入TokPrec NextPrec 即 40 40不退出递归符号*、RHSe被合入LHS(cd)LHS变为(cd)*e 递归ParseBinOpRHS第二轮当前LHS变为(cd)*e、符号为* TokPrec ExprPrec 即 40 21不退出递归TokPrec NextPrec即 40 20不进入递归符号*、RHSf被合入LHS(cd)*eLHS变为(cd)*e*f 递归ParseBinOpRHS第三轮当前LHS变为(cd)*e*f、符号为 TokPrec ExprPrec 即 20 21退出递归非常重要返回(cd)*e*f 外层还在处理第二个加号通过递归得到RHS(cd)*e*f合并、LHSab、RHS(cd)*e*f得到ab(cd)*e*f 第三轮解析g TokPrec ExprPrec 即 20 0不退出递归TokPrec NextPrec 即 20 20不进入递归符号、RHSg被合入LHSab(cd)*e*fLHS变为ab(cd)*e*fg 解析流程总结 ab(cd)*e*fg;的解析过程分了三部分循环一次解析一组一组的定义是【符号数字】或【符号(表达式)】也就是{b}、{(cd)}、{*e}、{*f}、{g}解析每一组的时候都是不断把rhs拼入lhs的过程rhs到底是什么需要判断是否递归解析比如前面是b(cd)*e在解析第二个加号的时候rhs就不能是(cd)了需要递归的把后面乘号也解了rhs应该是(cd)*e*f。 三步解析 外侧函数解析a解析b递归解析(cd)ef解析g 整个解析流程就是不断把RHS拼到LHS中最终返回LHS的过程。 中间比较重要的就是乘号和号的优先级问题上述代码中进入递归的含义为把优先级高于当前符号的所有后续表达式一块解析出来直到遇到当前符号为止那么这里就涉及递归进入条件和递归退出条件了 递归进入条件遇到的符号优先级比上一个符号高if (TokPrec NextPrec)递归退出条件遇到的符号优先级和上一个符号相同if (TokPrec ExprPrec) 假设当前符号为遇到*后TokPrec20、NextPrec40会进入递归。 假设当前符号为*遇到后TokPrec20、ExprPrec21会退出递归而遇到*的话ExprPrec40无法退出递归代码比较巧妙不容易理解。 语法解析器 gcc或clang编译均可下面makefile是clang的。 main.c #include cstdio #include cstdlib #include string #include map #include vector /** def foo(x y) xfoo(y, 4.0);* * def foo(x y) xy y;* * def foo(x y) xy );* * extern sin(a);** def foo(x y) ab(cd)*e*fg;*///----------------------------------------------------------------------// // Lexer //----------------------------------------------------------------------//// The lexer returns tokens [0-255] if it is an unknown character, otherwise one // of these for known things. enum Token {tok_eof -1,// commandstok_def -2, tok_extern -3,// primarytok_identifier -4, tok_number -5 };static std::string IdentifierStr; // Filled in if tok_identifier static double NumVal; // Filled in if tok_number/// gettok - Return the next token from standard input. static int gettok() {static int LastChar ;// Skip any whitespace.while (isspace(LastChar))LastChar getchar();if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]*IdentifierStr LastChar;while (isalnum((LastChar getchar())))IdentifierStr LastChar;if (IdentifierStr def) return tok_def;if (IdentifierStr extern) return tok_extern;return tok_identifier;}if (isdigit(LastChar) || LastChar .) { // Number: [0-9.]std::string NumStr;do {NumStr LastChar;LastChar getchar();} while (isdigit(LastChar) || LastChar .);NumVal strtod(NumStr.c_str(), 0);return tok_number;}if (LastChar #) {// Comment until end of line.do LastChar getchar();while (LastChar ! EOF LastChar ! \n LastChar ! \r);if (LastChar ! EOF)return gettok();}// Check for end of file. Dont eat the EOF.if (LastChar EOF)return tok_eof;// Otherwise, just return the character as its ascii value.int ThisChar LastChar;LastChar getchar();return ThisChar; }//----------------------------------------------------------------------// // Abstract Syntax Tree (aka Parse Tree) //----------------------------------------------------------------------///// ExprAST - Base class for all expression nodes. class ExprAST { public:virtual ~ExprAST() {} };/// NumberExprAST - Expression class for numeric literals like 1.0. class NumberExprAST : public ExprAST {double Val; public:NumberExprAST(double val) : Val(val) {} };/// VariableExprAST - Expression class for referencing a variable, like a. class VariableExprAST : public ExprAST {std::string Name; public:VariableExprAST(const std::string name) : Name(name) {} };/// BinaryExprAST - Expression class for a binary operator. class BinaryExprAST : public ExprAST {char Op;ExprAST *LHS, *RHS; public:BinaryExprAST(char op, ExprAST *lhs, ExprAST *rhs): Op(op), LHS(lhs), RHS(rhs) {} };/// CallExprAST - Expression class for function calls. class CallExprAST : public ExprAST {std::string Callee;std::vectorExprAST* Args; public:CallExprAST(const std::string callee, std::vectorExprAST* args): Callee(callee), Args(args) {} };/// PrototypeAST - This class represents the prototype for a function, /// which captures its name, and its argument names (thus implicitly the number /// of arguments the function takes). class PrototypeAST {std::string Name;std::vectorstd::string Args; public:PrototypeAST(const std::string name, const std::vectorstd::string args): Name(name), Args(args) {}};/// FunctionAST - This class represents a function definition itself. class FunctionAST {PrototypeAST *Proto;ExprAST *Body; public:FunctionAST(PrototypeAST *proto, ExprAST *body): Proto(proto), Body(body) {}};//----------------------------------------------------------------------// // Parser //----------------------------------------------------------------------///// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current /// token the parser is looking at. getNextToken reads another token from the /// lexer and updates CurTok with its results. static int CurTok; static int getNextToken() {return CurTok gettok(); }/// BinopPrecedence - This holds the precedence for each binary operator that is /// defined. static std::mapchar, int BinopPrecedence;/// GetTokPrecedence - Get the precedence of the pending binary operator token. static int GetTokPrecedence() {if (!isascii(CurTok))return -1;// Make sure its a declared binop.int TokPrec BinopPrecedence[CurTok];if (TokPrec 0) return -1;return TokPrec; }/// Error* - These are little helper functions for error handling. ExprAST *Error(const char *Str) { fprintf(stderr, Error: %s\n, Str);return 0;} PrototypeAST *ErrorP(const char *Str) { Error(Str); return 0; } FunctionAST *ErrorF(const char *Str) { Error(Str); return 0; }static ExprAST *ParseExpression();/// identifierexpr /// :: identifier /// :: identifier ( expression* ) static ExprAST *ParseIdentifierExpr() {std::string IdName IdentifierStr;getNextToken(); // eat identifier.if (CurTok ! () // Simple variable ref.return new VariableExprAST(IdName);// Call.getNextToken(); // eat (std::vectorExprAST* Args;if (CurTok ! )) {while (1) {ExprAST *Arg ParseExpression();if (!Arg) return 0;Args.push_back(Arg);if (CurTok )) break;if (CurTok ! ,)return Error(Expected ) or , in argument list);getNextToken();}}// Eat the ).getNextToken();return new CallExprAST(IdName, Args); }/// numberexpr :: number static ExprAST *ParseNumberExpr() {ExprAST *Result new NumberExprAST(NumVal);getNextToken(); // consume the numberreturn Result; }/// parenexpr :: ( expression ) static ExprAST *ParseParenExpr() {getNextToken(); // eat (.ExprAST *V ParseExpression();if (!V) return 0;if (CurTok ! ))return Error(expected ));getNextToken(); // eat ).return V; }/// primary /// :: identifierexpr /// :: numberexpr /// :: parenexpr static ExprAST *ParsePrimary() {switch (CurTok) {default: return Error(unknown token when expecting an expression);case tok_identifier: return ParseIdentifierExpr();case tok_number: return ParseNumberExpr();case (: return ParseParenExpr();} }/// binoprhs /// :: ( primary)* // 函数ParseBinOpRHS用于解析有序对列表其中RHS是Right Hand Side的缩写表示“右侧”与此相对应LHS表示“左侧”——译者注。 // 它的参数包括一个整数和一个指针其中整数代表运算符优先级指针则指向当前已解析出来的那部分表达式。注意单独一个“x”也是合法的表达式 // 也就是说binoprhs有可能为空碰到这种情况时函数将直接返回作为参数传入的表达式。在上面的例子中传入ParseBinOpRHS的表达式是“a”当前语元是“”。 // 传入ParseBinOpRHS的优先级表示的是该函数所能处理的最低运算符优先级。假设语元流中的下一对是“[, x]”且传入ParseBinOpRHS的优先级是40 // 那么该函数将直接返回因为“”的优先级是20。搞清楚这一点之后我们再来看ParseBinOpRHS的定义函数的开头是这样的// ab(cd)*e*fg // a [, b]、[, (cd)]、[*, e]、[*, f]和[, g] static ExprAST *ParseBinOpRHS(int ExprPrec, ExprAST *LHS) {// If this is a binop, find its precedence.while (1) {int TokPrec GetTokPrecedence();// If this is a binop that binds at least as tightly as the current binop,// consume it, otherwise we are done.if (TokPrec ExprPrec)return LHS;// Okay, we know this is a binop.int BinOp CurTok;getNextToken(); // eat binop// Parse the primary expression after the binary operator.ExprAST *RHS ParsePrimary();if (!RHS) return 0;// If BinOp binds less tightly with RHS than the operator after RHS, let// the pending operator take RHS as its LHS.int NextPrec GetTokPrecedence();if (TokPrec NextPrec) {RHS ParseBinOpRHS(TokPrec1, RHS);if (RHS 0) return 0;}// Merge LHS/RHS.LHS new BinaryExprAST(BinOp, LHS, RHS);} }/// expression /// :: primary binoprhs /// // def foo(x y) xy y; // 这里开始解析xy部分 static ExprAST *ParseExpression() {ExprAST *LHS ParsePrimary();if (!LHS) return 0;return ParseBinOpRHS(0, LHS); }/// prototype /// :: id ( id* ) static PrototypeAST *ParsePrototype() {if (CurTok ! tok_identifier)return ErrorP(Expected function name in prototype);std::string FnName IdentifierStr;getNextToken();if (CurTok ! ()return ErrorP(Expected ( in prototype);std::vectorstd::string ArgNames;while (getNextToken() tok_identifier)ArgNames.push_back(IdentifierStr);if (CurTok ! ))return ErrorP(Expected ) in prototype);// success.getNextToken(); // eat ).return new PrototypeAST(FnName, ArgNames); }/// definition :: def prototype expression static FunctionAST *ParseDefinition() {getNextToken(); // eat def.PrototypeAST *Proto ParsePrototype();if (Proto 0) return 0;if (ExprAST *E ParseExpression())return new FunctionAST(Proto, E);return 0; }/// toplevelexpr :: expression static FunctionAST *ParseTopLevelExpr() {if (ExprAST *E ParseExpression()) {// Make an anonymous proto.PrototypeAST *Proto new PrototypeAST(, std::vectorstd::string());return new FunctionAST(Proto, E);}return 0; }/// external :: extern prototype static PrototypeAST *ParseExtern() {getNextToken(); // eat extern.return ParsePrototype(); }//----------------------------------------------------------------------// // Top-Level parsing //----------------------------------------------------------------------//static void HandleDefinition() {if (ParseDefinition()) {fprintf(stderr, Parsed a function definition.\n);} else {// Skip token for error recovery.getNextToken();} }static void HandleExtern() {if (ParseExtern()) {fprintf(stderr, Parsed an extern\n);} else {// Skip token for error recovery.getNextToken();} }static void HandleTopLevelExpression() {// Evaluate a top-level expression into an anonymous function.if (ParseTopLevelExpr()) {fprintf(stderr, Parsed a top-level expr\n);} else {// Skip token for error recovery.getNextToken();} }/// top :: definition | external | expression | ; static void MainLoop() {while (1) {fprintf(stderr, ready );switch (CurTok) {case tok_eof: return;case ;: getNextToken(); break; // ignore top-level semicolons.case tok_def: HandleDefinition(); break;case tok_extern: HandleExtern(); break;default: HandleTopLevelExpression(); break;}} }//----------------------------------------------------------------------// // Main driver code. //----------------------------------------------------------------------//int main() {// Install standard binary operators.// 1 is lowest precedence.BinopPrecedence[] 10;BinopPrecedence[] 20;BinopPrecedence[-] 20;BinopPrecedence[*] 40; // highest.// Prime the first token.fprintf(stderr, ready );getNextToken();// Run the main interpreter loop now.MainLoop();return 0; }Makefile CC llvm-g -stdliblibc -stdc14 CFLAGS -g -O0 -I llvm/include -I llvm/build/include -I ./ LLVMFLAGS llvm-config --cxxflags --ldflags --system-libs --libs all.PHONY: mainmain: main.cpp${CC} ${CFLAGS} ${LLVMFLAGS} $ -o $clean:rm -r main main.o%.o: %.cpp${CC} ${CFLAGS} ${LLVMFLAGS} -c $ -o $
http://www.pierceye.com/news/171801/

相关文章:

  • 网站怎么做用qq登录接入网络舆情监测分析系统
  • 怎么把几个网站做互通wordpress 英文站
  • 建设高端网站需要多少钱wordpress检测
  • 如何学习网站建设app嘉兴建站软件
  • 驻马店市建设工程网站平面设计培训班学费一般多少百度贴吧
  • 长沙网络建设的网站免费的个人简历模板word下载
  • 网站维护简单吗wordpress绿色两栏响应式主题
  • 二手站网站怎做福州网站建设的公司哪家好
  • dw如何做网站后台佛山行业网站建设
  • 如何做网站轮播大图简单网页制作成品代码
  • 网站怎么做uc整合查企业网站
  • 网站没被收录什么原因网站排名点击工具
  • 江西南昌建设厅网站商品展示软件
  • 眼镜企业网站建设方案2015做那些网站致富
  • 创建个人网站的流程建设网站聊天室
  • cms 学校网站上海模板网站
  • 网站建设投资风险分析公司做的网站费用如何做账
  • 网站建设费用核算科目DW做的网页用网站打不开
  • wordpress标签搜索引擎嘉兴市做网站优化
  • 网站更换关键词怎么做好wordpress post fonts
  • 厦门优化网站排名网站备案转服务器
  • 怎样做pdf电子书下载网站做旅行攻略的网站
  • 怎样做网站推广啊抖音网站的flash怎么做
  • 网站建设小说网站建设目标是什么意思
  • 如何做一个好的网站中英文网站好处
  • wordpress站点版权设置晋中建设集团网站
  • 怎么夸一个网站做的好看烟台百度网站推广
  • 佛山市网站建设分站多少钱企业门户账号是什么
  • 大中型网站开发价格铜山区建设局局网站周保春
  • 为什么有人做商城优惠券网站卖科技风格设计网站