Convert infix expressions to prefix expressions (lisp implementation)

Use the three functions weight, opcode and infix_to_prefix to realize the conversion from infix expression to prefix expression.

Operator precedence function weight

First define the function weight, which returns the priority (priority) of an arithmetic operator (which can be referred to as an operator for short).

;确定算符的优先权
(defun weight (operator) 
	(cond 
		((equal operator 'dummy) -1) ;运算符号表的开始标记
		((equal operator '=) 0)  ;等于号
		((equal operator '+) 1)	;加号
		((equal operator '-) 1)	;减号
		((equal operator '*) 2)	;乘号
		((equal operator '/) 2);除号
		((equal operator '\\) 2);求余运算符
		((equal operator '^) 3) ;指数运算符
		(t (print (list operator 'not 'an 'operator)) 'nop)
	)
)

In some implementations of LISP, the backslash "/" indicates special treatment for the next character, such as preventing spaces from being interpreted as separators, so double backslashes "\\" are used in the above functions to represent single characters equivalently. Slash "\".

The dummy operator dummy in the above function is used to mark the beginning of the operator list.

Operator to opcode conversion function opcode

Defines the operator-to-opcode conversion function opcode.

;计算与operator对应的lisp函数名.
(defun opcode (operator) 
	(cond
		((equal operator 'dummy)
			(print 'hit-dummy) 
			'dummy
		)
		((equal operator '=) 'setq)
		((equal operator '+) 'plus)
		((equal operator '-) 'difference)
		((equal operator '*) 'times)
		((equal operator '/) 'quotient)
		((equal operator '\\ ) 'remainder)
		((equal operator '^) 'expt)
		(t (print (list operator 'not 'an 'operator)) 'nop)
	)
)

The function infix_to_prefix converts an infix expression to a prefix expression

There are many ways to convert from one form to another, and a linear scanning method from left to right is used here. Among them, operands and operators not yet used to produce output are kept in the table. The infix_to_prefix function uses operands and operators to store operands and operators (operators) respectively.

;将算术表达式由中缀形式变为前缀形式
(defun infix_to_prefix (ae)
	(prog (operands operators) ;操作数表和运算符表
		(cond((atom ae) (return ae))) ;特殊情况,只有一个操作数
		(setq operators (list 'dummy)) ;虚拟终结符
		stuff ;寻找操作数
			(cond
				((null ae) 扫描操作数,以运算符结尾
					(return 'unexpected-end)
				)
			) 
			;递归
			(setq 
				operands ;操作数入栈
					(cons 
						(cond 
							((atom (car ae)) (car ae)) 
							(t (infix_to_prefix (car ae)))
						)
						operands
					)	;设置operands
				ae (cdr ae) ;删除操作数,设置ae
			)
		scan ;扫描运算符
			(cond
				((and(null ae) (equal (car operators) 'dummy)) ;ae及运算符表为空
					(return (car operands))	;回送结果,operands即为所需的前缀表达式
				)
			)
			(cond
				;ae为空或运算符表的第一个算符的优先级高于ae的第一个算符的优先级
				((or (null ae)	
					(not (> (weight (car ae)) (weight (car operators)))))  ;嵌套次序.
					(setq 
						operands ;设置operands
							(cons (list (opcode (car operators)) (cadr operands) (car operands))
								(cddr operands)) ;弹出两个操作数
						operators (cdr operators);弹出一个运算符
					)
					(go scan) ;继续寻找运算符。
				)
				;否则
				(t 
					(setq 
						operators (cons (car ae) operators) ; 运算符入栈
						ae (cdr ae) ;从ae中删除算符
					)
					(go stuff)
				)
			)
	)
)

Three functions put together

For ease of use and replication, the three functions are put together

;确定算符的优先权
(defun weight (operator) 
	(cond 
		((equal operator 'dummy) -1) ;运算符号表的开始标记
		((equal operator '=) 0)  ;等于号
		((equal operator '+) 1)	;加号
		((equal operator '-) 1)	;减号
		((equal operator '*) 2)	;乘号
		((equal operator '/) 2);除号
		((equal operator '\\) 2);求余运算符
		((equal operator '^) 3) ;指数运算符
		(t (print (list operator 'not 'an 'operator)) 'nop)
	)
)

;计算与operator对应的lisp函数名.
(defun opcode (operator) 
	(cond
		((equal operator 'dummy)
			(print 'hit-dummy) 
			'dummy
		)
		((equal operator '=) 'setq)
		((equal operator '+) 'plus)
		((equal operator '-) 'difference)
		((equal operator '*) 'times)
		((equal operator '/) 'quotient)
		((equal operator '\\ ) 'remainder)
		((equal operator '^) 'expt)
		(t (print (list operator 'not 'an 'operator)) 'nop)
	)
)

;将算术表达式由中缀形式变为前缀形式
(defun infix_to_prefix (ae)
	(prog (operands operators) ;操作数表和运算符表
		(cond((atom ae) (return ae))) ;特殊情况,只有一个操作数
		(setq operators (list 'dummy)) ;虚拟终结符
		stuff ;寻找操作数
			(cond
				((null ae) 扫描操作数,以运算符结尾
					(return 'unexpected-end)
				)
			) 
			;递归
			(setq 
				operands ;操作数入栈
					(cons 
						(cond 
							((atom (car ae)) (car ae)) 
							(t (infix_to_prefix (car ae)))
						)
						operands
					)	;设置operands
				ae (cdr ae) ;删除操作数,设置ae
			)
		scan ;扫描运算符
			(cond
				((and(null ae) (equal (car operators) 'dummy)) ;ae及运算符表为空
					(return (car operands))	;回送结果,operands即为所需的前缀表达式
				)
			)
			(cond
				;ae为空或运算符表的第一个算符的优先级高于ae的第一个算符的优先级
				((or (null ae)	
					(not (> (weight (car ae)) (weight (car operators)))))  ;嵌套次序.
					(setq 
						operands ;设置operands
							(cons (list (opcode (car operators)) (cadr operands) (car operands))
								(cddr operands)) ;弹出两个操作数
						operators (cdr operators);弹出一个运算符
					)
					(go scan) ;继续寻找运算符。
				)
				;否则
				(t 
					(setq 
						operators (cons (car ae) operators) ; 运算符入栈
						ae (cdr ae) ;从ae中删除算符
					)
					(go stuff)
				)
			)
	)
)

Add definitions in the portal, as shown in the following figure:

program running

Enter the commands in turn

 (infix_to_prefix '(A + B * C) )

 (infix_to_prefix '(total = principal * ( 1.0 + interest ) ^ years ) )

The result of the operation is as follows:

 

 

Guess you like

Origin blog.csdn.net/Alexabc3000/article/details/127336557