Skip to content

Bring all the basic stuff together and create a calculator

License

Notifications You must be signed in to change notification settings

dezashibi-c/b-calculator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Calculator in C

Combine basic programming concepts to create a command-line calculator.

User Story

As an aspiring C programmer, I want to implement a command-line calculator tool to assist with various calculations as described below.

  • General usage: ./calc <command> <argument(s)>.
  • Possible commands are:
    • add : Add all the arguments together.
    • sub : Subtract all the arguments from each other.
    • mul : Multiply all the arguments together.
    • div : Divide all the arguments by each other.
    • f : Load instructions from a file, perform the calculations, and display the results on the screen.

Example of file input for the f command

input.clc

sub 1 2 3 4     4


add 5 6 7
mul 23 44

NOTE: Each line's result will be used as the first parameter of the next line, and the result of the last line will be printed out on the screen.

Project Structure

  • Use a multiple file structure with a proper Makefile.
  • The Makefile uses 3 different folder for better file organization.
    • src for source files
    • obj for object files
    • build for executables and build artifact
    • as always I've used .exe only for making the Makefile work easier on windows too.

Implementation Phases

Phase 1

I would like to implement this program using command pattern, by first looking at the problem I could see the repetitive form of command, + 1 2 3 is same as f file.clc as the first token is the command and the rest is argument(s).

Each command must be a structure with the following members, I would call it Command type:

  • char* for command name or command for short
  • char* for command help or help for short
  • invoke which is a function pointer to the definition of a function accepting int argc, char* argv[] and returning int

I would also define all the commands in a static commands array that holds a couple of Commands.

Phase 2

I have refactored all the codes to commands.h, commands.c and colors.h.

I also have created various macros to make my programming easier but I haven't forget to add comments for them!

At this phase all the main operations are finished

Phase 3 - Loading from file

I would like to load the text file line by line and create a fake argc, argv and run the process for each line, getting the result and add it at the top of the next line parameter lists.

I might need to change the invoker functions implementations to return actual result and manage failures using exit function instead.

To have access to pointer to commands and command_size I've added these arguments to invoke field and also the the def_invoke_fn_as macro.

Phase 4 - clean ups and review the code

At this moment the code is working and finished and I would like to take a break and then review the code and make some improvements

The result for the input below (input.clc):

sub 1 2 3 4     4


add 5 6 7
mul 23 44

Is:

CLI Calculator
Processing calculations from 'input.clc':
line 1) 1.00 - 2.00 - 3.00 - 4.00 - 4.00 = -12.00
line 2) -12.00 + 5.00 + 6.00 + 7.00 = 6.00
line 3) 6.00 x 23.00 x 44.00 = 6072.00

result is made running make run_input or ./build/calc.exe f input.clc manually.

Memory Management

One of the most obvious parts which needs memory management is the f command.

If you go through commits you could see at first to just make things work I went through a naive way of using malloc/free in each iteration. Then soon I thought "well, that's not good, memory allocation/de-allocation is expensive", so I've decided to pre-allocate a space in memory as a preserved one-time memory allocation and re-use it over and over and free it all only once I'm done with memory at the end.

Now I'm thinking even this can be removed, what if I have a 2 dimensional array for tokens per line, then I don't even need to allocate memory as I know I'm dealing with limited amount of tokens and characters per token in each line. The problem is that then I need to have fixed amount of temp_args all over the code definitions.

So I think with this problem I'm gonna keep the second approach.

UPDATE: The third method worked as expected, here is the breakdown of what happened in the code and why?

First of all, when you know why and how your program is written and must be used always apply limitations, never scared of telling your users there are limitations because there are!.

In the other hand, we're no longer living in Commodore 64 era, meaning we do have enough memory, trust me we do.

So, combined together, what we can do is to have a preserved array say for each line which can have 52 tokens that its first token is a dummy token we need to make things work in a generic way (a place holder for the executable name) the second one is the command name (version, add, sub, mul, div and f) and the rest are the arguments (numbers or file name) to the command. we can also limit the number of character per token as we already know the maximum number of characters might be for the executable path based on how user calls it, then version command and the rest are 3 to 4 characters plus null terminator character '\0'.

So I could came up with this:

#define MAX_TOK_PER_LINE 52
#define MAX_TOK_SIZE 50
#define MAX_LINE_SIZE (MAX_TOK_PER_LINE * MAX_TOK_SIZE)

You might want to change them, go ahead, that's no problem.

I've also added some size checking with proper error messages as well and refactored them into two function macros (check_argc_size and check_token_size). They are pretty much straight forward and self-explanatory.

License

Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0) License.

Please refer to LICENSE file.

About

Bring all the basic stuff together and create a calculator

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published