Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Programm zur Auswertung logischer Ausdrücke

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: [ 1 ] > 2 <
010
05.12.2006, 14:27 Uhr
JackBeauregard



Das Programm selbst soll ja nicht sehr professionell sein, d.h. es sollen nur die simpelsten logischen Operationen wie UND, ODER, NICHT realisiert werden. Ich Versuche immer noch den Zusammenhang zu den Bitweisen Operatoren herzustellen, jedoch gelingt mir dies nicht wirklich.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
011
05.12.2006, 22:46 Uhr
Windalf
Der wo fast so viele Posts wie FloSoft...
(Operator)


So hatte gerade mal langeweile..

ich glaub mit der Grammatik müsste man das hinbekommen....


Code:
A -> CB
B -> +CB  |epsilon
C -> ED
D ->*ED |epsilon
E -> (die gewünschten Terminals)



Wenn man noch negation will muss man ein bisschen an E drehen...

Das ganze in c zu coden schenkt allerdings garantiert extrem wenig freude. in c++ schon deutlich angenehmer... könnte man ja mal ne golfaufgabe draus stricken....
--
...fleißig wie zwei Weißbrote

Dieser Post wurde am 05.12.2006 um 22:47 Uhr von Windalf editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
012
05.12.2006, 23:28 Uhr
Blubber2063



Also die Grammatik dürfte es glaube ich noch nicht ganz tun, denn du kannst leider nicht mehr zurück nach B damit gibts nur einmal oder.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
013
06.12.2006, 09:39 Uhr
Windalf
Der wo fast so viele Posts wie FloSoft...
(Operator)


ups da hab ich mich vertippert...

müsste

Code:
A -> CB
B -> +CB  |epsilon
C -> ED
D ->*EB |epsilon
E -> (die gewünschten Terminals)



Hab allerdings nicth wirklich viele Terme getestet um sagen zu können ob es auch funzt...
--
...fleißig wie zwei Weißbrote
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
014
06.12.2006, 11:30 Uhr
ao

(Operator)



Zitat von JackBeauregard:
Leider sieht mein Prof, welcher mir die Aufgabe gestellt hat das anders (Anmerkung: Programmierung in C, 1. Semester). Er meinte, dass dies ohne Parser gehen würde. Ich solle die bitweisen Operatoren mit einbeziehen.

Dann schreib doch mal, ob die Funktion völlig frei definierbar sein muss, also z.B. auch so:

Code:
x = (a + .b) + .(c + .(.d & a) & (b + c) + (a & b & c)) + .....


- dann gehts nur mit Parser - oder ob es da möglicherweise starke Einschränkungen gibt.

ao
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
015
06.01.2007, 20:02 Uhr
JackBeauregard



Hallo,

eins vorab, die Funktionen sind noch nicht wirklich fertig, d.h. bspw writelist ist noch garnicht auf die Variablenanzahl angepasst usw.. Habe bislang folgendes zusammengebaut:


C++:
#include <stdio.h>

#define MAXFLEN 100
#define bit(v,b) ((v&(1<<b)) != 0)

.
.
.

int func(char funktion[MAXFLEN])
{
   int i;
   int c;
   int banz;
  
   do {
      printf("\nBitte booleschen Ausdruck eingeben:\n");
      printf("Y = ");
      
      fgets(funktion, MAXFLEN, stdin);
      banz = pruef(funktion);

      } while(banz == 0);

      printf("Y = %s\n", funktion);
      return banz;
}

int menue(void)
{
   printf("1 = Eingabe der logischen Funktion\n"
          "2 = Ausgabe der Wahrheitstafel\n"
          "0 = Programmende\n\n");
   return readint("Auswahl: ", 0, 2);
}

int readint(char msg[], int lower, int upper)
{
   int zahl, n;

   do
   {
      printf("%s", msg);
      n = scanf("%d", &zahl);
      while (getchar() != '\n');

      if (n != 1)
         printf("\nBitte nur Zahlen eingeben!\n\n");
      else if (zahl < lower)
      {
         printf("\nUngueltiger Bereich!\n\n", lower);
         n = 0;
      }
      else if (zahl > upper)
      {
         printf("\nUngueltiger Bereich!\n\n", upper);
         n = 0;
      }
   } while (n != 1);
   return zahl;
}

int writelist(void)
{
    const unsigned short a = 0x00FF;
    const unsigned short b = 0x0F0F;
    const unsigned short c = 0x3333;
    const unsigned short d = 0x5555;
    int i;

    printf("\na b c d | y\n");
    printf("--------|--\n");
    
    for(i = 15; i >= 0; i--)
    
       printf("%i %i %i %i | %i\n", bit(a,i), bit(b,i), bit(c,i), bit(d,i));
}

int main()
{
   int i;
   int auswahl;
   char funktion[MAXFLEN];

   printf("Boolesche Ausdruecke und Wahrheitstafeln\n"
          "----------------------------------------\n\n");  
   do {
      
      auswahl = menue();
      
      switch (auswahl) {

      /*Auswahl des Menuepunktes 1*/

      case 1:
         func(funktion);
         break;

      /*Auswahl des Menuepunktes 2*/

      case 2:
         writelist();
         break;

      /*Auswahl des Menuepunktes 0*/

      case 0:
         printf("\nProgrammende!");
         break;

      }
        
   } while(auswahl = 0);
  
return 0;
}

int pruef(char funktion[MAXFLEN])
{
    int a = 0;
    int b = 0;
    int c = 0;
    int d = 0;
    int punkt = 0;
    int oder = 0;
    int i;
    
    if(funktion[0] == '+'){
       printf("Zu Beginn des Ausdrucks kein Oder!");
       return 0;
    }
    for(i = 0; i < MAXFLEN; i++){
       if(funktion[i] == 'a'){
          a = 1;
          punkt = 0;
          oder = 0;
       }
       else if(funktion[i] == 'b'){
          b = 1;
          punkt = 0;
          oder = 0;
       }
       else if(funktion[i] == 'c'){
          c = 1;
          punkt = 0;
          oder = 0;
       }
       else if(funktion[i] == 'd'){
          d = 1;
          punkt = 0;
          oder = 0;
       }
       else if(funktion[i] == '.'){
          if(punkt == 1){
             printf("Syntaxfehler: Doppelte Negation an Stelle %i\n", i);
             return 0;
          } else {
             punkt = 1;
          }    
       }
       else if(funktion[i] == '+'){
          if(punkt == 1){
             printf("Syntaxfehler: Negation des Oder-Symbols an Stelle %i\n",
                    i);
             return 0;            
          }
          if(oder == 0){
             oder = 1;
          }else{
             printf("Syntaxfehler: Zwei Oder-Symbole nacheinander an Stelle %i"
                    "\n", i);
             return 0;
          }      
                
       }
       else{
          if(funktion[i] == ' '){

          } else if(funktion[i] == '\n') {
                
          
          } else if(funktion[i] == '\0') {
             if(punkt == 1 | oder == 1) {
                printf("Unzulaessiges Symbol am Ende des Ausdrucks!\n");                      
                return 0;
                }  
                i = MAXFLEN;
          } else {
             printf("Syntaxfehler: Unzulaessiges Symbol(%c) an Stelle %i\n",
                     funktion[i], i+1);
             return 0;
          }                    
       }          
    }
    if((a+b+c+d) < 2){
       printf("Bitte mindestens 2 Variablen benutzen!\n");
       return 0;
    }
    if(((a+b+c+d) == 3) && (d == 1)){
       printf("Bitte die Variablen nach Alphabetischer Reihenfolge waehlen!\n");
       return 0;
    }
    if(((a+b+c+d) == 2) && ((c == 1)|(d == 1))){
       printf("Bitte die Variablen nach Alphabetischer Reihenfolge waehlen!\n");
       return 0;
    }                                                                
    return (a+b+c+d);
}



Das Ganze soll so ablaufen, dass nach der Eingabe des log. Ausdrucks (Menüpunkt 1) ins Auswahlmenue zurückgesprungen werden soll und der Benutzer die Möglichkeit bekommen soll Menüpunkt 2 auszuwählen um so eine Wahrheitstabelle ausgegeben zu bekommen. Genauso soll nach der Ausgabe der Tabelle ins Auswahlmenue zurück gesprungen werden.

Wie kann dies realisiert werden? Ans Ende der Funktion ein main(); hängen wäre ja nicht wirklich gut . Wichtig ist ja hierbei, dass der eingegebene Ausdruck gespeichert wird damit er dann über die Wahrheitstafel ausgegeben werden kann.

Ich hoffe, dass ihr versteht was ich meine.

Gruß
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
016
06.01.2007, 20:25 Uhr
0xdeadbeef
Gott
(Operator)


Ich würd da ja eher mit ner EBNF rangehen, als mit nem Semi-Thue-System. Ich nehm grad mal an, dass & stärker binden soll, dann sähe das in etwa so aus:

Code:
DISJUNKTION = KONJUNKTION ( '+' KONJUNKTION)*
KONJUNKTION = TERM ( '&' TERM)*
TERM = LITERAL | ( '(' DISJUNKTION ')' )
LITERAL = wahr | falsch | *mögliche Variablennamen hier*


Das ganze dann an einen parser generator deiner Wahl verfüttern, und fertig ists.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
017
06.01.2007, 23:27 Uhr
0xdeadbeef
Gott
(Operator)


Ich hab das zum Spaß mal mit boost.spirit implementiert:
calculator.hh:

C++:
#ifndef INCLUDED_CALCULATOR_HH
#define INCLUDED_CALCULATOR_HH

#include <boost/spirit/tree/common.hpp>

#include <exception>
#include <map>
#include <ostream>
#include <string>

class calculator {
public:
  typedef char ast_data_t;

  struct invalid_input : public std::exception { virtual char const *what() const throw() { return "invalid input data"               ; } };
  struct malformed     : public invalid_input  { virtual char const *what() const throw() { return "malformed or missing expression"  ; } };
  struct vars_missing  : public invalid_input  { virtual char const *what() const throw() { return "variables missing"                ; } };

  calculator();
  calculator(std::string const &str) throw(malformed);
  calculator(       char const *str) throw(malformed);

  void parse(std::string const &str) throw(malformed);
  void parse(       char const *str) throw(malformed);

  inline bool full_match() const throw() { return tree_info_.full; }

  bool operator()(std::map<char, bool> const &vars) const throw(vars_missing, malformed);

  void to_xml(std::ostream &os, char const *str) const;

private:
  typedef boost::spirit::tree_parse_info<char const *, boost::spirit::node_val_data_factory<ast_data_t> > tree_type;
  typedef boost::spirit::tree_match     <char const *, boost::spirit::node_val_data_factory<ast_data_t>, boost::spirit::nil_t>::const_tree_iterator tree_iterator;

  void parse_aux(char const *begin, char const *end);

  bool eval(tree_iterator const &i, std::map<char, bool> const &vars) const throw(vars_missing);

  tree_type tree_info_;
};

#endif


calculator.cc:

C++:
#include "calculator.hh"

#include <boost/spirit/core.hpp>
#include <boost/spirit/tree/ast.hpp>
#include <boost/spirit/tree/parse_tree.hpp>
#include <boost/spirit/tree/tree_to_xml.hpp>

#include <cstring>
#include <exception>

namespace bs = boost::spirit;

namespace {
  class grammar : public bs::grammar<grammar> {
  public:
    typedef calculator::ast_data_t result_t;
    typedef bs::tree_node<bs::node_val_data<char const *, result_t> > node_t;

    enum rule_id {
            false_id = 1,
             true_id,
         variable_id,
             term_id,
      conjunction_id,
      disjunction_id
    };

    template<typename scanner_t> class definition {
    public:
      struct assign_char_to_node {
        void operator()(node_t &n,
                        typename scanner_t::iterator_t const &first,
                        typename scanner_t::iterator_t const &last) const {
          namespace bs = bs;

          result_t r;
          bs::parse(first, last, bs::range_p('a', 'z')[bs::assign_a(r)]);
          n.value.value(r);
        }
      };

      definition(grammar const &self) {
        namespace bs = bs;

        false_rule  = bs::str_p("#f") | '0';
        true_rule   = bs::str_p("#t") | '1';
        variable    = bs::access_node_d[bs::range_p('a', 'z')][assign_char_to_node_a];

        term        = false_rule                                  |
                      true_rule                                   |
                      variable                                    |
                      bs::inner_node_d['(' >> disjunction >> ')'] |
                      (bs::root_node_d[bs::ch_p('!')] >> term);

        conjunction = term        >> *(bs::root_node_d[bs::ch_p('&')] >> term       );
        disjunction = conjunction >> *(bs::root_node_d[bs::ch_p('|')] >> conjunction);
      }

      bs::rule<scanner_t, bs::parser_context<>, bs::parser_tag<disjunction_id> > const &start() const {
        return disjunction;
      }

    private:
      bs::rule<scanner_t, bs::parser_context<>, bs::parser_tag<       true_id> >   true_rule;
      bs::rule<scanner_t, bs::parser_context<>, bs::parser_tag<      false_id> >  false_rule;
      bs::rule<scanner_t, bs::parser_context<>, bs::parser_tag<   variable_id> >    variable;
      bs::rule<scanner_t, bs::parser_context<>, bs::parser_tag<       term_id> >        term;
      bs::rule<scanner_t, bs::parser_context<>, bs::parser_tag<conjunction_id> > conjunction;
      bs::rule<scanner_t, bs::parser_context<>, bs::parser_tag<disjunction_id> > disjunction;

      assign_char_to_node assign_char_to_node_a;
    };

  private:
  };
}

calculator::calculator() { }
calculator::calculator(std::string const &str) throw(malformed) { parse(str); }
calculator::calculator(       char const *str) throw(malformed) { parse(str); }

void calculator::parse(std::string const &str) throw(malformed) { parse_aux(str.c_str(), str.c_str() + str.size()      ); }
void calculator::parse(       char const *str) throw(malformed) { parse_aux(str        , str         + std::strlen(str)); }

void calculator::parse_aux(char const *begin, char const *end) {
  grammar g;
  tree_info_ = bs::ast_parse<bs::node_val_data_factory<ast_data_t> >(begin, end, g, bs::space_p);
}

bool calculator::operator()(std::map<char, bool> const &vars) const throw(vars_missing, malformed) {
  if(!full_match())
    throw malformed();

  return eval(tree_info_.trees.begin(), vars);
}

bool calculator::eval(tree_iterator const &i, std::map<char, bool> const &vars) const throw(vars_missing) {
  switch(i->value.id().to_long()) {
  case grammar::   false_id: return false;
  case grammar::    true_id: return  true;
  case grammar::variable_id:
    {
      std::map<char, bool>::const_iterator iter = vars.find(i->value.value());
      if(iter == vars.end()) throw vars_missing();
      return iter->second;
    }
  case grammar::       term_id: return !eval(i->children.begin(), vars);
  case grammar::conjunction_id: return  eval(i->children.begin(), vars) && eval(i->children.begin() + 1, vars);
  case grammar::disjunction_id: return  eval(i->children.begin(), vars) || eval(i->children.begin() + 1, vars);
  }
  // passiert nie
  throw std::bad_exception();
}

void calculator::to_xml(std::ostream &os, char const *str) const {
  std::map<bs::parser_id, std::string> rule_names;

  rule_names[grammar::      false_id] =       "false";
  rule_names[grammar::       true_id] =        "true";
  rule_names[grammar::   variable_id] =    "variable";

  rule_names[grammar::       term_id] =        "term";

  rule_names[grammar::conjunction_id] = "conjunction";
  rule_names[grammar::disjunction_id] = "disjunction";

  bs::tree_to_xml(os, tree_info_.trees, str, rule_names);
}


main.cc (zum Beispiel):

C++:
#include "calculator.hh"

#include <iostream>
#include <map>
#include <string>

int main() {
  calculator calc;
  std::string s;
  std::map<char, bool> vars;

  std::getline(std::cin, s);

  vars['a'] = true;
  vars['b'] = false;

  try {
    calc.parse(s);

    calc.to_xml(std::cout, s.c_str());
    std::cout << std::endl
              << calc(vars) << std::endl;
  } catch(calculator::invalid_input &e) {
    std::cerr << e.what() << std::endl;
  }
}



Bearbeitung:

Hmm. Die Formatierung ist da zwar etwas im Eimer, aber kopiers halt raus, dann sollte es einsichtiger sein.

Ich hab calculator.cc mal mit namespace bs = boost::spirit versehen, ums ein bisschen besser da reinzuquetschen.


--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 06.01.2007 um 23:31 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: [ 1 ] > 2 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: