Mathe OpenSource Library für C



  • Guten Morgen,

    ich suche eine Library in C womit ich ausdrücke wie:
    (11+2)*4^2
    berechnen kann, kann mir da jemand weiterhelfen?


  • Mod

    Ich kann dir zwar keine empfehlen (weil ich nie eine benutzt habe), aber ich kann dir helfen, eine zu finden:
    Google: c math parser



  • Ich hab sowas noch hier rumliegen. Es ist zwar nicht ganz für die Bibliotheksform geschrieben - eine vernünftige Fehlerbehandlung wirst du noch einpflegen müssen - aber vielleicht hilft es dir ja weiter. Das ganze implementiert den Shunting-Yard-Algorithmus.

    Ich hoffe nur, das Formu nimmt mir so viel Quellcode nicht übel...also:

    // token.h
    
    #ifndef INCLUDED_TOKEN_H
    #define INCLUDED_TOKEN_H
    
    #include <stddef.h>
    
    enum token_type {
      tok_num,
      tok_op
    };
    
    struct token {
      union {
        double num;
        char   op;
      } v;
    
      enum token_type type;
    };
    
    struct token *get_token(char const **pos, struct token *dest);
    
    struct token_node {
      struct token_node *prev;
      struct token_node *next;
      struct token val;
    };
    
    struct token_node *token_node_new   (struct token_node *pos, struct token val);
    void               token_node_delete(struct token_node *);
    
    struct token_list {
      struct token_node *head;
      struct token_node *tail;
    
      size_t size;
    };
    
    void         token_list_new   (struct token_list *);
    void         token_list_delete(struct token_list *);
    
    void         token_list_insert    (struct token_list       *, struct token_node *pos, struct token val);
    void         token_list_push_front(struct token_list       *, struct token);
    void         token_list_push_back (struct token_list       *, struct token);
    
    void         token_list_remove    (struct token_list       *, struct token_node *);
    struct token token_list_pop_front (struct token_list       *);
    struct token token_list_pop_back  (struct token_list       *);
    
    struct token token_list_peek_front(struct token_list const *); 
    struct token token_list_peek_back (struct token_list const *); 
    
    #endif
    
    // token.c
    
    #include "token.h"
    
    #include <ctype.h>
    #include <stddef.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    static char const *const op_chars = "+-*/^()";
    
    struct token *get_token(char const **pos, struct token *dest) {
      int n;
      double num;
      char const *line = *pos;
    
      while(line[0] == ' ') {
        ++line;
      }
    
      if(strchr(op_chars, line[0]) != NULL) {
        dest->v.op = line[0];
        dest->type = tok_op;
        *pos = line + 1;
      } else if(sscanf(line, "%lf%n", &num, &n) == 1) {
        dest->v.num = num;
        dest->type = tok_num;
        *pos = line + n;
      } else {
        return NULL;
      }
    
      return dest;
    }
    
    struct token_node *token_node_new(struct token_node *pos, struct token val) {
      struct token_node *n = calloc(1, sizeof(struct token_node));
    
      n->prev = pos->prev;
      n->next = pos;
    
      n->prev->next = n;
      n->next->prev = n;
    
      n->val = val;
    
      return n;
    }
    
    void token_node_delete(struct token_node *n) {
      n->prev->next = n->next;
      n->next->prev = n->prev;
    
      free(n);
    }
    
    void token_list_new(struct token_list *l) {
      l->size = 0;
    
      l->head = calloc(1, sizeof(struct token_node));
      l->tail = calloc(1, sizeof(struct token_node));
    
      l->head->next = l->tail->next = l->tail;
      l->tail->prev = l->head->prev = l->head;
    }
    
    void token_list_delete(struct token_list *l) {
      while(l->size > 0) {
        token_list_pop_front(l);
      }
    
      free(l->head);
      free(l->tail);
    }
    
    void token_list_remove(struct token_list *l, struct token_node *n) {
      if(l->size > 0) {
        token_node_delete(n);
        --l->size;
      }
    }
    
    struct token token_list_pop_front(struct token_list *l) {
      struct token tok = token_list_peek_front(l);
      token_list_remove(l, l->head->next);
      return tok;
    }
    
    struct token token_list_pop_back(struct token_list *l) {
      struct token tok = token_list_peek_back(l);
      token_list_remove(l, l->tail->prev);
      return tok;
    }
    
    void token_list_insert(struct token_list *l, struct token_node *pos, struct token val) {
      token_node_new(pos, val);
      ++l->size;
    }
    
    void token_list_push_back(struct token_list *l, struct token val) {
      token_list_insert(l, l->tail, val);
    }
    
    void token_list_push_front(struct token_list *l, struct token val) {
      token_list_insert(l, l->head->next, val);
    }
    
    struct token token_list_peek_front(struct token_list const *l) {
      return l->head->next->val;
    }
    
    struct token token_list_peek_back(struct token_list const *l) {
      return l->tail->prev->val;
    }
    
    // syard.h
    
    #ifndef INCLUDED_SYARD_H
    #define INCLUDED_SYARD_H
    
    #include "token.h"
    
    struct token_list make_rpn(char const *line);
    
    double eval_rpn(struct token_list *rpn);
    double eval_string(char const *expr);
    
    #endif
    
    // syard.c
    
    #include "syard.h"
    
    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    static int op_pcd(char op) {
      switch(op) {
      case '+':
      case '-':
        return 0;
      case '*':
      case '/':
        return 1;
      case '^':
        return 3;
      }
    
      return -1;
    }
    
    struct token_list make_rpn(char const *line) {
      struct token_list result;
      struct token_list stack;
      struct token tok;
      char const *pos = line;
    
      token_list_new(&result);
      token_list_new(&stack);
    
      while(get_token(&pos, &tok)) {
        switch(tok.type) {
        case tok_num:
          {
    	token_list_push_back(&result, tok);
    	break;
          }
        case tok_op:
          {
    	char op = tok.v.op;
    
    	if(op == '(') {
    	  token_list_push_back(&stack, tok);
    	} else if(op == ')') {
    	  while(token_list_peek_back(&stack).v.op != '(') {
    	    if(stack.size == 0) {
    	      fputs("Mismatched parentheses\n", stderr);
    	      exit(-1);
    	    }
    
    	    token_list_push_back(&result, token_list_pop_back(&stack));
    	  }
    
    	  token_list_pop_back(&stack);
    	} else {
    	  while(op != '^' &&
    		stack.size != 0 &&
    		op_pcd(op) <= op_pcd(token_list_peek_back(&stack).v.op)) {
    	    token_list_push_back(&result, token_list_pop_back(&stack));
    	  }
    
    	  token_list_push_back(&stack, tok);
    	}
    
    	break;
          }
        }
      }
    
      while(stack.size > 0) {
        if(token_list_peek_back(&stack).v.op == '(') {
          fputs("Mismatched parentheses\n", stderr);
          exit(-1);
        }
    
        token_list_push_back(&result, token_list_pop_back(&stack));
      }
    
      token_list_delete(&stack);
    
      return result;
    }
    
    double eval_rpn(struct token_list *q) {
      struct token_list stack;
      double r;
    
      token_list_new(&stack);
    
      while(q->size > 0) {
        struct token tok = token_list_peek_front(q);
    
        switch(tok.type) {
        case tok_num: 
          {
    	token_list_push_back(&stack, tok );
    	break;
          }
        case tok_op:
          {
    	struct token operand1, operand2, result;
    
    	if(stack.size < 2) {
    	  fputs("RPN: Zu wenig Zahlen\n", stderr);
    	  exit(-1);
    	}
    
    	operand2 = token_list_pop_back(&stack);
    	operand1 = token_list_pop_back(&stack);
    
    	result.type = tok_num;
    	switch(tok.v.op) {
    	case '+': result.v.num = operand1.v.num + operand2.v.num; break;
    	case '-': result.v.num = operand1.v.num - operand2.v.num; break;
    	case '*': result.v.num = operand1.v.num * operand2.v.num; break;
    	case '/': result.v.num = operand1.v.num / operand2.v.num; break;
    	case '^': result.v.num = pow(operand1.v.num, operand2.v.num); break;
    	}
    
    	token_list_push_back(&stack, result);
    	break;
          }
        default:
          fputs("RPN: Unbekannter Token-Typ", stderr);
          exit(-1);
          break;
        }
    
        token_list_pop_front(q);
      }
    
      if(stack.size != 1) {
        fputs("RPN: Zu viel oder zu wenig Zahlen\n", stderr);
        exit(-1);
      }
    
      r = token_list_peek_back(&stack).v.num;
    
      token_list_delete(&stack);
    
      return r;
    }
    
    double eval_string(char const *expr) {
      struct token_list q = make_rpn(expr);
      double d = eval_rpn(&q);
    
      token_list_delete(&q);
    
      return d;
    }
    
    // main.c
    
    #include "token.h"
    #include "syard.h"
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    int main(void) {
      char line[1024];
    
      if(fgets(line, 1024, stdin) != NULL) {
        printf("%g\n", eval_string(line));
      }
    
      return 0;
    }
    

    Und die Makefile:

    #!/usr/bin/make
    
    TARGET  = calc
    
    CC      = gcc
    CFLAGS  = -Wall -Wextra -pedantic -g
    LDFLAGS = -lm
    
    SRCS    = $(wildcard *.c)
    OBJS    = $(SRCS:%.c=%.o)
    
    DEPFILE = .depend
    
    all: dep $(TARGET)
    
    dep: $(DEPFILE)
    
    $(DEPFILE): $(SRCS)
    	$(CC) -MM $+ > $@
    
    $(TARGET): $(OBJS)
    	$(CC) $(CFLAGS) $(LDFLAGS) $+ -o $@
    
    clean:
    	rm $(OBJS)
    
    distclean: clean
    	rm $(TARGET)
    
    .PHONY: all dep clean distclean
    


  • Hat niemand eine Empfehlung für einen "fertigen" Parser?



  • lern programmieren 🙄



  • bartek schrieb:

    Hat niemand eine Empfehlung für einen "fertigen" Parser?

    Das geht mit GNU Octave oder Matlab. Je nach dem, ob du mit der GPL leben kannst, oder genug Geld hast.


Anmelden zum Antworten