Search code examples
arrayscmatrixstructrpn

Reverse Polish Notation - arrays, vectors, scalars in C


I have a big problem. My teacher told me that I must write a program. I must use reverse polish notation for operations on vectors, matrices, scalars etc. For example, when you calculate, you write 4+5-6. In RPN, you will write this, in this way 45+6-. https://www.prodevelopertutorial.com/given-an-expression-in-reverse-polish-notation-evaluate-it-and-get-the-output-in-c/ I must write output into the file and show on the screen

But my program will be much more difficult.

  1. I will not use in my calculations numbers, but vectors, scalars, matrices.
  2. I must read values from a file
  3. I must use shortcuts; V is Vector, S is Scalars, M is Matrix
  4. In additions, I must use much more operations, not only simple operations but also
+ adding
- subtraction
* multiplication
/ division
T transpose of an array
. scalar product
x vector product
D determinant
R inverse matrix

This is my data file

S scalar1 3
S scalar2 5
V vector1 3
2 4 7
V vector2 3
3 6 1
M matrix_A 3 3
1 2 3
4 5 6
7 8 9
M matrix_B 3 3
9 8 7
6 5 4
3 2 1

You see that I must create structs that have shortcut M/V/S, name of the element, dimension (dimX and Y for Matrices), and values. Later I will add in this data file operations like

matrix_A
matric_B
*

This is my file with io functions operation_io.c

#include <stdio.h>
#include <stdlib.h>
#define MAX_NAME 20
#define MAX_ARRAY_DIM 50

typedef struct Vector {
    char keyWordV;
    char name[MAX_NAME];
    int dim;
    double data[MAX_ARRAY_DIM];
} Vector;

typedef struct Scalar {
    char keyWordS;
    char name[MAX_NAME];
    double data;
} Scalar;

typedef struct Matrix {
    char keyWordM;
    char name[MAX_NAME];
    int dimX;
    int dimY;
    double data[MAX_ARRAY_DIM][MAX_ARRAY_DIM];
} Matrix;

typedef struct Element {
    char type;
    union {
        Scalar s;
        Vector v;
        Matrix m;
    } elem;
} Element;

void readScalar(FILE *file, Scalar* s) {
    fscanf(file, " %s ", &s->name[0]);
    fscanf(file, "%10lf", &s->data);
    }
    
void writeScalar(FILE *file, Scalar* s) {
    fprintf(file, "S");
    fprintf(file, " %s \n", s->name);
    fprintf(file, "%10.2lf \n", s->data);
    }

void showScalar(Scalar* s) {
    printf("S");
    printf(" %s \n", s->name);
    printf("%10.2lf \n", s->data);
    }
    
void readVector(FILE *file, Vector* v) {
    fscanf(file, " %s %d ", &v->name[0], &v->dim);
    for (int j = 0; j < v->dim; ++j) {
        fscanf(file, "%10lf", &v->data[j]);
    }
}

void writeVector(FILE *file, Vector* v) {
    fprintf(file, "V");
    fprintf(file, " %s %d \n", v->name, v->dim);
    for (int j = 0; j < v->dim; ++j) {
        fprintf(file, "%10.2lf ", v->data[j]);
    }
    fprintf(file, "\n");
}

void showVector(Vector* v) {
    printf("V");
    printf(" %s %d \n", v->name, v->dim);
    for (int j = 0; j < v->dim; ++j) {
        printf("%10.2lf ", v->data[j]);
    }
    printf("\n");
}

void readMatrix(FILE *file, Matrix* m) {
    fscanf(file, " %s %d %d", &m->name[0], &m->dimX, &m->dimY);
    for (int i = 0; i < m->dimX; ++i)
        for (int j = 0; j < m->dimY; ++j)
            fscanf(file, "%10lf", &m->data[i][j]);
}

void writeMatrix(FILE *file, Matrix* m) {
    fprintf(file, "M");
    fprintf(file, " %s %d %d \n", m->name, m->dimX, m->dimY);
    for (int i = 0; i < m->dimX; ++i) 
    {
        for (int j = 0; j < m->dimY; ++j)
        {
            fprintf(file, "%10.2lf", m->data[i][j]);
        }
        fprintf(file, "\n");
    }
}

void showMatrix(Matrix* m) {
    printf("M");
    printf(" %s %d %d \n", m->name, m->dimX, m->dimY);
    for (int i = 0; i < m->dimX; ++i)
    {
        for (int j = 0; j < m->dimY; ++j)
        {
            printf("%10.2lf", m->data[i][j]);
        }
        printf("\n");
    }
}
void readElement(FILE *file, Element* e) {
    char type;
    fscanf(file, " %c ", &type);
    switch (type) {
    case 'S':
        e->type = 'S';
        readScalar(file, &e->elem.s);
        writeScalar(file, &e->elem.s);
        showScalar(&e->elem.s);
        break;
    case 'V':
        e->type = 'V';
        readVector(file, &e->elem.v);
        writeVector(file, &e->elem.v);
        showVector(&e->elem.v);
        break;
    case 'M':
        e->type = 'M';
        readMatrix(file, &e->elem.m);
        writeMatrix(file, &e->elem.m);
        showMatrix(&e->elem.m);
        break;
    default:
        fputs("Error: unknown token!\n", stderr);
        exit(1);
    }
}

void policz(FILE *file, Element* e1, Element* e2, Element* e3)
{
    char type1, type2, type3;
    fscanf(file, " %c ", &type1);
    fscanf(file, " %c ", &type2);
    fscanf(file, " %c ", &type3);
    
}
int isOperator(char ch){
   if(ch == '+'|| ch == '-'|| ch == '*'|| ch == '/' || ch == '^')
      return 1;//character is an operator
   return -1;//not an operator
}
int isOperand(char ch){
   if(ch == 'S' || ch == 'V' || ch == 'M')
      return 1;//character is an operand
   return -1;//not an operand
}
#define MAX_D 256
double stack[MAX_D];
int depth;



void die(const char *msg)
{
    fprintf(stderr, "%s", msg);
    abort();
}
void push(double v)
{
    if (depth >= MAX_D) die("stack overflow\n");
    stack[depth++] = v;
}
 
double pop()
{
    if (!depth) die("stack underflow\n");
    return stack[--depth];
}
float operation(int a, int b, char op){ //bede dopiero pisal funkcje
   //Perform operation
   if(op == '+')
      return 1;
   else if(op == '-')
      return 1;
   else if(op == '*')
      return 1;
   else if(op == '/')
      return 1;
   else
      return 1; //return negative infinity
}

operation_io.h

#ifndef WEKTORY
#define WEKTORY

typedef struct Scalar Scalar;
typedef struct Vector Vector;
typedef struct Matrix Matrix;
typedef struct Element Element;

void readScalar(FILE *file, Scalar* s);
void writeScalar(FILE *file, Scalar* s);
void showScalar(Scalar* s);
void readVector(FILE *file, Vector* v);
void writeVector(FILE *file, Vector* v);
void showVector(Vector* v);
void readMatrix(FILE *file, Matrix* m);
void writeMatrix(FILE *file, Matrix* m);
void showMatrix(Matrix* m);
void readElement(FILE *file, Element* e);
void die(const char *msg);
void push(double v);
double pop();
float operation(int a, int b, char op);

#endif

This is my main program. main.c

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "operation_io.h"
#define MAX_NAME 20
#define MAX_ARRAY_DIM 50


typedef struct Vector {
    char keyWordV;
    char name[MAX_NAME];
    int dim;
    double data[MAX_ARRAY_DIM];
} Vector;

typedef struct Scalar {
    char keyWordS;
    char name[MAX_NAME];
    double data;
} Scalar;

typedef struct Matrix {
    char keyWordM;
    char name[MAX_NAME];
    int dimX;
    int dimY;
    double data[MAX_ARRAY_DIM][MAX_ARRAY_DIM];
} Matrix;

typedef struct Element {
    char type;
    union {
        Scalar s;
        Vector v;
        Matrix m;
    } elem;
} Element;

int main (int argc, char *argv[])
{    
    FILE *wz, *wc;  

    if (argc != 3) {                                
    printf("Wrong arguments number\n");
    printf("I should run this way:\n");
    printf("%s source\n",argv[0]);
    exit(1);
    }
    
    if( (wz= fopen(argv[1],"r")) == NULL) {
        printf("Open error %s\n", argv[1]);
        exit(1);
    }
    if( (wc= fopen(argv[2], "w")) == NULL) {
    printf("Open error %s\n", argv[2]);
    exit(2);
    }


    Element elements[10];
    for (int i = 0; i < 6; i++) {
        readElement(wz, &elements[i]);
    }
    fclose(wz);
    fclose(wz);
    
    return 0;

}

MY file with the arithmetic operation. operation_m.c is empty because I'm not started with writing these functions because I have a problem. I want to use algorithm like that https://rosettacode.org/wiki/Parsing/RPN_calculator_algorithm#C But my case is more complicated because I am not using numbers and I have more operations (not only +,-,*,=)

I have 3 problems right now

  1. My writing functions aren't working, but my functions with showing on the screen works perfect.
  2. I dont know, how my program will know that I use matrix, vector or scalar? For example I have
matrix_A
matrix_B
*

how my program will know that name matrix_A and matrix_B means the multiplication of 2 matrices and use function multMatrices() (I haven't written this functions yet, but I will). I have an Idea. I want to connect name with a shortcut. So my program will find that I want to multiplicate matrices not for example scalar and matrix. I have my objects here - array of elements

    Element elements[10];
    for (int i = 0; i < 6; i++) {
        readElement(wz, &elements[i]);
    }

so I must know how to use a proper element from this array, so how to do that?

  1. In this algorithm I dont have unary operations https://rosettacode.org/wiki/Parsing/RPN_calculator_algorithm#C but in my program I will have like transpose of matrix etc. So I must add some if in switch case probably???

Solution

    1. I dont know, how my program will know that I use matrix, vector or scalar? For example I have

      matrix_A matrix_B * how my program will know that name matrix_A and matrix_B means the multiplication of 2 matrices and use function multMatrices()

    you need a dictionary associating name (char*) to Element, because you will have very probably few definitions there is no performance problem and it is useless to use complex structures and to implement a map using hashing, or balanced tree etc.

    Then having for instance a binary operation the valid case is to have at least 2 Element pushed in the stack and you just have to check their type to decide what function to call. Note you can also use 0, 1, 2 for the type allowing to use an array of pointer to function.

    Are the type of the operand must be the same ? It may be allowed to multiply/add/divide/substract a vector/matrix by a scalar for instance, applying the operation on each cell ?

    In Vector the attribute keyWordV, in Scalar the attribute keyWordS is useless, in Matrix the attribute keyWordM is useless.

    It is also useless to have the attribute name in Vector/Scalar/Matrix, you just need to have it in Element at the same level of type (out of the union)

    To use fixed size array in Vector/Scalar/Matrix is practical but that use more memory than necessary and what you will do if a number of element is greater than MAX_ARRAY_DIM or if a name is greater than MAX_NAME ? Same for Element elements[10];.

    1. My writing functions aren't working, but my functions with showing on the screen works perfect

    how is it possible, the writeX and showX functions are exactly the same and in fact showX(x) can be defined as writeX(stdout, x)

    1. In this algorithm I dont have unary operations ...

    Frankly the reverse polish notation is so simple to implement you can do that by yourself from scratch, and doing that you will learn more ;-)

    Whatever n an nnary operator pops its n operand(s) from the stack (of course check there are at least n element else indicate the error), computes the result, then pushes the result, trivial