5. Модули

Разделно компилиране

Създаване на заглавни файлове
* Стек - пример
   s.push("Able")
   s.push("Backer")
   s.push("Charlie")
   s.pop() -> "Charlie"
   s.push("Delta")
   s.pop() -> "Delta"
   s.pop() -> "Backer"
   s.pop() -> "Able"
* Създаване на клас
class Stack  {
public:
 Stack();
 void push(string s);
 string pop();
 bool is_empty() const;
private:
 vector<string> data;
 int top;
};
Stack::Stack() { top = 0; }

void Stack::push(string s)
{
 if (top < data.size()) data[top] = s;
 else data.push_back(s);
 top++;
}
string Stack::pop()
{
 assert(top > 0);
 top--;
 return data[top];
}
bool Stack::is_empty() const  {  return top == 0;  }

* Разделяне на информацията между stack.h и stack.cpp
// stack.h
#include <vector>
#include <string>
using namespace std;

class Stack  {
public:
 Stack();
 void push(string s);
 string pop();
 bool is_empty() const;
private:
 vector<string> data;
 int top;
};
// stack.cpp
#include <cassert>
using namespace std;
#include "stack.h"

Stack::Stack() { top = 0; }

void Stack::push(string s)
{
 if (top < data.size()) data[top] = s;
 else data.push_back(s);
 top++;
}

string Stack::pop()
{
 assert(top > 0);
 top--;
 return data[top];
}

bool Stack::is_empty() const {  return top == 0;  }

*Проблемът за двукратно включване на един и същи заглавен файл в програмата
#ifndef STACK_H
#define STACK_H
...
#endif

Разделяне на програмата на няколко първични файла

// error.h
#ifndef ERROR_H
#define ERROR_H
#include <string>
using namespace std;

void error(string message);
#endif

// input.h
#ifndef INPUT_H
#define INPUT_H
#include <string>
using namespace std;

bool is_operator(string s);
string next_token();
#endif

// eval.h
#ifndef EVAL_H
#define EVAL_H
#include <string>
using namespace std;
#include "stack.h"

int precedence(string s);
void evaluate(Stack& num, string op);
#endif

// error.cpp
#include <iostream>
#include <string>
using namespace std;
#include "error.h"

void error(string message)
{
   cout << "ERROR: " << message << ".\n";
   exit(1);
}

// eval.cpp
#include <string>
#include <sstream>
#include <cmath>
using namespace std;

#include "stack.h"
#include "error.h"
#include "eval.h"

int precedence(string s)
{
 if (s == "+" or s == "-")       return 1;
 else if (s == "*" or s == "/")  return 2;
 else if (s == "^")              return 3;
 else                            return 0;
}

double string_to_double(string s)
{
   istringstream instr(s);
   double x;
   instr >> x;
   return x;
}

string double_to_string(double x)
{
   ostringstream outstr;
   outstr << x;
   return outstr.str();
}

void evaluate(Stack& num, string op)
{
   if (num.is_empty()) error("Syntax error");
   double y = string_to_double(num.pop());
    if (num.is_empty()) error("Syntax error");
   double x = string_to_double(num.pop());
   double z;
   if (op == "^") z = pow(x, y);
   else if (op == "*") z = x * y;
   else if (op == "/")
   {  if (y == 0) error("Divide by 0");
      else z = x / y;
   }
   else if (op == "+") z = x + y;
   else if (op == "-") z = x - y;
   else error("Syntax error");
   num.push(double_to_string(z));
}

// input.cpp
#include <iostream>
#include <string>
#include <cctype>
using namespace std;

#include "error.h"
#include "input.h"

bool is_operator(string s)
{
 return s == "+" or s == "-" or
        s == "*" or s == "/" or s == "^";
}

void skip_whitespace()
{
   char ch;
   do
   {  cin.get(ch);
      if (cin.fail()) return;
   }  while (isspace(ch));
#ifndef CCC_USE_OLD_STREAMS
   cin.unget();
#else
   cin.putback(ch);
/* used if your compiler doesn't support the ANSI unget function */
#endif
}

string next_number()
{
   string r;
   bool more = true;
   while (more)
   {  char ch;
      cin.get(ch);
      if (cin.fail())  more = false;
      else if (isdigit(ch))  r = r + ch;
      else
      {
#ifndef CCC_USE_OLD_STREAMS
         cin.unget();
#else
         cin.putback(ch);
/* used if your compiler doesn't support the ANSI unget function */
#endif
         more = false;
      }
 }
   return r;
}

string next_token()
{
   skip_whitespace();
   char ch;
   cin.get(ch);
   if (cin.fail()) return "";
   if (isdigit(ch))
   {
#ifndef CCC_USE_OLD_STREAMS
      cin.unget();
#else
      cin.putback(ch);
         /* used if your compiler doesn't support the ANSI unget function */
#endif
      return next_number();
   }
 else
   {  string token;
      token = token + ch;
      if (is_operator(token) or token == "(" or token == ")"
            or token == "=") return token;
      else
      {  string message = "Unexpected input ";
         error(message + ch);
         return "";
      }
   }
}

// calc.cpp
#include <iostream>
#include <string>
using namespace std;

#include "stack.h"
#include "input.h"
#include "eval.h"
#include "error.h"

int main()
{
 Stack numstack;
 Stack opstack;

 while (true)
 {  string s = next_token();
  if (is_operator(s))
  {  if (opstack.is_empty()) opstack.push(s);
     else
   {  string old_op = opstack.pop();
    if (precedence(s) > precedence(old_op))  stack.push(old_op);
    else
     evaluate(numstack, old_op);
    opstack.push(s);
   }
  }
  else if (s == "(") opstack.push(s);
  else if (s == ")")
  {  bool more = true;
   while (more)
   {  if (opstack.is_empty()) error("No matching (");
    string old_op = opstack.pop();
    if (old_op == "(") more = false;
    else evaluate(numstack, old_op);
   }
  }
  else if (s == "=")
  {  while (not opstack.is_empty())
   {  string old_op = opstack.pop();
    if (old_op == "(") error("No matching )");
    else evaluate(numstack, old_op);
   }
   if (numstack.is_empty()) error("Syntax error");
   cout << numstack.pop() << "\n";
   if (not numstack.is_empty()) error("Syntax error");
  }
  else if (s == "") /* end of input */
         return 0;
  else /* must be a number */
   numstack.push(s);
 }
}

Поделяне на променливи между модули
 

Проекти