如何在没有解析器生成器的情况下在C或Objective-C中编写解析器?

我试图在C或Objective-C中创建一个接受字符串的计算器

8/2+4(3*9)^2 

并返回答案2920.我不想使用像Lex或Yacc这样的生成器,所以我想从头开始编写代码。 我该怎么做呢? 除了龙书,是否有任何推荐的文本涵盖这个主题?

Dave DeLong的DDMathParser课程可以为您节省大量时间和麻烦。

如果我没记错的话,你可以用两个堆栈解决这个问题,一个用于操作符,另一个用于操作数。

 // OPTR stack: store operators // OPND stack: store operands // OP: predefined set of operators OperandType EvaluateExpression(){ InitStack(OPET);Push(OPTR,'#'); initStack(OPND);c=getchar(); while(c!='#'||GetTop(OPTR)!='#'){ if(!In(c,OP)){Push((OPND,c);c=getchar();} //Push to stack if not operator else switch(Precede(GetTop(OPTR),c){ //Top element in stack has a lower priority case '<': Push(OPTR,c); c=getch(); break; case '=': Pop(OPTR,x); c=getch(); break; //Pop top element and push back the calculated result case '>': Pop(OPTR,theta); Pop(OPND,b); Pop(OPND,a); Push(OPND,Operate(a,theta,b)); break; } } return GetTop(OPND); } 

已经提到了调车场算法。 另一个经典之作是简单的递归下降。 这是我多年前写的一篇相当短的文章:

 #include  #include  #include  void expression(void); void show(int ch) { putchar(ch); putchar(' '); } int token() { int ch; while (isspace(ch=getchar())) ; return ch; } void factor() { int ch = token(); if (ch == '(') { expression(); ch = token(); if (ch != ')') { fprintf(stderr, "Syntax error. Expected close paren, found: %c\n", ch); exit(EXIT_FAILURE); } } else show(ch); } void term() { int ch; factor(); ch = token(); if (ch == '*' || ch == '/') { term(); show(ch); } else ungetc(ch, stdin); } void expression() { int ch; term(); ch = token(); if (ch == '-' || ch=='+') { expression(); show(ch); } else ungetc(ch, stdin); } int main(int argc, char **argv) { expression(); return 0; } 

请注意,这个特定的只是解析输入,并将其转换为RPN表单。 如果您想要解释结果,则需要替换打印出每个操作数/运算符,并实际评估表达式中该部分的结果。

我认为这接近你想要的: http : //www.codeproject.com/KB/recipes/alxparser.aspx

我在CSE340中做到了这一点:在我大学CS的大三学年编写Lanugages简介。 因此,如果您真的想从头开始编写解析器,请准备好它可能是“一个学期长的项目”。

您需要标记,解析,构建抽象表达式树,评估等。

我们使用了Louden的编程语言:原理和实践 。 我喜欢它。 虽然它没有尽力指导您完成实施过程。

当然,这不仅仅是“从头开始编码”。 你需要编写一个语法,然后构建一个解析器来处理规则……除了学习活动之外,我不确定你为什么要这样做。

使用Objective-C NSLinguisticTagger可能是一个很好的解决方案

 - (void)enumerateTagsInRange:(NSRange)range scheme:(NSString *)tagScheme options:(NSLinguisticTaggerOptions)opts usingBlock:(void (^)(NSString *tag, NSRange tokenRange, NSRange sentenceRange, BOOL *stop))block