Gentee Programming Language > Documentation > Tutorial | Download documentation |
Example 1
Write an elementary program that parses and calculates expressions.
We define the lexem type with two fields. An element type will be stored in the id field, a value (if an element is an number) - in the dval field. To find out the information about element types, go to the define command. Besides, we take the oper array with the allowable operations as well as the priority array with their precedence. The precedence of operators affects evaluation of arithmetic expressions, for example in order to calculate the result value in the expression: 1+2*3 multiplication should precede addition.Operations in arrays are arranged in the same order as their define definitions. Null element indicates an error. Moreover, we create the assignment operator of two variables of the lexem type.
operator lexem =( lexem left right )
The getlexem function will retrieve an element of the expression from the string. Let's define whether or not an element is an operation. We start with the first symbol entered into the oper array.
ptr = expr.ptr() fornum i = 1, *oper { if oper[i] == ptr->byte { expr.del(0, 1) return lex.id = i } }
Then we check if an element is a number or not. Now we skip through the number parsing. There are two additional checking operations there. In the first case if a number contains '.', it is supposed to be a decimal point. If the point occurs later, the number parsing will be interrupted with an error. This method is used to process numbers written in the form 1E-5, 2.45E+10, 34E5. The expression xE(+|-)y defines the number x * ( calculates 10 raised to the power of y ).
if ptr->byte >= '0' && ptr->byte <= '9' { str stemp ptr++ while ptr->byte >= '0' && ptr->byte <= '9' : ptr++ if ptr->byte == '.' { ptr++ while ptr->byte >= '0' && ptr->byte <= '9' : ptr++ } if ptr->byte == 'E' || ptr->byte == 'e' ...
We specify a numeric data type of a number and assign a value to it.
result = $NUM_DOUBLE stemp.copy( expr.ptr(), ptr - expr.ptr() ) lex.dval = str2double( stemp )
The ptr variable is served as a pointer to the current character. After the element of the expression is obtained, it will be deleted from the beginning of the string. Thus, the parsing of the next element starts at the beginning of the string.
expr.del( 0, ptr - expr.ptr())
The calculate function performs parsing and calculation of an expression. It contains the calc subfunction. Instead of passing any arguments, the subfunction is used to work with the local variables defined in the calculate function. The calc subfunction deals with the number stack vals as well as with the operation stack opers. An operation is popped from the stack and applied to two values or one value (for unary minus) from the number stack. It works like this:
curoper = opers.top()->lexem if lex.id == $OPER_RPARENTH && curoper.id == $OPER_LPARENTH { opers.pop() break } elif priority[ curoper.id ] < priority[ lex.id ] : break
The next operation of the expression is stored in the lex variable. The top operation of the stack is put down in curoper. If the right parenthesis follows, we must first perform operations before the left parenthesis. If the top operation has a lower priority than the priority of the next one, we will stop calculations. For example, while performing multiplication '*' in the expression 1 + 2 * 3, the stack contains 1 2 values; as for addition +, numbers 1 and 2 can not be added, because of the higher priority of multiplication.
Now we proceed to the main part of calculations. The parsing process is carried out until the expr string is empty. We get the element with help of getlexem and stop calculations if error occurs. We push the number in the stack of values. prevlex contains the previous element, we check the sequence of two operations or values that follow one after another.
while *expr.trimspace() { getlexem( expr, lex ) if lex.id == $LEX_ERR : return $LEX_ERR elif lex.id == $NUM_DOUBLE { if prevlex == $NUM_DOUBLE || prevlex == $OPER_RPARENTH : return $LEX_ERR vals.push()->lexem = lex }
If the right parenthesis follows, we will call the calc subfunction used for calculating the expression followed by the left parenthesis and will reduce the parenth value where a number of left parentheses has been stored. We can perform the stack operations, if a new operation has a lower priority than the previous operation does; furthermore, if there is neither unary minus nor the left parenthesis. After that, we push the operation into the opers stack.
if lex.id == $OPER_RPARENTH { if !parenth || !calc() : return $LEX_ERR parenth-- } else { uint top top as opers.top()->lexem if ( top && priority[ lex.id ] <= priority[ top.id ] && lex.id != $OPER_UMINUS && lex.id != $OPER_LPARENTH ) { if !calc() : return $LEX_ERR } opers.push()->lexem = lex }
Finally, we work out the operations left in the stack, the top value in vals will be a result.
calc() if vals.top() : lex = vals.top()->lexem return lex.id
So, we request a user to input an expression into the main function and call the calculate function for the calculation. If a user presses Enter, we will exit the program.
while 1 { congetstr( "Enter a mathematical expression: ", expr ) if !*expr : break if !calculate( expr, result ) : @"There is an error in the expression\n" else : @"Result = \( result.dval )\n" }
![]() |
![]() Copyright © 2004-2006 Gentee Inc. All rights reserved. ![]() |