📜 ⬆️ ⬇️

Polish reverse record in assembly language with syntax AT & T

This program was originally written as a small laboratory work on the course of computer-oriented programming, but later the idea appeared to present it to the community. It is because the algorithm is not implemented in assembly language with Intel syntax, but in assembly language with AT & T syntax.

This syntax is chosen simply because it is cool and a bit non-standard compared to writing programs in a "normal" assembler.

Algorithm


So, let's start with a description of the algorithm for converting an expression into a reverse Polish notation.
Consider each character in turn:
  1. If this character is a number (or variable), then simply put it in the output string.
  2. If the symbol is an operation sign (+, -, *, /), then we check the priority of this operation. Multiply and divide operations have the highest priority (suppose it is equal to 3). The operations of addition and subtraction have a lower priority (equal to 2). The lowest priority (equal to 1) has an opening bracket.
    Having received one of these characters, we need to check the stack:
    • a) If the stack is still empty, or the characters in it (and only operations characters and the opening bracket can be in it) have a lower priority than the priority of the current character, then we put the current character on the stack.
    • b) If the character at the top of the stack has a priority greater than or equal to the priority of the current character, then we extract the characters from the stack to the output line until this condition is met; then go to a)

  3. If the current character is an opening bracket, then we put it on the stack.
  4. If the current character is a closing parenthesis, then we extract characters from the stack to the output line until we find an open parenthesis on the stack (i.e., a character with a priority of 1), which should be simply destroyed. The closing bracket is also destroyed.
  5. If the entire input line is parsed, and there are still operation characters in the stack, we retrieve them from the stack to the output line.

On Habré there was already a topic in which the algorithm was analyzed in detail with examples of its work. Therefore, in the framework of this post it will not be considered.

Program


So, let's start writing the program. In this implementation, the priorities of operations are exactly the same as described above - the multiplication and division operations have the highest priority equal to 3, the operations of addition and subtraction have priority equal to 2, the closing bracket priority equal to 1. The numbers have zero priority. The priority for the digit is introduced for a simpler and more flexible implementation of the algorithm. Also, the priority for the closing bracket is 5. This is also done to facilitate the implementation of the algorithm. Below is a function that determines the priority of the character passed to it:
.text
.globl getPriotiry
# %eax
.type getPriority, @function
getPriority:
pushl %ebp
movl %esp, %ebp

movl 8(%esp), %eax

cmpl $42, %eax # *
je priority3
cmpl $47, %eax # /
je priority3
cmpl $43, %eax # +
je priority2
cmpl $45, %eax # -
je priority2
cmpl $40, %eax # (
je priority1
cmpl $41, %eax # )
je priority5

# -- 0
movl $0, %eax
jmp exit
priority3: # * and /
movl $3, %eax
jmp exit
priority2: # + and -
movl $2, %eax
jmp exit
priority1: # (
movl $1, %eax
jmp exit
priority5: # )
movl $5, %eax
jmp exit
exit:
leave
ret
.size getPriority, .-getPriority

A very interesting point is the implementation of the stack. I decided not to complicate the implementation and understanding of the algorithm and therefore the stack is presented in the form of an array of fixed length, where the first element stores the number of elements in the stack. So, below are the functions for working with the stack: set, take, check the stack for emptiness, get the size of the stack. Each function takes an address on the stack.
#
.text
.globl stack_push
.type stack_push, @function
stack_push:
pushl %ebp
movl %esp, %ebp

# -- , --
movl 8(%ebp), %eax
cmp $50, %eax # . -- , , --
jg address
movl %eax, %edx
jmp number
address:
movzbl (%eax), %ebx
number:
movzbl 12(%ebp), %edx
movl %edx, (%eax, %ebx, 1)

#
movl 8(%ebp), %eax
addl $1, (%eax)

leave
ret
.size stack_push, .-stack_push
#-------------------------------------------------------------------
#
.text
.globl stack_pop
.type stack_pop, @function
stack_pop:
pushl %ebp
movl %esp, %ebp

#
movl 8(%ebp), %eax
subl $1, (%eax)
movzbl (%eax), %ebx

#
movzbl (%eax, %ebx, 1), %eax
# movzbl %edx, %eax

leave
ret
.size stack_pop, .-stack_pop
#-------------------------------------------------------------------
# 0 . 1
.text
.globl stack_isEmpty
.type stack_isEmpty, @function

stack_isEmpty:
pushl %ebp
mov %esp, %ebp

movl 8(%esp), %eax
movzbl (%eax), %eax
cmpl $1, %eax

movl $0, %eax
jg exit
movl $1, %eax

exit:
leave
ret
.size stack_isEmpty, .-stack_pop
#-------------------------------------------------------------------
#
.text
.globl stack_size
.type stack_size, @function

stack_size:
pushl %ebp
movl %esp, %ebp

movl 8(%esp), %eax
movzbl (%eax), %eax
subl $1, %eax

leave
ret
.size stack_size, .-stack_size
#-------------------------------------------------------------------
#
.text
.globl stack_top
.type stack_top, @function

stack_top:
pushl %ebp
movl %esp, %ebp

movl 8(%esp), %eax
movzbl (%eax), %ebx
subl $1, %ebx
movzbl (%eax, %ebx, 1), %eax

leave
ret
.size stack_top, .-stack_size

The main loop of the algorithm is as follows:
  1. Take the next element of the line
  2. Get character priority
  3. Depending on the operation, perform the required action: put it on the stack, put it on the result string, or push all operations up to the opening bracket from the stack.

This part of the program is quite straightforward and uninteresting, so it makes no sense to give it.
The full program code as well as makefile can be found here: dl.dropbox.com/u/1379084/pol.zip

')

Source: https://habr.com/ru/post/111143/


All Articles