简易计算器 (1) - 词法分析(不使用Lex)

使用手工的方式编写一个简易的计算器,首先手工实现词法的解析。
lex.h

#ifndef _LEX_H
#define _LEX_H

typedef enum {
    TOKEN_BAD,
    TOKEN_NUM,
    TOKEN_OP_ADD,
    TOKEN_OP_SUB,
    TOKEN_OP_MUL,
    TOKEN_OP_DIV,
    TOKEN_LINE_END,
} TokenKind;

#define MAX_TOKEN_SIZE  (100)

typedef struct {
    TokenKind kind;
    double value;
    char  str[MAX_TOKEN_SIZE];
} Token;

void SetLine(char *file);
void GetToken(Token *token);

#endif

lex.c


#include "lex.h"

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

static char *sLine;
static int sLinePos;

typedef enum {
    INIT_ST,
    INT_PART_ST,
    DOT_ST,
    FRAC_PART_ST,
} LexerStatus;

void GetToken(Token *token)
{
   int pos = 0;
   LexerStatus st = INIT_ST;
   char currChar;
   token->kind = TOKEN_BAD;
   while (sLine[sLinePos] != '\0') {
       currChar = sLine[sLinePos];
       // extract number
       if ((st == INT_PART_ST || st == FRAC_PART_ST)    
            && !isdigit(currChar) && currChar != '.') {
            token->kind = TOKEN_NUM;
            sscanf(token->str, "%lf", &token->value);
            return ;
       }
       // skip space
       if (isspace(currChar)) { 
           if (currChar == '\n') {
               token->kind = TOKEN_LINE_END;
               return ;
           }
           sLinePos++;
           continue;
       }
       if (sLinePos >= MAX_TOKEN_SIZE - 1) {
           fprintf(stderr, "token too long \n");
       }
       token->str[pos] = sLine[sLinePos];
       sLinePos++;
       pos++;
       token->str[pos] = '\0';

       if (currChar == '+')
       {
           token->kind = TOKEN_OP_ADD;
           return ;
       } else if (currChar == '-') {
           token->kind = TOKEN_OP_SUB;
           return ;
       } else if (currChar == '*') {
           token->kind = TOKEN_OP_MUL;
           return ;
       } else if (currChar == '/') {
           token->kind = TOKEN_OP_DIV;
           return ;
       } else if (isdigit(currChar)) {
           if (st == INIT_ST) {
               st = INT_PART_ST;
           } else if (st == DOT_ST) {
               st = FRAC_PART_ST;
           }
       } else if (currChar == '.') {
           if (st == INT_PART_ST) {
               st = DOT_ST;
           } else {
               fprintf(stderr, "syntax error. \n");
               exit(1);
           }
       } else {
           fprintf(stderr, "bad charactor(%c)\n", currChar);
           exit(1);
       }
   }
}

void SetLine(char *line)
{
    sLine = line;
    sLinePos = 0;
}


// test code 
void ParseLine(char *buf)
{
    Token token;
    SetLine(buf);
    while (1) {
        GetToken(&token);
        if (token.kind == TOKEN_LINE_END) {
            break;
        } else {
            printf("kind : %d -- %s \n", token.kind, token.str);
        }
    }
}

int main(int argc, char **argv)
{
    char buf[1024];
    while (fgets(buf, 1024, stdin) != NULL) {
        printf("Parse String: %s", buf);
        ParseLine(buf);
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值