Alphanumeric Calculator: The Source
Posted 10-01-2021 at 07:28 PM by astrogeek
Updated 10-12-2021 at 11:52 AM by astrogeek (Test cases, rearrange page)
Updated 10-12-2021 at 11:52 AM by astrogeek (Test cases, rearrange page)
Alphanumeric Calculator: The Source
To make it easy to find the source code I have moved the links to the top, along with links to test cases for my code and your build! You will find a brief discussion of the origins of this project below, as well as instructions for building and running the program.
The Source Code
Two source files and a Makefile are all that is required to build this project. Follow each of the links below to copy/paste the source into files with the indicated names in a single directory on your local machine.
Makefile
alphacalc.l - Flex lexer specification source
alphacalc.y - GNU Bison parser specification source (includes application C source)
Test Cases: Sign
Test Cases: Limits
Test Cases: Associativity and Precedence
Test Cases: Optional "and" Handling
Test Cases: Multi-line Input
OK! So what is this all about anyway?
This project is not about the "clever program I wrote"©. Nor is it yet another example of, "Look! More free code!".
This little project is all about the confluence of clever and powerful ideas which come together to make such programs as this example so ordinary, and the enjoyment of discovering and exploring those ideas for ourselves and sharing the experience with others!
The origin, or source of this project was my own far from satisfying first encounters with Lex and YACC in the distant past. At the time I realized that the source of that dissatisfaction (dumbfounded frustration might be a better choice of words) was actually my own lack of understanding of what Lex and YACC provided, the development of the ideas behind them, and how to use both the ideas and the applications derived from them to accomplish some useful task!
As a formal subject this was mostly new territory for me, so I began by reading about the ideas behind tokenizing, lexical analysis, parsing, syntactic analysis, semantic analysis... and a great many other terms I first encountered along the way! Somewhat unexpectedly, I found it all very interesting and continued that research long after my immediate needs had been met! I'll list a few of what I think are the best references on the topic at the end of this post.
As my knowledge of the various subjects and their actual scope initially grew I set the goal of writing my own example parsing project from the ground up, from my own acquired understanding of those first principles not based on any of the examples I encountered along the way. At the time I thought that writing a calculator which communicated through words instead of numbers and math symbols would provide a target of sufficient scope - and it certainly did!
Although it looks simple in retrospect, writing each of the required parts from scratch proved to be an enjoyable and rich source of new understanding, with many "Aha!" moments. It has been an idea to which I have returned several times over the years!
My early code was built around C's strtok() and strtok_r() functions as the basis of my lexer, and various attempts to write a recursive descent parser which might actually implement my (poorly understood) grammars! Although limited and usually incomplete, those exercises were very effective at expanding my own understanding of and ability to work with the underlying ideas, which was the real point. By the time I returned to Lex and YACC (now replaced by Flex and GNU Bison respectively on most platforms) I had a much better understanding of what they actually provided, and how to make more effective use of them.
While moving my older code archives onto a new machine recently, I had a fresh look at my old exercises and realized that I had never actually built a "finished" version, so I thought I'd do the whole exercise again with yet another new grammar, current Flex, Bison and C versions, and extended range of operation, to hopefully end with a more finished application. I recalled the fun of discovery it had always provided and wanted to share that with others. At the same time I wondered how others might approach the same problem, so I posted it as the Programming Challenge: English Speaking Calculator here on LQ.
This post, and the files linked above are my entry into that challenge competition.
I hope that you will find my little program interesting, but I wouldn't suggest that you use it to manage your personal finances!
Instead, I hope that it will be intersting to you in a different way, and prompt you to learn more about the important underlying ideas on which it, and pretty much all of computing as we know it, is ultimately built!
It is more about discovering the path than about arriving at some destination, enjoy your journey!
How To Build and Use
To build the application with debug and trace features built-in run make with DEBUG=1 parameter set:
To build without debug and trace options simply:
You may read input from a file by invoking the program with the name of the file, for example:
Or run in interactive mode:
To make it easy to find the source code I have moved the links to the top, along with links to test cases for my code and your build! You will find a brief discussion of the origins of this project below, as well as instructions for building and running the program.
The Source Code
Two source files and a Makefile are all that is required to build this project. Follow each of the links below to copy/paste the source into files with the indicated names in a single directory on your local machine.
Makefile
alphacalc.l - Flex lexer specification source
alphacalc.y - GNU Bison parser specification source (includes application C source)
Test Cases: Sign
Test Cases: Limits
Test Cases: Associativity and Precedence
Test Cases: Optional "and" Handling
Test Cases: Multi-line Input
OK! So what is this all about anyway?
This project is not about the "clever program I wrote"©. Nor is it yet another example of, "Look! More free code!".
This little project is all about the confluence of clever and powerful ideas which come together to make such programs as this example so ordinary, and the enjoyment of discovering and exploring those ideas for ourselves and sharing the experience with others!
The origin, or source of this project was my own far from satisfying first encounters with Lex and YACC in the distant past. At the time I realized that the source of that dissatisfaction (dumbfounded frustration might be a better choice of words) was actually my own lack of understanding of what Lex and YACC provided, the development of the ideas behind them, and how to use both the ideas and the applications derived from them to accomplish some useful task!
As a formal subject this was mostly new territory for me, so I began by reading about the ideas behind tokenizing, lexical analysis, parsing, syntactic analysis, semantic analysis... and a great many other terms I first encountered along the way! Somewhat unexpectedly, I found it all very interesting and continued that research long after my immediate needs had been met! I'll list a few of what I think are the best references on the topic at the end of this post.
As my knowledge of the various subjects and their actual scope initially grew I set the goal of writing my own example parsing project from the ground up, from my own acquired understanding of those first principles not based on any of the examples I encountered along the way. At the time I thought that writing a calculator which communicated through words instead of numbers and math symbols would provide a target of sufficient scope - and it certainly did!
Although it looks simple in retrospect, writing each of the required parts from scratch proved to be an enjoyable and rich source of new understanding, with many "Aha!" moments. It has been an idea to which I have returned several times over the years!
My early code was built around C's strtok() and strtok_r() functions as the basis of my lexer, and various attempts to write a recursive descent parser which might actually implement my (poorly understood) grammars! Although limited and usually incomplete, those exercises were very effective at expanding my own understanding of and ability to work with the underlying ideas, which was the real point. By the time I returned to Lex and YACC (now replaced by Flex and GNU Bison respectively on most platforms) I had a much better understanding of what they actually provided, and how to make more effective use of them.
While moving my older code archives onto a new machine recently, I had a fresh look at my old exercises and realized that I had never actually built a "finished" version, so I thought I'd do the whole exercise again with yet another new grammar, current Flex, Bison and C versions, and extended range of operation, to hopefully end with a more finished application. I recalled the fun of discovery it had always provided and wanted to share that with others. At the same time I wondered how others might approach the same problem, so I posted it as the Programming Challenge: English Speaking Calculator here on LQ.
This post, and the files linked above are my entry into that challenge competition.
I hope that you will find my little program interesting, but I wouldn't suggest that you use it to manage your personal finances!
Instead, I hope that it will be intersting to you in a different way, and prompt you to learn more about the important underlying ideas on which it, and pretty much all of computing as we know it, is ultimately built!
It is more about discovering the path than about arriving at some destination, enjoy your journey!
How To Build and Use
To build the application with debug and trace features built-in run make with DEBUG=1 parameter set:
Code:
make DEBUG=1 or make DEBUG=1 alphacalc
Code:
make or make alphacalc
Code:
$ cat example /* A few example expressions */ seven times ( thirty three plus negative eighty eight over four) eleven hundred and twenty minus ninety six $ ./alphacalc example seventy seven one thousand and twenty four
Code:
$ ./alphacalc >Type help for runtime reference info >help Input Expression Syntax Integer expressions in the range +/-999999999999 may be entered as words or numbers Number names: positive, negative, zero...nineteen, twenty...ninety, hundred, thousand, million, billion may be combined into any valid, commonly spoken numeric expression Integer values including sign must be atomic: expressed as all english words or as number, may be otherwise mixed in expressions Ex: one hundred [and] eleven thousand three hundred [and] twenty two (111322) Ex: three million [and] three over three (1000001) Ex: one hundred seven plus 3, or 107 + three, but not one hundred 7 plus 3 Arithmetic Operations and Sign plus | + addition ('+' with no trailing space is sign) minus | - subtraction ('-' with no trailing space is sign) times | * multiplication divided by | over | / division ( expression ) nested parentheses follow normal precedence rules Runtime Options alpha | numeric | both : Set output mode and : Toggles default trailing 'and' in alpha output (always follows input) debug : Toggle parser debug trace mode trace : Toggle lexer debug trace mode help : Show this help message usage : Show invocation help message (same as -h) quit : Exit program >
Total Comments 0