Algorithms_in_C 1.0.0
Set of algorithms implemented in C.
Loading...
Searching...
No Matches
shunting_yard.c File Reference

Shunting Yard Algorithm More...

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
Include dependency graph for shunting_yard.c:

Functions

int getPrecedence (char operator)
 for assertion
 
int getAssociativity (char operator)
 Helper function that returns each operator's associativity.
 
int shuntingYard (const char *input, char *output)
 An implementation of the shunting yard that converts infix notation to reversed polish notation.
 
static void test ()
 Self-test implementations.
 
int main ()
 Main function.
 

Detailed Description

Shunting Yard Algorithm

From Wikipedia: In computer science, the shunting yard algorithm is a method for parsing arithmetical or logical expressions, or a combination of both, specified in infix notation. It can produce either a postfix notation string, also known as Reverse Polish notation (RPN), or an abstract syntax tree (AST). The algorithm was invented by Edsger Dijkstra and named the "shunting yard" algorithm because its operation resembles that of a railroad shunting yard.

Author
CascadingCascade

Function Documentation

◆ getAssociativity()

int getAssociativity ( char  operator)

Helper function that returns each operator's associativity.

Parameters
operatorthe operator to be queried
Returns
'1' if the operator is left associative
'0' if the operator is right associative
48 {
49 switch (operator) {
50 case '^': {
51 return 0;
52 }
53 case '+':
54 case '-':
55 case '*':
56 case '/': {
57 return 1;
58 }
59 default: {
60 fprintf(stderr,"Error: Invalid operator\n");
61 return -1;
62 }
63 }
64}

◆ getPrecedence()

int getPrecedence ( char  operator)

for assertion

for IO operations for memory management for string operations for isdigit()

Helper function that returns each operator's precedence

Parameters
operatorthe operator to be queried
Returns
the operator's precedence
22 {
23 switch (operator) {
24 case '+':
25 case '-': {
26 return 1;
27 }
28 case '*':
29 case '/': {
30 return 2;
31 }
32 case '^': {
33 return 3;
34 }
35 default:{
36 fprintf(stderr,"Error: Invalid operator\n");
37 return -1;
38 }
39 }
40}

◆ main()

int main ( void  )

Main function.

Returns
0 on exit
235 {
236 test(); // Run self-test implementations
237 return 0;
238}
static void test()
Self-test implementations.
Definition shunting_yard.c:205
Here is the call graph for this function:

◆ shuntingYard()

int shuntingYard ( const char *  input,
char *  output 
)

An implementation of the shunting yard that converts infix notation to reversed polish notation.

Parameters
inputpointer to input string
outputpointer to output location
Returns
1 if a parentheses mismatch is detected
0 if no mismatches are detected
73 {
74 const unsigned int inputLength = strlen(input);
75 char* operatorStack = (char*) malloc(sizeof(char) * inputLength);
76
77 // This pointer points at where we should insert the next element,
78 // Hence stackPointer - 1 is used when accessing elements
79 unsigned int stackPointer = 0;
80
81 // We will parse the input with strtok(),
82 // Since strtok() is destructive, we make a copy of the input to preserve the original string
83 char* str = malloc(sizeof(char) * inputLength + 1);
84 strcpy(str,input);
85 char* token = strtok(str," ");
86
87 // We will push to output with strcat() and strncat(),
88 // This initializes output to be a string with a length of zero
89 output[0] = '\0';
90
91 while (token != NULL) {
92 // If it's a number, push it to the output directly
93 if (isdigit(token[0])) {
94 strcat(output,token);
95 strcat(output," ");
96
97 token = strtok(NULL," ");
98 continue;
99 }
100
101 switch (token[0]) {
102 // If it's a left parenthesis, push it to the operator stack for later matching
103 case '(': {
104 operatorStack[stackPointer++] = token[0];
105 break;
106 }
107
108 // If it's a right parenthesis, search for a left parenthesis to match it
109 case ')': {
110 // Guard statement against accessing an empty stack
111 if(stackPointer < 1) {
112 fprintf(stderr,"Error: Mismatched parentheses\n");
113 free(operatorStack);
114 free(str);
115 return 1;
116 }
117
118 while (operatorStack[stackPointer - 1] != '(') {
119 // strncat() with a count of 1 is used to append characters to output
120 const unsigned int i = (stackPointer--) - 1;
121 strncat(output, &operatorStack[i], 1);
122 strcat(output," ");
123
124 // If the operator stack is exhausted before a match can be found,
125 // There must be a mismatch
126 if(stackPointer == 0) {
127 fprintf(stderr,"Error: Mismatched parentheses\n");
128 free(operatorStack);
129 free(str);
130 return 1;
131 }
132 }
133
134 // Discards the parentheses now the matching is complete,
135 // Simply remove the left parenthesis from the stack is enough,
136 // Since the right parenthesis didn't enter the stack in the first place
137 stackPointer--;
138 break;
139 }
140
141 // If it's an operator(o1), we compare it to whatever is at the top of the operator stack(o2)
142 default: {
143 // Places the operator into the stack directly if it's empty
144 if(stackPointer < 1) {
145 operatorStack[stackPointer++] = token[0];
146 break;
147 }
148
149 // We need to check if there's actually a valid operator at the top of the stack
150 if((stackPointer - 1 > 0) && operatorStack[stackPointer - 1] != '(') {
151 const int precedence1 = getPrecedence(token[0]);
152 const int precedence2 = getPrecedence(operatorStack[stackPointer - 1]);
153 const int associativity = getAssociativity(token[0]);
154
155 // We pop operators from the stack, if...
156 while ( // ... their precedences are equal, and o1 is left associative, ...
157 ((associativity && precedence1 == precedence2) ||
158 // ... or o2 simply have a higher precedence, ...
159 precedence2 > precedence1) &&
160 // ... and there are still operators available to be popped.
161 ((stackPointer - 1 > 0) && operatorStack[stackPointer - 1] != '(')) {
162
163 strncat(output,&operatorStack[(stackPointer--) - 1],1);
164 strcat(output," ");
165 }
166 }
167
168 // We'll save o1 for later
169 operatorStack[stackPointer++] = token[0];
170 break;
171 }
172 }
173
174 token = strtok(NULL," ");
175 }
176
177 free(str);
178
179 // Now all input has been exhausted,
180 // Pop everything from the operator stack, then push them to the output
181 while (stackPointer > 0) {
182 // If there are still leftover left parentheses in the stack,
183 // There must be a mismatch
184 if(operatorStack[stackPointer - 1] == '(') {
185 fprintf(stderr,"Error: Mismatched parentheses\n");
186 free(operatorStack);
187 return 1;
188 }
189
190 const unsigned int i = (stackPointer--) - 1;
191 strncat(output, &operatorStack[i], 1);
192 if (i != 0) {
193 strcat(output," ");
194 }
195 }
196
197 free(operatorStack);
198 return 0;
199}
#define malloc(bytes)
This macro replace the standard malloc function with malloc_dbg.
Definition malloc_dbg.h:18
#define free(ptr)
This macro replace the standard free function with free_dbg.
Definition malloc_dbg.h:26
int getPrecedence(char operator)
for assertion
Definition shunting_yard.c:22
int getAssociativity(char operator)
Helper function that returns each operator's associativity.
Definition shunting_yard.c:48
Here is the call graph for this function:

◆ test()

static void test ( void  )
static

Self-test implementations.

Returns
void
205 {
206 char* in = malloc(sizeof(char) * 50);
207 char* out = malloc(sizeof(char) * 50);
208 int i;
209
210 strcpy(in,"3 + 4 * ( 2 - 1 )");
211 printf("Infix: %s\n",in);
212 i = shuntingYard(in, out);
213 printf("RPN: %s\n",out);
214 printf("Return code: %d\n\n",i);
215 assert(strcmp(out,"3 4 2 1 - * +") == 0);
216 assert(i == 0);
217
218 strcpy(in,"3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3");
219 printf("Infix: %s\n",in);
220 i = shuntingYard(in, out);
221 printf("RPN: %s\n",out);
222 printf("Return code: %d\n\n",i);
223 assert(strcmp(out,"3 4 2 * 1 5 - 2 3 ^ ^ / +") == 0);
224 assert(i == 0);
225
226 printf("Testing successfully completed!\n");
227 free(in);
228 free(out);
229}
int shuntingYard(const char *input, char *output)
An implementation of the shunting yard that converts infix notation to reversed polish notation.
Definition shunting_yard.c:73
Here is the call graph for this function: