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

时间:2011-05-02 03:01:04

标签: objective-c c parsing lexical-analysis

我正在尝试在C或Objective-C中创建一个接受

行的字符串的计算器
8/2+4(3*9)^2

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

7 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:2)

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

// 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);
   }

答案 2 :(得分:2)

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

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

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格式。如果你想要解释结果,你可以用实际评估表达式那部分的结果来替换每个操作数/运算符的打印。

答案 3 :(得分:1)

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

答案 4 :(得分:1)

答案 5 :(得分:0)

我在CSE340中做到了这一点:在我大学的CS大三学期编程Lanugages。因此,如果确实希望从头开始编写解析器代码,请准备好它可能是“一个学期长的项目”。

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

我们使用Louden's Programming Languages: Principles and Practice。我喜欢它。虽然它没有尽力指导您完成实施过程。

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

答案 6 :(得分:0)

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

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