Program 3

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 20

CS 121

Erik Cooley
2.24.2023
Program 3

Design:
Introduction:
The purpose of this project is to convert an infix expression (i.e. 5 + 6, 7 * 4) to a postfix
expression (i.e. 5 6 +, 7 4 *). This procedure is of some significance in the computing world as
postfix expressions are considerably easier for computers to process. This procedure will be
accomplished using two ADTs, linked lists and stacks.
The four challenges this project presents are the creation of linked list and stack classes,
the input of an expression by the user, the task of error-checking this expression, and the
algorithm for converting from a correct infix expression to a postfix expression. Since the
conversion algorithm is already provided in the assignment, the hardest part of creating this
program is taken care of, leaving the implementation of the classes, the error checking, user
input, and the overall structure of the program.
Functions:
1) void postfixCalc()
This function will be in the main function to run continuously until the quit keyword is
entered. It will ask the user for input and store the input in a character linked list. It will then
use function checkValidity() to check if user input is a valid infix expression. If the
expression is valid, it will be put through the conversion algorithm. The corresponding
postfix expression will then be printed. This conversion algorithm also requires four auxiliary
functions to perform various checks: greaterPrecedent(), to determine which of two
operators is of greater precedence; isOp(), to determine whether a character is an operator;
isInt(), to determine if a function is an integer; and isPar(), to determine whether a character
is a parenthesis (which isn’t entirely necessary, but it keeps things consistent).
2) bool checkValidity( LinkedList )
This function will need to check for several types of errors: unbalanced parentheses,
double integers (“55”), double operators (“++”), double parentheses (“()” or “)(“), operators
to the right of opening parentheses (“(+”), integers to the left of opening parentheses (“5)”) or
to the right of closing parentheses (“)5”), and completely invalid characters, as well as
operators at the start and end of an expression. It will iterate through the linked list infix
expression, which will be passed in as an argument in the postfix() function, and output a
Boolean indicating whether the expression passed all tests.
3) bool greaterPrecedent( char, char )
This function will take two characters as input and compare them on the basis of operator
precedence. It will then return a Boolean value indicating whether the first operator is of
greater or equal to precedence than the second.
4) bool isInt( char ), bool isPar( char ), bool isOp( char )
These functions are extremely similar in function and execution. They will take in a
character and determine whether it fits the criterion of integer, parenthesis, or operator,
respectively. These functions will likely be used in checkValidity() and postfixCalc().
Data Structures:
1) Linked List
This class will be a basic linked list class with basic operations that allow it to support a
stack class. It will also need a function to read a value at a certain index. Luckily, I already
have a linked list class coded, so I’ll use that.
2) Stack
Only the basic functions of pushing, reading, printing, checking for emptiness, and
popping are necessary for this class in this program. I also already have a stack class built on
a linked list coded, so I only need to update that a bit.
Time Estimate:
I estimate this project will take me around seven hours to complete: one hour on the isOp(),
isPar(), isInt(), and greaterPrecedent() functions, two hours for the main postfix conversion
algorithm and user input, and four hours for the integration of the error checking function and
debugging (I think this will take a long time simply because of the number of test cases I will
have to run).
Programming Log:
Total time spent – 5.5 hours.
• 2.25.2023
Spent about an hour implementing the simple Boolean check functions and adding functions I
thought I might need to my stack class ( topNode() ).
• 2.26.2023
Spent 3 ½ hours implementing postfix conversion function (sans error checking). Tried to build a
functioning validity check function, but success is elusive. I keep getting an ambiguous error
message saying double free detected in tcache 2. I think this might be due to the passing in of a
linked list. Tomorrow I’ll try converting the linked list to a simple array before passing it into the
error function.
• 2.27.2023
Spent about an hour coding. Converted the linked list to an array and finished error-checking
algorithm. Everything runs great. Added a do/while loop to the main function to run the postfix
calculator continuously until user decides to quit.
Source Code:
1. plink.h
/*
* plink.h
*
* stands for “postfix linked list.” The p is silent.
*/

#ifndef PLINK_H
#define PLINK_H

#include <iostream>
using namespace std;

class LinkedList {
private:
struct node { // list is built of nodes
node * next; // next pointer
char info; // info in this linked list is a char
};
typedef node* nodeptr;
nodeptr head; // points to start of list
int count; // size of list
public:
// constructor
LinkedList() {
head = NULL;
count = 0;
}
// destructor
~LinkedList() {
while (head != NULL) {
nodeptr tmp = head;
head = head -> next;
delete tmp;
}
}
void addNode(char); // add node to front
void addToEnd(char); // add node to back
void deleteNode(char); // del node with some info char
char firstNode(); // return first node info
void print(); // print list
bool isInList(char); //check if node with some info is in list
int Size(); // return size of list
char readAtIndex(int); // return info of node at some index
};
#endif

2. plink.cpp
/*
* plink.cpp
*
* stands for “postfix linked list”
*/

#include "plink.h"
#include <iostream>
using namespace std;

/* add a node to front of list */


void LinkedList::addNode(char x) {
nodeptr n = new node;
n->info = x;
n->next = head;
count++;

if (head != NULL) {
head = n;
} else {
head = n;
n->next = NULL;
}
}

/* add a node to end of list */


void LinkedList::addToEnd(char x) {
nodeptr n = new node;
nodeptr p = head;
n -> info = x;
n -> next = NULL;
count++;

if (head != NULL) {
while (p -> next != NULL) {
p = p->next;
}
p -> next = n;
} else {
head = n;
}
}

/* delete a node with info x */


void LinkedList::deleteNode(char x){
nodeptr prev, curr;
curr = head;
prev = NULL;

if (head != NULL) {
do {
if (curr -> info == x) {
if (prev != NULL) {
prev -> next = curr -> next;
} else {
head = head -> next;
}
delete curr;
count--;
break;
}
prev = curr;
curr = curr->next;
} while (curr != NULL);
}
}

/* return info of first node in list */


char LinkedList::firstNode() {
if (head != NULL) {
return head -> info;
} else {
cout << "warning: no first node." << endl;
return '0';
}
}
/* print list */
void LinkedList::print() {
nodeptr p = head;
while (p != NULL) {
cout << p -> info << " ";
p = p -> next;
}
}

/* check if node with info x is in list */


bool LinkedList::isInList(char x) {
nodeptr p = head;
bool yorn = false; // yes or no (in list or no?)

while (p != NULL) {
if (p -> info == x) {
yorn = true;
}
p = p->next;
}
return yorn;
}

/* return length of list */


int LinkedList::Size() {
return count;
}

/* return info of node at position i in list */


char LinkedList::readAtIndex(int i) {
nodeptr p = head;
if ( i < count && i >= 0) {
for (int j = 0; j < i; j++) {
p = p -> next;
}
return p -> info;
} else {
cout << "error: index not contained in list" << endl;
return '\n';
}
}

3. pstack.h
/*
* pstack.h
* stands for “postfix stack”
*/

#ifndef PSTACK_H
#define PSTACK_H

#include "plink.h"
using namespace std;

class Stack {
private:
// each stack is made of a linked list
LinkedList top;
public:
// destructor
~Stack();

void push(char); // push a node to stack


char pop(); // pop top node from stack
int isEmpty(); // is the stack empty?
void print(); // print stack
char topNode(); // read top node
};

#endif

4. pstack.cpp
/*
* pstack.cpp
* stands for “postfix stack”
*/

#include "pstack.h"
#include <iostream>
using namespace std;

/* destructor */
Stack::~Stack() {
while ( !isEmpty() ) {
int n = top.firstNode();
top.deleteNode(n);
}
}

/* push node with info n to stack */


void Stack::push(char n) {
top.addNode(n);
}
/* remove top element from stack */
char Stack::pop() {
int n = top.firstNode();
if ( !isEmpty() ){
top.deleteNode(n);
}
return n;
}

/* return 1 if stack is empty */


int Stack::isEmpty() {
int n = top.Size();
if (n == 0) {
return 1;
} else {
return 0;
}
}

/* print stack info */


void Stack::print() {
top.print();
}

/* return top node of stack */


char Stack::topNode() {
return top.firstNode();
}

5. postfixCalc.cpp
/* postfixCalc.cpp
* CS 121.Bolden.............g++ on Ubuntu 9.3.0...........Erik Cooley
* 2.28.23.....HP, Intel CORE i5 7th Gen....cool9072@vandals.uidaho.edu
*
* Program takes an infix expression from the user and outputs the
* corresponding postfix expression using an algorithm which utilizes
* stacks and linked lists.
*--------------------------------------------------------------------
*/
#include <iostream>
#include "plink.h"
#include "pstack.h"

using namespace std;

void postfixCalc();

bool isInt(char);

bool isOp(char);

bool isPar(char);

bool greaterPrecedent(int, int);

bool checkValidity(char, int);

int main() {
char quit; // stores quit/continue input
do {
postfixCalc();
cout << "Press any key to quit or enter to perform another
conversion: ";
cin.get(quit);
} while (quit == '\n');

return 0;
}

/*----------checks if a character is an integer-----------*/


bool isInt(char c) {
return (c == '0' || c == '1' || c == '2' || c == '3' || c == '4'
|| c == '5' || c == '6' || c == '7' || c == '8' || c == '9');
}

/*---------checks if a character is an operator----------*/


bool isOp(char c) {
return (c == '+' || c == '-' || c == '*' || c == '/');
}

/*-----------checks if a character is a parenthesis-----------*/


bool isPar(char c) {
return (c == '(' || c == ')');
}

/*--------checks if x is of greater precedent than y-------*/


bool greaterPrecedent(int x, int y) {
bool r; // whether x is of greater precedence than y
if (x == '*' || x == '/') {
r = true;
} else if (x == '-' || x == '+') {
if (y == '*' || y == '/') {
r = false;
} else {
r = true;
}
}
return r;
}

/*---------checks the validity of an infix expression---------*/


bool checkValidity(char ex[], int size) {
Stack s; // stack for checking for balanced parentheses
bool valid = true; // is expression valid?
int counter = 0; // what character of array are we checking
char curr; // current character
char prev; // previous character, if applicable

// expression must not begin with a ) or an operation symbol


if (isOp(ex[0]) || ex[0] == ')') {
valid = false;
} else {
// iterate through expression
while (counter < size && valid) {

// set current and previous characters


curr = ex[counter];
if (counter > 0) {
prev = ex[counter - 1];
}
// if the current is a parenthesis, perform balancing
// operation and check for other invalid formations
if (isPar(curr)) {
// balancing operation
if (curr == '(') {
s.push(curr);
// 5( is invalid
if (isInt(prev)){
valid = false;
}
} else if (curr == ')') {
if (s.isEmpty()) {
valid = false;
} else {
valid = (s.pop() == '(');
}
// +) is invalid
if (isOp(prev)){
valid = false;
} else if (prev == '(') { // () is invalid
valid = false;
}
}
// if the current is an operator
} else if (isOp(curr)) {
// ++ is invalid
if (isOp(prev)) {
valid = false;
// operator at end of expression is invalid
} else if (counter == size – 1) {
valid = false;
}
// if the current is an integer
} else if (isInt(curr)){
// 88 is invalid
if (isInt(prev)) {
valid = false;
}
// if the current is some other character
} else {
valid = false;
}
counter++;
}
}

// valid and no leftover parentheses from balancing stack


valid = (valid && s.isEmpty());

return valid;
}

/* asks for user input, converts infix expression (if valid)


* to postfix expression
*/
void postfixCalc() {
LinkedList infix; // stores user input (infix)
LinkedList postfix; // stores function output (postfix)
Stack opstack; // operator stack for algorithm
// get input from user in form of linked list
char c; // temporarily stores user-input characters for addition
to linked list
cout << "Input: ";
while ( c != '\n' ) {
cin.get(c);
infix.addToEnd(c);
}
infix.deleteNode('\n');
infix.deleteNode('\n');

// get rid of spaces in expression


for (int i = 0; i < infix.Size(); i++) {
infix.deleteNode(' ');
}

// infix linked list is converted to an array for error checking


char infixArr[infix.Size()]; // new infix array
for (int i = 0; i < infix.Size(); i++) {
infixArr[i] = infix.readAtIndex(i);
}

// if valid, run function


if ( !checkValidity(infixArr, infix.Size()) ) {
cout << "Output: Invalid expression.\n";
} else {
int counter = 0; // index of character in infix list
char curr; // character in infix list

// conversion algorithm
infix.addToEnd(')');
opstack.push('(');

while ( !opstack.isEmpty() ) {
curr = infix.readAtIndex(counter);
if (curr == '(') {
opstack.push(curr);
} else if (isInt(curr)) {
postfix.addToEnd(curr);
} else if (curr == ')') {
char tmp;
tmp = opstack.pop();
while (tmp != '(') {
postfix.addToEnd(tmp);
tmp = opstack.pop();
}
} else if (isOp(curr)) {
while (greaterPrecedent(opstack.topNode(), curr)) {
postfix.addToEnd(opstack.pop());
}
opstack.push(curr);
}
counter++;
}

// output postfix expression


cout << "Output: ";
postfix.print();
cout << endl;
}
}
Output:
Erik Cooley | 2.28.2023 | postfixCalc

$ ./postfixCalc
Input: 3 + 4
Output: 3 4 +
Press any key to quit or enter to perform another conversion:
Input: (3 + 4)
Output: 3 4 +
Press any key to quit or enter to perform another conversion:
Input: (2 + 3) * 4
Output: 2 3 + 4 *
Press any key to quit or enter to perform another conversion:
Input: 2 + ((5) * 3)
Output: 2 5 3 * +
Press any key to quit or enter to perform another conversion:
Input: 2 * ((3 + 4 * 7) / 2 + 4)
Output: 2 3 4 7 * + 2 / 4 + *
Press any key to quit or enter to perform another conversion: q

You might also like