PowerBuilder expressions support user-defined variables
Zhang Junfei, Hunan Post and Telecommunications Technology Center, Tan Fei
---- In some application development, it is necessary to process the expression of the end user input. In general, the program developer needs to use the lexical analysis in the compilation principle, grammar analysis and semantic analysis technique, scan the user input symbol string and calculate the value of the expression with the explanation. The Describe function provided by PowerBuilder has powerful expressive analysis capabilities to provide strong support for user expressions. However, the Describe function does not support user-defined variables, which do not provide specific error reasons and error locations for syntax errors. This article gives a solution in practical applications for reference in other developers with this needs.
---- In a budget preparation software development process using PowerBuilder as a development tool, the user makes such a requirement: When the user enters an expression, the system can automatically calculate its value, and the expression can contain functions, user-defined Variables and comments, etc.
---- Shape like: "π / 4 * (D2-D2) {Note: Ring area} sin (XYZ {Custom Variable XYZ Demand}) - [ROW%] {Custom Variable ROW% No need solution}". In the face of such a complex expression how to solve it.
---- PowerBuilder unique data window function is powerful, and provides a rich data window function, and solving this complex expression is to be implemented using the DESCRIBE () data window function.
---- Describe () function is typically used to obtain the attribute values of the data window object attribute values and the individual objects in the data window object. But it still has a function - calculating expression. It can calculate the value of the specified line or column, return the result. Its syntax format is: dwcontrol.describe (Evaluate ('expression', line number)). For example, use the Describe function to calculate the value of the third line Salry field in the data window, whether the value of Salry is greater than 100000 to determine the return value is 255 or 0.
Ls_ret = dw_1.describe ("Evaluate
('IF (Salary> 100000, 255, 0)', 3) ")
---- Special, if the specified line number is 0, only the value of the expression is returned, regardless of its own line.
---- But this function can only calculate only a simple expression that only numb, operators, and functions. If you use it to make custom expressions, you must perform the necessary filtration, replacement, etc. Pretreatment.
---- Custom expression solve theory is the process of a lexical analysis. That is, the input string is analyzed, distinguishes the variables, functions, constants, operators, and retain words. The replacement variable is then calculated.
---- Or in shape: "π / 4 * (d2 -d2) {Note: ring area} sin (xyz {custom variable XYZ demand}) - [ROW%] {Custom Variable ROW% Exquisite} "The expression is an example.
---- Assuming the legal form of custom variables in the expression is: starting with letters and numbers. Note in the expression is accommodated, such as braces {}.
---- Solving work first by three-step pretreatment (separately using space f_skip_space () in the expression, the expression f_trim_notes (), syntax analysis and variable replacement f_PARSE_EXPRESS () three functions are completed, Then call the DESCRIBE function to evaluate the expression that does not contain user-defined variables after the transformation.
---- f_skip_space (): The entrance is the original string, returns a new string of spaces and other invisible characters.
---- The function body reads the character one by one by one cycle, and adds the ASC value greater than 32 to a variable of a String type. The variable is accommodated after the variable is completed. The new string of the space is removed.
---- f_trim_notes (): The entrance is a new string that removes the space, returns the new string after comment.
---- The initial hierarchical LI_LEVEL initial value is 0 in the function body, using a loop scanning input string, once the '{' is li_level plus one; if you encounter '}', li_level minus one; if li_level = 0 Add this character to a variable of a String type. If there is a case where Li_LEVEL <1 is in the cyclic body, or after the end of the cycle, it means that the cord procedure does not match, and the prompt should be given, and the analysis is aborted. After the cycle is normal, the value of the variable is the new string after removing the comment. ---- f_PARSE_EXPRESSION (): This function is the main part of the expression analysis. Space and annotations have been removed in the above two steps. This function is to determine if the expression is legal, including whether the left and right parenthesis match, whether the operator position is correct, whether the function name is correct. At the same time, to obtain the value of the user-defined variable to the corresponding variable table, replace the variable. Form the final only combination of functions, operators, deviations, numbers, return to the DESCRIBE () function calculation.
---- This function can contain three entry parameters: as_exp receiving the two processing expressions; as_reserved receives variables that do not need to be replaced, such as column name, etc., use [a] [b] form; Al_Flag decision See which database table finds the variable value. The third parameter is mainly from a versatility perspective, and if only one table of custom variables can only be defined.
---- The function body is used in some judgments, which can be implemented in some functions. For example, if a character is a valid character (AZ or AZ), it is determined whether a character is an operator (' ', '-', '*', '/', '^'), determined whether a character is For numbers (0-9), it is determined whether a character is a reserved word ('[int] [sin] [cos] [TAN] [LOG] [Logten] [EXP] [PI] [Fact] [ABS] [SIGN ] [SQRT] '), etc.
---- The function body is mainly determined by a (if_else_endif) condition (IF_ELSE_ENDIF) condition, and then nested one (Do WHILE) inner layer loops plus some judgment composition. The condition of the outer cycle is to assume that a pointer begins in order from the first character of the expression until the last character is pointing. If the current pointer points to a number or parentheses, it is accumulated to a String type variable ls_result, and the left and right brackets add 1 or minus 1 or minus 1 to indicate the nested hierarch of parentheses. If the current pointer points to a character, read the character string to a string of the character in the inner layer to a String type variable LS_IDENTIFIER, while moving the pointer back until the operator, the virtual character or the expression end value The cycle ends. Saved in LS_IDENTIFIER is a variable name or function name. Remove the next character, if it is '(', then saved in ls_identifer should be a function name, and check if it is a legal reserved word; if not '(', if there is any variable in As_ReServer, if there is Do not need to explain (such as the column name of the data window), retention the identifier directly, add it to the LS_RESULT, if you need to explain, then extract the corresponding value according to Al_Flag to different database tables, and determine the results according to the results (if Empty, value 0) Add to LS_RESULT. After the outer cycle is completed, whether or not the value of li_level is 0 to determine whether the brackets in the expression match.
--- Finally, such as normal end returns the result string ls_result, that is, a simple string containing only numbers, operators, functions, column names, can be calculated by the describe () function.