Jestem w trakcie pisania prostego "kompilatora" i natknąłem się na problem:
Dotychczas mój ewaluator (to chyba poprawne określenie ;)) działał na zasadzie odwrotnej notacji polskiej; tzn.zamieniałem wyrażenie na ONP, a potem je po kolei ewaluowałem, więc np.z 2+2*2
robiło się 2 2 2 * +
, a potem zamiana na bytecode:
ipush(2)
ipush(2)
ipush(2)
ipop(ei2)
ipop(ei1)
mul(ei1, ei2)
ipush(ei1)
ipop(ei2)
ipop(ei1)
ipush(ei1)
w tej chwili na stosie lądowała wartość 6
(oczywiście przy wyłączonej optymalizacji; dodałem prosty optymalizator który na żywo obliczał wyrażenia stałe, chodzi mi o pokazanie sposobu działania).
W kwestii wytłumaczenia:
ipush(int)
- wrzucenie liczby typu int
/integer
na stos (dodatnia lub ujemna)
ipop(rejestr)
- pobranie liczby typu int
/integer
ze stosu i wrzucenie jej do rejestru
mul(rejestr, wartość)
- pomnożenie rejestru przez wartość i wrzucenie wyniku do rejestru
Rejestry dla liczb typu int
to: ei1
, ei2
, ei3
oraz ei4
.
Natomiast wracając do tematu: z tego co zauważyłem, "prawdziwe" kompilatory zrobiłyby to na zasadzie:
mov(ei1, 2)
mov(ei2, 2)
mul(ei1, ei2)
add(ei1, 2)
I to jest moje pytanie: jak mając wyrażenie w formie 2+2*2
lub 2 2 2 * +
wykonać zamianę kod podany powyżej?
ONP opiera się na stosie, podczas gdy z tego co zauważyłem, kompilatory korzystają z niego rzadko (a w każdym razie w prostych programach).