10calc

本文详细阐述了一个解析并计算复杂数学表达式的算法,包括符号运算、优先级处理和错误检查。通过使用栈数据结构来管理和计算操作符和数字,实现了对不同运算符的正确处理,并对括号进行有效解析,确保了表达式的准确计算。


calc/calc.h

#include "stack.h"

enum pre_flag {
    OPR,
    NUM,
};

typedef ssize_t num_t;

struct calc_info {
    const char *expr;
    char *cur;
    struct stack_info opr;
    struct stack_info num;
    enum pre_flag flag;
    num_t (*output)(struct calc_info *, const char *); 
};

void calc_init(struct calc_info *); 
void calc_destroy(struct calc_info *); 


calc/calc.c

#include <stdio.h>
#include <assert.h>
#include "calc.h"

#define DEBUG

#ifdef DEBUG
#define DEBUG_PRT(fmt, arg...) printf(fmt, arg)
#else
#define DEBUG_PRT(fmt, arg...)
#endif


#define PUSH_NUM(n) do {info->num.push(&info->num, &n, sizeof(num_t));} while (0)
#define POP_NUM(n) ({info->num.pop(&info->num, &n, sizeof(num_t));})
#define TOP_NUM(n) ({info->num.top(&info->num, &n, sizeof(num_t));})
#define ISEMPTY_NUM ({info->num.isempty(&info->num);})

#define PUSH_OPR(n) do {info->opr.push(&info->opr, &n, sizeof(char));} while (0)
#define POP_OPR(n) ({info->opr.pop(&info->opr, &n, sizeof(char));})
#define TOP_OPR(n) ({info->opr.top(&info->opr, &n, sizeof(char));})
#define ISEMPTY_OPR ({info->opr.isempty(&info->opr);})
static void num_handler(struct calc_info *info)
{
    num_t num = *info->cur - '0';
    num_t pre_num = 0;

    if (info->flag == NUM) {
        assert(!ISEMPTY_NUM);
        POP_NUM(pre_num);
        num += pre_num * 10;
    }
    PUSH_NUM(num);

    info->flag = NUM;
}
static int do_stack(struct calc_info *info)
{
    num_t a = 0;
    num_t b = 0;
    char opr = 0;
    num_t ret = 0;

    assert(!(ISEMPTY_NUM));
    POP_NUM(b);
    assert(!(ISEMPTY_NUM));
    POP_NUM(a);
    assert(!(ISEMPTY_OPR));
    POP_OPR(opr);

    switch (opr) {
        case '+':
            ret = a + b;
            break;
        case '-':
            ret = a - b;
            break;
        case '*':
            ret = a * b;
            break;
        case '/':
            ret = a / b;
            break;
        case '(':
            fprintf(stderr, "?..?..宸?.??n");
            return -1;
        default:
            DEBUG_PRT("%d: %s - wrong elem in stack\n", __LINE__, __FUNCTION__);


 

            assert(0);
    };

    DEBUG_PRT("%ld %c %ld = %ld\n", a, opr, b, ret);

    PUSH_NUM(ret);
    return 0;
}


 

static int opr_level(char opr)
{
    int level = 0;

    switch (opr) {
        case '(':
            break;
        case '+':
        case '-':
            level += 1;
            break;
        case '*':
        case '/':
            level += 2;
            break;
        default:
            DEBUG_PRT("%d: %s - wrong opr in level check\n", __LINE__, __FUNCTION__);
            assert(0);
    };

    return level;
}

static inline int cmp_opr(char opr_a, char opr_b)
{
    return opr_level(opr_a) - opr_level(opr_b);
}


 

static int opr_handler(struct calc_info *info)
{
    char opr = 0;

    if (info->flag == OPR ) {//褰..cur?..璐..
        if (*info->cur != '-') {
            fprintf(stderr, "?..?.?缁.?绠..\n");
            return -1;
        } else {
            //寰€num?.腑?.?涓.锛.舰?.€.-?..琛ㄨ揪寮.??ユ.浠h??
            num_t zero = 0;
            PUSH_NUM(zero);
        }
    } else {//褰..cur?..杩..琛ㄨ揪寮
        while (!(ISEMPTY_OPR || (TOP_OPR(opr), cmp_opr(*info->cur, opr) > 0))) {
            if (do_stack(info) < 0) {
                return -1;
            }
        }
    }

    PUSH_OPR(*info->cur);
    info->flag = OPR;

    return 0;
}


 

static int bracket_handler(struct calc_info *info)
{
    char opr = 0;

    switch (*info->cur) {
        case '(':
            PUSH_OPR(*info->cur);
            info->flag = OPR;
            break;
        case ')':
            assert(!ISEMPTY_OPR);
            while (!(TOP_OPR(opr) < 0) && (opr != '(')) {
                if (do_stack(info) < 0) {
                    return -1;
                }
            }
            if (opr == '(') {
                POP_OPR(opr);
            } else { //宸?.?风己?.??..?..?..
                fprintf(stderr, "?..?..?虫.??n");
                return -1;
            }
            break;
        default:
            DEBUG_PRT("%d: %s - wrong opr in bracket_handler\n", __LINE__, __FUNCTION__);
            assert(0);
    };

    return 0;
}


 

static num_t calc(struct calc_info *info, const char *expr)
{
    //init
    info->expr = expr;
    info->cur = (char*)info->expr;
    stack_init(&info->opr);
    stack_init(&info->num);
    info->flag = OPR;

    for (; *info->cur; ++(info->cur)) {
        switch (*info->cur) {
            case '0'...'9':
                num_handler(info);
                break;
            case '+':
            case '-':
            case '*':
            case '/':
                if (opr_handler(info) < 0) {
                    goto error;
                }
                break;
            case '(':
            case ')':
                if (bracket_handler(info) < 0) {
                    goto error;
                }
                break;
            default:
                break;
        };
    }

    while (!(ISEMPTY_OPR)) {
        if (do_stack(info) < 0) {
            goto error;
        }
    }

    num_t ret = 0;
    POP_NUM(ret);

    DEBUG_PRT("%s = %ld\n", info->expr, ret);

    stack_destroy(&info->num);
    stack_destroy(&info->opr);

    return ret;

error:
    stack_destroy(&info->num);
    stack_destroy(&info->opr);
    return -1;
}

void calc_init(struct calc_info *info)
{
    info->output = calc;
}

void calc_destroy(struct calc_info *info)
{

}


calc/list.h

struct node_info {
    struct node_info *prev;
    struct node_info *next;
    char priv[];
};

struct list_info {
    struct node_info *head;
    void (*add)(struct list_info *,
            const void *data_entry,
            size_t data_size);
    void (*add_tail)(struct list_info *,
            const void *data_entry,
            size_t data_size);
    void (*del)(struct list_info *,
            struct node_info *,
            size_t data_size);
};

#define list_for_each(cur, head) \
    for (cur = (head)->next; \
        (cur) != (head); \
        cur = (cur)->next)

#define list_for_each_safe(cur, tmp, head) \
    for (cur = (head)->next, tmp = (cur)->next; \
        (cur) != (head); \
        cur = tmp, tmp = (tmp)->next)

#define ENTRY(node, type) ((type*)(node->priv))

void list_init(struct list_info*);
void list_destroy(struct list_info*);


calc/list.c

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


static void __list_add(struct node_info *prev,
        struct node_info *next,
        const void *data_entry,
        size_t data_size)
{
    struct node_info *node = (struct node_info *)malloc(sizeof(struct node_info) + data_size);
    memcpy(node->priv, data_entry, data_size);

    node->prev = prev;
    node->next = next;
    prev->next = node;
    next->prev = node;
}

static void list_add(struct list_info *info,
        const void *data_entry, size_t data_size)
{
    __list_add(info->head, info->head->next,
            data_entry, data_size);
}

static void list_add_tail(struct list_info *info,
        const void *data_entry, size_t data_size)
{
    __list_add(info->head->prev, info->head,
            data_entry, data_size);
}


 

static void list_del(struct list_info *info,
        struct node_info *node,
        size_t data_size)
{
    node->prev->next = node->next;
    node->next->prev = node->prev;
    node->prev = node;
    node->next = node;

    if (data_size) {
        memset(node->priv, 0, data_size);
    }
    free(node);
}

void list_init(struct list_info *info)
{
    info->head = (struct node_info *)malloc(sizeof(struct node_info));
    info->head->prev = info->head;
    info->head->next = info->head;

    info->add = list_add;
    info->add_tail = list_add_tail;
    info->del = list_del;
}

void list_destroy(struct list_info *info)
{
    struct node_info *cur = info->head->next;

    for (; cur != info->head; cur = info->head->next) {
        list_del(info, cur, 0);
    }

    free(info->head);
}


calc/Makefile

TGT := calc
SRCS := list.c stack.c calc.c test.c

CFLAGS :=

$(TGT): $(SRCS)
    $(CC) $(CFLAGS) -o $@ $^

clean:
    $(RM) $(TGT)
~                           


calc/stack.h

#include "list.h"

struct stack_info {
    struct list_info list;
    void (*push)(struct stack_info *,
            const void *data_entry,
            size_t data_size);
    int (*pop)(struct stack_info *,
            void *data_entry,
            size_t data_size);
    int (*top)(struct stack_info *,
            void *data_entry,
            size_t data_size);
    int (*isempty)(struct stack_info *); 
};

void stack_init(struct stack_info *); 
void stack_destroy(struct stack_info *); 
~                                                   


calc/stack.c

#include "stack.h"


static void stack_push(struct stack_info *info,
        const void *data_entry,
        size_t data_size)
{
    info->list.add(&info->list, data_entry, data_size);
}

static int stack_isempty(struct stack_info *info)
{
    return info->list.head->next == info->list.head;
}

static int stack_top(struct stack_info *info,
        void *data_entry,
        size_t data_size)
{
    if (stack_isempty(info)) {
        return -1; 
    }   

    if (data_entry) {
        memcpy(data_entry, info->list.head->next->priv, data_size);
    }   
    return 0;
}


 

static int stack_pop(struct stack_info *info,
        void *data_entry,
        size_t data_size)
{
    if (stack_top(info, data_entry, data_size) < 0) {
        return -1; 
    }

    //?..绗.?涓..?..?
    info->list.del(&info->list, info->list.head->next, data_size);
    return 0;
}

void stack_init(struct stack_info *info)
{
    list_init(&info->list);
    info->push = stack_push;
    info->pop = stack_pop;
    info->top = stack_top;
    info->isempty = stack_isempty;
}

void stack_destroy(struct stack_info *info)
{
    list_destroy(&info->list);
}


calc/test.c

#include <stdio.h>
#include "calc.h"

int main(int argc, char **argv)
{
    const char *expr = "(115+(-( -126 - (-2) )))* (84 / (41 + (-1)))";

    const char *banner = "璁$.???ㄦ?锛..浠?琛ㄨ揪寮.n?

    struct calc_info calc;
    calc_init(&calc);

    if (argc == 1) {
        printf("%ld\n", calc.output(&calc, expr));
    }   
    else if (argc == 2) {
        printf("%ld\n", calc.output(&calc, argv[1]));
    } else {
        fprintf(stderr, "%s\n", banner);
    }   

    calc_destroy(&calc);

    return 0;
}   


calc/macro_test.c

#include <stdio.h>

#define DEBUG_PRT(fmt, arg...) printf(fmt, arg)

#define ABC(a, b...) ""#b""
/*#define ABC(a, b...) "b"*/

#define DEF(a, b) a##hello##b

void func(int a, ...)
{

}

int main()
{
    DEBUG_PRT("%s %c %d\n", "abc", 'X', 100);

    func(100, 200, 300, 400);

    printf("%s\n", ABC(aa, bb, cc, dd));

    int DEF(aa, bb) = 1234;

    printf("%d\n", aahellobb);

    return 0;
}


 

由图表可知,本实验工程包括 4 个子模块,其中频率计算模块(freq_meter_calc)是实验 工程的核心模块,他将输入的待检测信号利用等精度测量法进行计算,得出被测时钟信号 时钟频率并输出;数码管显示模块(seg_595_dynamic)接收频率计算模块输出的计算结果, 并显示在数码管上;被测时钟生成模块(clk_test_gen)负责产生某一频率的待检测时钟信 号;最后的顶层模块(freq_meter),内部将上述 3 个子功能模块实例化其中,连接各自对应 信号,外部输入时钟、复位和待检测信号,输出段选、位选和待检测数据频率计算模块的作用是:使用等精度测量法对输入的待检测时钟信号进行频率测量, 并将测量结果输出。频率计算模块框图,具体见图 32-4;模块输入输出端口描述,具体见 表格 32-2。 图 32-4 频率计算模块框图 模块内部实例化一个时钟生成 IP 核,负责将 50MHz 系统时钟信号(sys_clk)倍频生成 100MHz 标准时钟。 为什么要使用 100MHz 时钟信号作为标志信号呢?在前文的等精度测量原理中,我们 知道,被测时钟信号的时钟频率 fx 的相对误差与被测时钟信号无关;增大“软件闸门”的 有效范围或者提高“标准时钟信号”的时钟频率 fs,可以减小误差,提高测量精度。 使用 100 MHz 时钟作为标准时钟信号,实际闸门时间大于或等于 1s,就可使测量的最 大相对误差小于或等于 10 -8,即精度达到 1/100 MHz,大大提高了测量精度。 表格 32-2 模块输入输出信号功能描述 信号 位宽 类型 功能描述 sys_clk 1Bit Input 系统时钟,频率 50MHz sys_rst_n 1Bit Input 复位信号。低电平有效 clk_test 1Bit Intput 待检测时钟信号输入 freq 34Bit Output 频率测量结果输出 模块有 3 路输入信号:时钟(sys_clk)、复位(sys_rst_n)和待检测时钟信号(clk_test);有 输出信号 1 路,输出频率测量结果(freq)。 波形图绘制 在模块框图小节,我们已经对本模块做了简单介绍,接下来,我们将通过波形图的绘 制,对各信号波形进行详细说明,教会读者等精度测量的实现方法。频率计算模块整体波 形图如图 32-5 所示。 图 32-5 频率计算模块整体波形图 结合等精度测量法原理,我们对各信号波形的设计与实现进行详细说明。 第一部分:软件闸门 gate_s 及相关信号的设计与实现 由等精度测量原理可知,实现等精度测量必不可少的是实际闸门,而实际闸门是由软 件闸门得来,所以我们先来生成一下软件闸门。我们计划一个完整周期的软件闸门为 1.5s,前 0.25s 保持低电平,中间 1s 保持高电平,最后 0.25s 保持低电平。低电平部分是为 了将各计数器清 0,并计算待测时钟信号时钟频率;高电平部分就是软件闸门有效部分, 高电平保持 1s 是为了提高测试精度,在前文已有提及。 软件闸门的生成我们需要声明计数器进行时间计数,计数时钟使用系统时钟 sys_clk。 声明软件闸门计数器 cnt_gate_s,计数时钟为 50MHz 系统时钟,时钟周期为 20ns,计数器 cnt_gate_s 初值为 0,在(0 – CNT_GATE_S_MAX)范围内循环计数。 声 明 软 件 闸 门 gate_s , 只 有 计 数 器 cnt_gate_s 计 数 在 ((CNT_RISE_MAX+1)- (CNT_GATE_S_MAX-CNT_RISE_MAX))范围内保持有效高电平,高电平保持时间为 1s, 其他时刻均为低电平第二部分:实际闸门 gate_a 的设计与实现 生成软件闸门后,使用被测时钟对软件闸门进行同步生成实际闸门 gate_a,实际闸门 波形图如下。 图 32-7 gate_a 信号波形图 第三部分:实际闸门下,标准信号和被测信号时钟计数相关信号的波形设计与实现 在实际闸门下,分别对标准信号和被测信号的时钟周期进行计数。声明计数器 cnt_clk_stand,在实际闸门下对标准时钟信号 clk_stand 进行时钟周期计数;声明计数器 cnt_clk_test,在实际闸门下对被测时钟信号 clk_test 进行时钟周期计数,两计数器波形如 下。 图 32-8 cnt_clk_stand、cnt_clk_test 信号波形图 计数器 cnt_clk_stand、cnt_clk_test 在实际闸门下计数完成后,需要进行数据清零,方 便下次计数。但是被测时钟频率的计算需要计数器的数据,所以在计数器数据清零之前我 们需要将计数器数据做一下寄存,对于数据寄存的时刻,我们选择实际闸门的下降沿。 声明寄存器 cnt_clk_stand_reg;在标准时钟信号 clk_stand 同步下对实际闸门打一拍得 到 gate_a_s;使用实际闸门 gate_a 和 gate_a_s 得到标准时钟下的实际闸门下降沿标志信号 gate_a_fall_stand。当 gate_afall_stand 信号为高电平时,将计数器 cnt_clk_stand 数值赋值给 寄存器 cnt_clk_stand_reg。 对 于 计 数 器 cnt_clk_test 的 数 值 寄 存 , 我 们 使 用 相 同 的 方 法 , 声 明 寄 存 器 cnt_clk_test_reg;在被检测时钟信号 clk_test 同步下对实际闸门打一拍得到 gate_a_t;使用 实际闸门 gate_a 和 gate_a_t 得到被检测时钟下的实际闸门下降沿标志信号 gate_a_fall_test。 当 gate_a_fall_test 信号为高电平时,将计数器 cnt_clk_test 数值赋值给 cnt_clk_test_reg。第四部分:频率计算结果 freq 等相关信号波形的设计与实现 实际闸门下的标准时钟和被测时钟的周期个数已经完成计数,且对结果进行了寄存, 标准时钟信号的时钟频率为已知量,得到这些参数,结合公式可以进行频率的求解。同 时,新的问题出现,在哪一时刻进行数据求解。 我们可以利用最初声明的软件闸门计数器 cnt_gate_s,声明计算标志信号 calc_flag,在 计数器 cnt_gate_s 计数到最大值,将 calc_flag 拉高一个时钟周期的高电平作为计算标志, 计算被检测时钟信号时钟频率 freq_reg(注意变量位宽是否满足要求);然后在系统时钟下将 计算标志信号 calc_flag 打一拍,得到时钟频率输出标志信号 calc_flag_reg,当时钟频率输 出标志信号 calc_flag_reg 为高电平时,将时钟频率计算结果 freq_reg 赋值给输出信号 freq。各信号波形图如下。 图 32-10 calc_flag、freq 信号波形图 到了这里,频率计算模块涉及的各信号波形均已设计并实现,经过整合后就得到频率 计算模块整体波形图根据上述写一下等精度频率计频率计算模块的vhdl语言代码
07-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值