| ECE291 | Computer Engineering II | Kalbarczyk, Fall 1999 |
| Purpose | User I/O, Parsing algorithms |
| Points | 50 |
| Due Date | Tuesday 10/5/99 5:00 |
Calculators have been one of the greatest gifts to the engineer this century. They eliminated the tedious work of calculating numerical results. The implimentations of various calculators have varied in order to solve the problem of correctly making calculations with a minimal effort to both the user and designer of the calculator.
In order to make the calculator more intuitive to use, the infix notation is used. This is the "normal" way that we are all used to seeing algebraic equations. The infix notation of a mathematical expression is a notation in which operators are placed between the operands that they operate on. This is in contrast to prefix or postfix notation in which all operators appear before or after the operands respectively.
Below is an example of how the equation 1 + 1 would look in prefix, infix, and postfix notations.
| Prefix | Infix | Postfix |
| + 1 1 | 1 + 1 | 1 1 + |
The infix notation is what most people are taught in grammar school, however it is difficult to impliment this on a computer since you must know what each of the operands are before you can perform an operation. In addition, the order of precidence of the operations makes it difficult to determine which operations should be performed first.
In this MP, you will write an infix calculator that must to conquer these problems.
The solution code for this MP is capable of performing a great many functions. Your program will only be required to impliment a subset of these operations. There are a few basic required functions of your program. In addition, you will have to choose from a number of extra functions to give your calculator. These more advaced functions appear in italics throughout this writeup.
When calculations are performed it is important to obser the order of precidence. For a example, operations in the innermost set of parenthesis have the highest precidence, follwed by multiplication and division calculated from left to right, which is then followed by addiditon and subtraction which is also calculated from left to right.
| Operator | Type |
| - ~ |
unary minus (negation) unary bitwise NOT |
| ! | unary factorial |
| * / % |
multiplication division modulus |
| + - |
addition subtraction |
| < > |
bitwise shift left bitwise shift right |
| & | bitwise AND |
| ^ | bitwise XOR |
| | | bitwise OR |
| () [] {} |
parentheses brackets braces |
The operations that are listed first on the table have the highest precidence. All operations that are in the same table row have equal precidence and depend upon the order in which they appear. For the unary minus, and unary bitwise NOT operations, operations are performed from right to left. For all other operators, operations are performed left to right.
Note that even though you sould normally consider parentheses to have the highest precidence, they will be calculated last. This is to ensure that all operations within parentheses are calculated before the parentheses itself is evaluated.
The task of solving an equation is a difficult one. The following algorithm will allow your program to solve any algebraic equation.
A careful discussion of each of these steps is written below.
Often we take for granted how input is entered into programs. This can be a difficult process to program in assembly. Your program must only accept those characters found the the accept string. Upon any other entry, the computer should beep. While your program should accept line feeds, it must ignore them to allow input from a file. In addition, you must allow backspacing, but you must make sure that the buffer is never overflowed, or underflowed. After a carriage return is entered, a '$' should be added to the end of the string to identify it.
The program should exit if the input string was left empty, or if the escape key was pressed. The input procedure will not however exit the program by itself. Instead, the input procedure will set the carry flag, which will be used as a signal for main to exit. To prevent the program from quitting in other cases, the carry flag should be cleared.
If your implimentation is unable to handle any of the inputs that are within the accept string, you should remove those characters from the string, and decrease the constant NUMACCEPT accordingly.
It is important that all of the parentheses match correctly. This means that each open parentheses must have a matching closed parenteses. The following are several examples of input.
1 + 1 OK (1 + 1) OK (1) + (1) OK ((((1)))) OK 1 + (1 + 1 No matching closed parentheses )1 + 1( No mathcin open parenteses and no matching closed parentheses (1 + 1 No matching closed parentheses 1 + 1) No matching open parentheses
Since it is difficult for the computer to perform mathematical operations on ASCII numbers, it is necessary to parse the string, or convert it into a more useable form. When parsing the string, each byte is individually examined and manipulated.
If it is determined that the byte being examined is an operator, then that operator is stored directly into the control string.
If it is a number, then the constant STARTNUM should be placed into the control string, followed by the word sized binary equivalent for the number, followed by the constant ENDNUM.
If the byte being examined is a space, it should be ignored.
Parsing should end when a '$' has been found in the input string, and a ENDSTR character should be placed at the end of the control string.
Several examples of how input is parsed are shown below. For these examples, STARTNUM is displayed as a 'N', ENDNUM is displayed as 'n' and ENDSTR is shown as '$'. You should however use the defined constants in your code. Also note that numbers have been written in hex in the little endian format of the x86.
An example of how number and operators are parsed, the equation 1*1 would be parsed as the following string of bytes in the control string:
| 'N' | 01h | 00h | 'n' | '*' | 'N' | 01h | 00h | 'n' | '$' |
The equation (1 + 1) would be parsed as the following string of bytes in the control string:
| '(' | 'N' | 01h | 00h | 'n' | '+' | 'N' | 01h | 00h | 'n' | ')' | '$' |
A minus sign can be difficult to handle. In general, your program may assume that whenever a '-' is immediately followed by a digit, there is a negative number, and whenever a '-' is immediately followed by anything other than a digit, it is a binary subtraction.
As an example the equation 2 - -1 should be parsed into the following string of bytes:
| 'N' | 02h | 00h | 'n' | '-' | 'N' | FFh | FFh | 'n' | '$' |
As you can see, since the first minus sign was immediately followed by a space, it was treated as the subtraction operation. The second minus sign however was immediately followed by an ASCII digit, so it was trated as a negation. The only time your code should interpret a number as being negative is if it is followed by an ASCII digit.
As the input string is parsed, it is also checked that it follows certain rules. In general, numbers are followed by operators and operators are followed by numbers. Also, the equation should start and end with a number.
Parentheses are special operators which must be delt with seperately. In general, since everything inside of a pair of parentheses will be evaluated to a single number, an open parentheses may be treated externally as the start of a number, and a closed parentheses may be treated externally as the end of a number.
The following is a list of rules that the input string must follow.
The rules above work only for the basic operations that your program may perform. Depending upon the extra functions that your program performs other special cases may arise, the following table describes all possible exceptions.
| Tolken | Preceded By | Followed By |
| the start of the string | -- | a number an open parentheses bitwise NOT '~' or unary negation '-' |
| a number | the start of the string open parentheses a binary operator bitwise NOT '~' or unary negation closed parentheses with implicit multiply |
a binary operator closed parentheses the end of the string factorial '!' open parentheses with implicit multiply |
| binary operators | a number closed parentheses factorial '!' |
a number open parentheses. bitwise NOT '~' or unary negation '-' |
| open parentheses | the start of the string open parentheses a binary operation bitwise NOT '~' or unary negation '-' factorial '!' with implicit multiply a number with implicit multiply closed parentheses with implicit multiply |
a number open parentheses. bitwise NOT '~' or unary negation |
| close parentheses | a number close parentheses factorial '!' |
a binary operator close parentheses the end of the string factorial '!' a number with implicit multiply open parentheses with implicit multiply |
| the end of the string | a number close parentheses factorial '!' |
-- |
| bitwise NOT '~' or unary negation '-' | the start of the string open parentheses a binary operator bitwise NOT '~' or unary negation '-' close parentheses with implicit multiplication |
a number bitwise NOT '~' or unary negation open parentheses |
| factorial '!' | a number close parentheses factorial '!' |
a binary operator the end of the string factorial '!' open parentheses with implicit multiply |
In order to impliment the complex set of rules above, a simple algorithm is needed which will successfully allow the rules to be implimented.
In general, the computer will always be expecting to see something. It will either expect to see a number, or an operation, or in some cases it doesn't care which appears next in the input string. By making this general assumption, and adding a few special cases, we can develop a simple algorithm which will perform the necessary checks, easily and painlessly.
This greatly simplifies the algorithm, but there are a number of exceptional cases that must be examined. Most noteably, parentheses have special rules that differ from other types of operations.
By carefully following these rules and exceptions, your code should be capable of verifying that a valid string has been entered. There may be other exceptions to these rules depending upon which functions your calculator handles. These exceptions are listed later in this writeup.
It can easily be determined if the string is fully simplified. If the string contains nothing except a single number, then it is fully simplified. If it contains no numbers, then there is an error that there are no operands to work with. If the string contains more than one number and no operators, then there is an error since the string is not fully simplified, and there are no operations to perform.
An innermost set of parenthese is a matching pair of parenthese that contain no other parentheses. If you scan an equation from left to right, you will notice that the first closed parentheses is part of an innermost pair. This simple observation should make it easy for you to find an innermost pair of parentheses.
The procedure FindInner, returns two values. The first output value is returned in register BX, and indicates where the open parentheses is, and the second output value is SI and when added to BX, indicates where the closed parentheses is.
One case that you may consider is when there are no parentheses left in the equation. In this case, we would like to look at the entire equation as a whole. Therefore, the program should act as if there are parentheses in the equation that start at the first position in the string, and end in the last position. For example, if you were to enter the equation 1 * 1 as shown in an above example, the findInner procedure should report that the innermost set of parenthases begins at offset 0, and ends at offset 8 .
Each operator is given a specific priority level. The operator with the highest priority has the highest precidence, and therefore should be evaluated first. There is howver the difficulty associated with operators that have equal priority. In this case, most of the operators are evaluated from left to right as they appear in the equation. Only the unary minus and bitwise NOT operators are evaluated from right to left.
Defined in the MP is a table for your program to look up the precidence of each of the operators. Each of the operators that are evaluated from left to right are given an even priority, while each of the operators that are evaluated from right to left are given an odd priority.
To find the highest priority operator, your program should scan the substring from left to right. When an operator is found, it's priority should be looked up in the priority table. This priority level and the address of theis operator should then be recorded. For operators that are evaluated from right to left, the priority of the operator should be decremented at this point so that any operators of the same type that lie to the right appear to have a higher priority. For each following operator, the operator's priority should be again looked up in the table. Only if the looked up value of the priority is greater than the previously recoded priority, should the new information is stored. This process should continue until the end of the substring is reached.
In the case that there are no operators between a set of parentheses, then the parenthses themselves must be evaluated. Therefore, the open parentheses will should be returned as the operator to be evaluated.
When solving a particular operator, the goal is to simplify the cotnrol string. The operands of the operator must be found by scanning forward and backwards in the control string. If there are two operands, then one of them must be replaced with nulls, while the other one is replaced with the results of the operation. If there is only one operand, then that operand is replaced with the results of the operation. In either case, the operator itself is replaced with NULLs. In the special case of parentheses, each of the parentheses should simply be replaced with NULLs. No operands need be evaluated.
The NULLs that are inserted into the string are placed there to indicate white space in the control string. These characters should simply be ignored or skiped over whenever they are found in the control string through the solving process.
For some of the procedures, it is necesary to scan the control string. It is important to note that the control string contains numbers, which may take on any value, as well as operators which have very specific values. It is possible that a number will contain a byte that takes on a value of an operator. For this reason, it is important that your program does skips over numbers when it is scanning the string.
In addition, NULLs may have been inserted into the string durring the solving process to indicate that a part of the equation has been simplified. To handle this, your code should always ignore NULLs when scanning the string.
You have been given for free the procedure LibDspCtrlStr. This library procedure will convert the control string to ASCII characters and display it to the screen. You may wish to insert calls to this procedure in your code to help with the debugging process. This procedure is called before each simplification of the control string.
Your program must only perform addition, subtraction, multiplication, the modulus operation and accept parentheses, as well as accept positive and negative numbers. In the above sections, meathods have been described as to how to implement these simple functions. However, you will also have to give your code your choice of the following extra functions. These functions may cause a number of exceptional cases that you will have to deal with. Some of the extra functions and their associated exceptions are described below:
(1 + 1] Parentheses type mismatch ([1 + 1)] Parentheses type mismatch
As you can see from the above examples, you may not simply be able to count the number of open and closed parentheses, as the last example would pass this test.
Instead, you will make use of the stack. Each time an open parentheses is found, you should push that value onto the stack. When a closed parentheses is found, you should pop the last value off the stack and verify that the closed parentheses that was found matches with the open parentheses that was pushed onto the stack. Since there may be errors in the input string, you must make sure that the stack is left in the same condition as when the procedure began. It is very important that you do not try to return from the procedure before poping off everything that you pushed onto the stack, and you should not pop anything off of the stack before pushing something on first.
Also, to reduce added work in the rest of the code, when checking the parentheses in the string, all open braces and open brackets should be replaced with open parentheses. Similarly, close braces and close brackets should be replaced with close parentheses. This replacement occurs in the input string when the checkParens function is called.
As an example, the equation ({[1 + 1]}) would be converted in the input string into (((1 + 1))) in the checkParens procedure. This string should then be stored into the control string as the following string of bytes:
| '(' | '(' | '(' | 'N' | 01h | 00h | 'n' | '+' | 'N' | 01h | 00h | 'n' | ')' | ')' | ')' | '$' |
Implicit multiplication is assuming that you intend to multiply the value inside of a pair of parentheses with a value adjacent to a pair of parentheses, without explicitly writing the multiplication symbol. An example of implicit multiplication is interpreting the equation 2(2) to mean 2 * 2.
Allowing for implicit parentheses changes the rules for verifying parentheses, as now the parentheses themselves may or may not be interpreted as a binary operator. the following is a list verification rules for parentheses if implicit multiplication is allowed:
When evaluating parentheses, it is necessary to search the string to determine if an implicit multiplication should be performed. If a backwards search reveals that the preceding tolken is a number then the first parentheses should be replaced by a multiply ('*'), otherwise, it should be replaced with a NULL as usual. If a forward search reveals that the following tolken is a number then the second parentheses should be replaced by a multiply ('*'), otherwise, it should be replaced by a NULL as before.
Since the factorial is a unary post-operator, it has it's own set of special rules when verifying the string.
You will also have to add the functionality of evaluating the factorial in the SolveOne procedure.
Adding the factorial also adds complexity if your program performs implicit multiplication. When evaluating an open parentheses with implicit multiplication, your program must replace the open parentheses with a multiply ('*') when it is preceded either by a number, or by a factorial. Otherwise, it should be replaced with a NULL as usual.
To impliment unary negation, additional cases must be handled when parsing the input string since a minus sign ('-') could indicate subtraction, a negative number, or unary negation. The following rules decide how a minus sign should be handled.
The fact that unary negation and the bitwise not are unary pre-operators, these operators have their own set of sepcial rules when verifying the string.
You will also have to add the functionality of evaluating these operands into the SolveOne procedure.
In addition, these two operators must be evaluated from right to left. For this reason, in the priority table, each of the operators that are evaluated from right to left have an odd priority, while each of the operators that are evaluated from left to right have an even priority. This can be used to easily lower the priority of only those operators that have an odd priority, so that the next operator with the same priority may replace it as the operator with the highest precidence.
If your program also impliments implicit multiplication, agian there is added complexity. When evaluating the closed parentheses with implicit multiplication, your program must replace the close parentheses with a multiply ('*') when it is followed by a number, or a bitwise NOT, or a unary negation. Otherwise, it should be replaced with a NULL as usual.
You may notice that the unary negation appears as a differnt symbol when using LibDspCtrlStr this is to allow us to distinguish between a unary negation of a positive number, and a negative number.
All that is needed to impliment these operations is to add the fucntions to the SolveOne procedure.
While for these functions it is only needed to add the functions to the SolveOne procedure, it is necessary to take special care when shifting by a negative number, or when shifting by large numbers whose low eight bits are zeroed out.
The intelligent handleing of the minus sign simply refers to an attempt to not cause an error. While by default, your program should always asume that if a minus sign is followed by an ASCII character that it is a negative number, a more intelligent way of dealing with this is to treat the negative number as actually subtracting a positive number. In this way the equation 1-1 where no white space was entered could be interpreted as 1 - 1 rather than 1 -1 which cannot be evaluated.
However, if a minus sign is followed by anything other than a decimal digit, your program should not try to parse this as being a negative number. For instace the equation 1*- 1 should still cause an error, as there is white space between teh minus sign and the number 1.
The follwoing shows how a sample equation in the control string would be simplified one step at a time. At each step, a single operation is performed, simplifing the equation.
After the equation (2 * ( 4 + 6 / 2)) is parsed, the following would be displayed to the screen after each step.
(2 * (4 + 6 / 2)) (2 * (4 + 3)) (2 * (7)) (2 * 7) (14) 14
The following table shows what each byte of the control string would contain after each step is performed.
| '(' | 'N' | 02h | 00h | 'n' | '*' | '(' | 'N' | 04h | 00h | 'n' | '+' | 'N' | 06h | 00h | 'n' | '/' | 'N' | 02h | 00h | 'n' | ')' | ')' | '$' |
| '(' | 'N' | 02h | 00h | 'n' | '*' | '(' | 'N' | 04h | 00h | 'n' | '+' | 'N' | 03h | 00h | 'n' | NULL | NULL | NULL | NULL | NULL | ')' | ')' | '$' |
| '(' | 'N' | 02h | 00h | 'n' | '*' | '(' | 'N' | 07h | 00h | 'n' | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | ')' | ')' | '$' |
| '(' | 'N' | 02h | 00h | 'n' | '*' | NULL | 'N' | 07h | 00h | 'n' | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | ')' | '$' |
| '(' | 'N' | 0Dh | 00h | 'n' | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | ')' | '$' |
| NULL | 'N' | 0Dh | 00h | 'n' | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | '$' |
You can see how after each operation, an operator and an operand are replaced with NULLs and an operand is replaced with the results of an operation. After the last step, the equation is found to only contain the number 14 (000Dh), which is the correct answer to the equation.
|
Please enter an equation. Hit <ESC>, or enter an empty equation to exit. -(-7*3! +4-6)~[1 | (2) < 1 & 15] % 53/{1 > -2} Verifying and parsing the string... -(-7 * 3! + 4 - 6)~(1 | (2) < 1 & 15) % 53 / (1 > -2) -(-7 * 6 + 4 - 6)~(1 | (2) < 1 & 15) % 53 / (1 > -2) -(-42 + 4 - 6)~(1 | (2) < 1 & 15) % 53 / (1 > -2) -(-38 - 6)~(1 | (2) < 1 & 15) % 53 / (1 > -2) -(-44)~(1 | (2) < 1 & 15) % 53 / (1 > -2) --44 * ~(1 | (2) < 1 & 15) % 53 / (1 > -2) --44 * ~(1 | 2 < 1 & 15) % 53 / (1 > -2) --44 * ~(1 | 4 & 15) % 53 / (1 > -2) --44 * ~(1 | 4) % 53 / (1 > -2) --44 * ~(5) % 53 / (1 > -2) --44 * ~5 % 53 / (1 > -2) --44 * ~5 % 53 / (4) --44 * ~5 % 53 / 4 --44 * -6 % 53 / 4 44 * -6 % 53 / 4 -264 % 53 / 4 -52 / 4 -13 Please enter an equation. Hit <ESC>, or enter an empty equation to exit. LIBMP2 Ver 1.0 Calls -LibInput -LibCheckParens -LibParse -LibCheckDone -LibFindInner -LibFindOne -LibSolveOne -LibGetOp1 -LibGetOp2 |
Monitor the newsgroup and this on-line section for revisions to the MP or to the writeup
TITLE MP2:Infix-Calculator Your_Name Todays_Date
.MODEL SMALL
.386
COMMENT *
In this MP, you will write a program which will take input
from the keyboard which will be parsed and solved as an
arithmatic equation
ECE291: Machine Problem 2
Prof. Zbigniew Kalbarczyk
Guest Author: Brandon Tipp
Univeristy of Illinois
Dept. of Electrical & Computer Engineering
Fall 1999
Ver 1.0
*
;====== SECTION 1: Define constants =======================================
;misc ASCII codes
BEL EQU 007h
BS EQU 008h
CR EQU 00Dh
LF EQU 00Ah
SPACE EQU 020h
ESCKEY EQU 01Bh
MAX_BUFF_LEN EQU 80 ; Bytes; limit input to one line
NUM_ACCEPT EQU 33 ; The number of acceptable characters
; Definitions for the control string
NULL EQU 00
STARTNUM EQU 78
ENDNUM EQU 110
ENDSTR EQU 36
NEGATE EQU 0C4h ; ascii for a hyphen
PUBLIC BEL, BS, CR, LF, SPACE, ESCKEY
PUBLIC MAX_BUFF_LEN, NUM_ACCEPT
PUBLIC NULL, STARTNUM, ENDNUM, ENDSTR, NEGATE
; GetOperands MACRO
; This macro may be used and edited freely. Edit this comment
; block to reflect changes
; Purpose: Get the left and right operands to an operation.
; Nullifies the right operand
; Inputs: X, the place to store the left operand (must be a register, not bp, di, si, or bx)
; Y, the place to store the right operand (must be a register, not bp, di, si, or bx)
; Ouputs: X, holds the number that was indicated by GetOp1
; Y, holds the number that was indicated by GetOp2
; The number indicated by GetOp2 is nullified from the string
; BP , the return value from GetOp1, indicating where the number is
; Notes: Performs no error checking.
GetOperands MACRO x, y
call GetOp2
mov y, word ptr controlStr[bp + 1]
mov word ptr controlStr[bp], NULL
mov word ptr controlStr[bp + 2], NULL
call GetOp1
mov x, word ptr controlStr[bp + 1]
endm
;====== SECTION 2: Declare external procedures ============================
EXTRN kbdine:near, dspout:near, dspmsg:near, binasc:near, ascbin: near
EXTRN mp2xit:near, kbdin:near
;====== Library procedures ================================================
;Free Library procedure
EXTRN LibDspCtrlStr:near
;The follwing library procedures must be replaced with your own code.
EXTRN LibInput:near
EXTRN LibCheckParens:near
EXTRN LibParse:near
EXTRN LibCheckDone:near
EXTRN LibFindInner:near
EXTRN LibFindOne:near
EXTRN LibSolveOne:near
EXTRN LibGetOp1:near
EXTRN LibGetOp2:near
;These procedures need to be public so the library may call them
PUBLIC GetOp1, GetOp2
;====== SECTION 3: Define stack segment ===================================
STKSEG SEGMENT STACK ; *** STACK SEGMENT ***
db 64 dup ('STACK ')
STKSEG ENDS
;====== SECTION 4: Define code segment ====================================
CSEG SEGMENT PUBLIC 'code' ; *** CODE SEGMENT ***
ASSUME cs:cseg, ds:cseg, ss:stkseg, es:nothing
;====== SECTION 5: Declare variables for main procedure ===================
inputBuff db MAX_BUFF_LEN dup (?), '$'
controlStr db MAX_BUFF_LEN * 3 dup (?), ENDSTR
buff db 7 dup(?)
accept db '0123456789!*/%+-(){}[] <>&|^~',BS,CR,LF,ESCKEY ; all acceptable input chars
inputMsg db CR,LF,'Please enter an equation.',CR,LF
db 'Hit , or enter an empty equation to exit.',CR,LF,'$'
parseMsg db 'Verifying and parsing the string...',CR,LF,'$'
; A lookup table of the priority of each of the operations
priority db 33 dup (0) ; control characters
db 16 ; !
db 0, 0, 0 ; ", #, $
db 14 ; %
db 8 ; &
db 0 ; '
db 2 ; (
db 0 ; )
db 14 ; *
db 12 ; +
db 0 ; ,
db 12 ; -
db 0 ; .
db 14 ; /
db 12 dup (0) ; numerals, :, ;
db 10 ; <
db 0 ; =
db 10 ; >
db 31 dup (0) ; ?, @, caps, [, \, ]
db 6 ; ^
db 29 dup (0) ; _, ', lower case letters, {
db 4 ; |
db 0 ; }
db 17 ; ~
db 69 dup (0) ; DELete, the extended charaters
db 17 ; Long dash for negate
db 59 dup (0) ; the rest of the extended characters
errMsg db BEL,'The equation was not fully simplified due to an error.',CR,LF,'$'
errMsg0 db BEL,'Type 0 error: Divide by zero.',CR,LF,'$'
errMsg1 db BEL,'Type 1 error: Parenthesis mismatch.',CR,LF,'$'
errMsg2 db BEL,'Type 2 error: Input overflow.',CR,LF,'$'
errMsg3 db BEL,'Type 3 error: Calculation overflow.',CR,LF,'$'
errMsg4 db BEL,'Type 4 error: Missing operand',CR,LF,'$'
errMsg5 db BEL,'Type 5 error: Encountered a unary operator while expecting a binary operator.',CR,LF,'$'
errMsg6 db BEL,'Type 6 error: Encountered a number while expecting a binary operator.',CR,LF,'$'
errMsg7 db BEL,'Type 7 error: Encountered a binary operator while expecting a number.',CR,LF,'$'
errMsg8 db BEL,'Type 8 error: Encountered end of string while expecting a number.',CR,LF,'$'
errMsg9 db BEL,'Type 9 error: No numbers found in control string.',CR,LF,'$'
errMsg10 db BEL,'Type 10 error: Unknown operation encountered.',CR,LF,'$'
errMsg11 db BEL,'Type 11 error: Attempting to resolve parenthesis containing too many operands.',CR,LF,'$'
errMsg12 db BEL,'Type 12 error: Cannot take the factorial of a negative number.',CR,LF,'$'
public inputBuff, controlStr
public inputMsg, parseMsg, priority, buff, accept
public inputMsg, errMsg0, errMsg1, errMsg2, errMsg3, errMsg4, errMsg5
public errMsg6, errMsg7, errMsg8, errMsg9, errMsg10, errMsg11, errMsg12
;====== SECTION 6: Procedures ============================================
;Comment your funcitons!!!
Input proc near
call LibInput ; comment this call out and replace it with your own code
ret
Input endp
;Comment your code!!!
CheckParens proc near
call LibCheckParens ; comment this call out and replace it with your own code
ret
CheckParens endp
;Comment loops in your code!!!
Parse proc near
call LibParse
ret
parse endp
;Comment the registers that are used as variables!!!
CheckDone proc near
call LibCheckDone
ret
CheckDone endp
;Comment code that is confusing!!!
FindInner proc near
call LibFindInner
ret
FindInner endp
;Don't write a comment for every line!!!
FindOne proc near
call LibFindOne
ret
FindOne endp
;Don't write paragraphs of comments!!!
SolveOne proc near
call LibSolveOne
ret
SolveOne endp
;Write your comments well!!!
GetOp1 proc near
call LibGetOp1
ret
GetOp1 endp
;When you duplicate code, don't duplicate commentes!!!
GetOp2 proc near
call LibGetOp2
ret
GetOp2 endp
MAIN PROC NEAR
mov ax, cseg ; Initialize Default Segment register
mov ds, ax
begin:
call Input
jc FinalExit ; if done, exit
mov dx, offset parseMsg
call dspmsg
call checkParens
jc Error
call Parse
jc Error ; on err, start over
solve:
call LibDspCtrlStr ; show the current state of calculation
call CheckDone
jc Error
jz begin
continue:
call kbdin ; pause before continueing
cmp al, ESCKEY
jz FinalExit
cmp al, LF
jz continue
;find and solve the operator of highest precidence
call FindInner
call FindOne
jc Error
call SolveOne
jc Error
jmp solve
Error:
mov dx, offset errMsg
call dspmsg
jmp begin
FinalExit:
call mp2xit ; Exit to DOS
MAIN ENDP
CSEG ENDS
END MAIN