Zum Inhalt springen

[Delphi, YACC] Befehle zum Compilerbau


paule22

Empfohlene Beiträge

Hallo Miteinander!

Ich bin gerade dabei einen Compiler zu schreiben.

Wie kann ich den Ausdruck:

ident '=' expr

(Zeile: 218)

also: variable = 12

in Assembler umsetzen?

Als Grundlage soll folgender Yacc Source dienen:

nopaste.info - free nopaste script and service

Für Anregungen und Informationen bin ich jedem dankbar.

MfG

paule22

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

wie man ein Assemblerprogramm schreiben kann, ist für mich noch etwas neuland. Kann aber schon Konstrukte aufstellen.

unter nopaste.info - free nopaste script and service

könnt Ihr eine etwas überarbeitete Version vorfinden.

Was mir komisch vorkommt ist, das Stack nicht gleich

Stack ist.

Zum Beispiel beginnend ab Zeile 256 hochrangelnd auf

Zeile 216 -> expr (Zeile 88) -> weiter bei Zeile 118.

Warum wird dann folgender Code erzeugt:

Für Ideen und Vorschläge bin ich jedem dankbar!

Gruß

Jens

---


BITS 32

cpu 486


extern _exit, _show_message

extern _set_vergleichswert_A1

extern _set_vergleichswert_A2

extern _set_vergleichswert_byvar

extern _vergleiche_cmpeq


@var_var1: dd 10

@Pshow_message0: db "ist 5",0

@Pshow_message1: db "juhu 5",0

@Pshow_message2: db "nuja halt 7",0

@Pshow_message3: db "ok",0

@Pshow_message4: db "ist nicht 5",0



segment .text

global _start_main

_start_main:

    push ebp

    mov ebp, esp


; die folgende Zeilen müssten doch theoretisch

; unter push [@var_var2] stehen?

; mache ich einen Programmierfehler oder liegt

; das Problem am Yacc?

    call _set_vergleichswert_byvar

    add esp, 8


    push dword [@var_var1]

    push dword [@var_var2]

    call _vergleiche_cmpeq

    cmp eax, 1

    jne near Le0

    push @Pshow_message0

    call _show_message

    jmp near Lj0

Le0:

    call _vergleiche_cmpeq

    cmp eax, 1

    jne near Le2

    push @Pshow_message1

    call _show_message

    jMP near Lj2

Le2:

    call _vergleiche_cmpeq

    cmp eax, 1

    jne near Le4

    push @Pshow_message2

    call _show_message

    push @Pshow_message3

    call _show_message

    jMP near Lj4

Le4:

    push @Pshow_message4

    call _show_message

    jmp near Lj4

Lj4:

    jmp near Lj2

Lj2:

    jmp near Lj0

Lj0:

    push dword 0

    call _exit

    leave

    ret

---


der QuellCode schaut wie folgt aus:


...

var1 = 10

//var2 = 1


if var1 = var2

  showmessage("ist 5")

elseif 5 = 7

  showmessage("juhu 5")

elseif 5 = 5

  showmessage("nuja halt 7")

  showmessage("ok")

else

  showmessage("ist nicht 5")

endif

...

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo Perfiliev,

vielleicht sollte ich etwas zu dem Projekt sagen ...

Es handelt sich hierbei wohl eher um einen Skript-Compiler. Das hört sich jetzt vielleicht lustig an, ist aber so :-)

Der Kern des Compilers wurde von mir in Delphi 7 gestartet/programmiert.

Mittlerweile wird das Projekt unter Windows Vista und CodeGear (Delphi 2009)

weiter entwickelt, da es zu Problemen mit Delphi 7 unter Vista (Kompatibilität) gab.

Unter dem WebLink: TP Lex/Yacc

kann man die tply41a.zip downloaden (Yacc für Pascal)

So als Grundlage für den Compiler dient der nopaste code vom letztem Posting.

Yacc ist ja Stack basierend, vielleicht hier die kleine Unmissverständlichkeit.

Der ParserCode erzeugt aus einer Quelldatei NASM (Netwide Assembler) Win32 Code. NASM verwende ich dann um den ASM-Text/Ausgabe in Win32 obj binary umzuwandeln. Dieser obj Code ist kompatibel mit den MingW32 GCC Compiler. Deshalb auch meine Wahl des Assemblers.

Mittels selbst geschriebener Lib's (ausser Qt 4.3.4) werden dann die Daten gegeneinander zu einer EXE Datei gelinkt.

Eine BATCH Datei würde dann so aussehen:


set path=i:\mingw\bin;i:\qt\4.3.4\bin;%path%

nasm -f win32 11.asm

g++ -o 11.exe 11.obj -Li:\Qt\4.3.4\lib -L.\lib -lkalib -lkagraph -lxbase -lkernel32 -lwin32k -lQtCore4 -lqtmain -lQtGui4

Nun zu den cmp Funktionen: Dazu dient ein Ausschnitt aus der Datei jk_class.cc:

...

float ErgebnisWert = 0.0;


float vglwertA1 = 0;

float vglwertA2 = 0;

extern "C" void set_vergleichswert_A1(int nach, int vor) { vglwertA1 = QString("%1.%2").arg(vor).arg(nach).toFloat(); }

extern "C" void set_vergleichswert_A2(int nach, int vor) { vglwertA2 = QString("%1.%2").arg(vor).arg(nach).toFloat(); }


// die folgende Funktion muss noch angepasst werden

// Sie steht nur exemplarisch (erstmal) hier aufgelistet ...

extern "C" void set_vergleichswert_byvar(float v1, float v2)

{

  vglwertA1 = v1;

  vglwertA2 = v2;

}


extern "C" int vergleiche_cmpeq(void)

{

  if (vglwertA1 == vglwertA2)

  return 1; else

  return 0;

}

...

Zu Deiner Frage mit (siehe obigen Code _exemplarisch_),
Wenn es C-call ist, dann braucht man zwei PUSHs bevor.
ja das ist richtig, aber das ist das wenigste Problem (erstmal). _vergleiche_cmpeq hat wie im Code oben zu sehen ist kein Argument. Zu den CodeAbschnitt Je0: call _vergleiche_cmpeq hier handelt es sich um eine NichtOptimierter Codestelle. Es wird halt nochmals auf "=" (Gleichheit) geprüft - der Compiler in seiner jetzigen Form ist halt noch ein recht dummy/dummer Automat, der keinen optimierten Code auswirft. So das dazu erstmal. Nun zum eigentlichem Problem: Das Programm YACC (so scheint es mir) ist ein STACK/(Keller) (YetAnother) Compiler-Compiler Tool. Doch warum verhält sich dieses Tool so merkwürdig? Beispiel:

zahl : NUMMER_TOKEN

  ;


t_var : /* kann leer bleiben */

  | zahl zahl  {


    wird als Stack von links nach rechts ausgewertet

    also zahl1 dann zahl2

  }

  ;

verständlich :confused: Also müsste doch mit dem vorliegenden YACC-Code der AsmCode nicht wie:

...

call _set_vergleichswert_byvar

add esp, 8

push dword [@var_var1]

push dword [@var_var2]

call _vergleiche_cmpeq

...

aussehen, sondern so:

...

push dword [@var_var1]

push dword [@var_var2]

call _set_vergleichswert_byvar

add esp, 8

call _vergleiche_cmpeq

cmp eax, 1

jne near Le0

...

oder liege ich da jetzt falsch?

Für sachdienliche Hinweise bin ich sehr dankbar!

Gruß

Jens

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo Jens,

zuerst habe ich falsch verstanden, dass vergleiche_cmpeq pascal-call ist und zwei args hat.

Jetzt habe ich set_vergleichswert_byvar vergleiche_cmpeq gesehen. Beide sind C-call.

Dann ist dieses Code ganz richtig:

...

push dword [@var_var1]

push dword [@var_var2]

call _set_vergleichswert_byvar

add esp, 8

call _vergleiche_cmpeq

cmp eax, 1

jne near Le0

...

Und nicht wie:

push @Pshow_messageXXX

call _show_message

sondern, so:

push @Pshow_messageXXX

call _show_message

add esp,4

Wenn _show_message auch C-call ist.

Wenn ich später Zeit habe,dann versuche ich dir helfen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo Jens,

pcode.pas

PCODE.7z ñêà÷àòü ñ Ôàéëû@Mail.Ru

var1 = 10

var2 = 1


if var1 = var2

  showmessage("ist 5")

elseif var1 = var2

  showmessage("ist nicht 5")

endif
asm code:
BITS 32

cpu 486


extern _exit, _show_message

extern _set_vergleichswert_A1, _set_vergleichswert_A2, _set_vergleichswert_bychar

extern _vergleiche_cmpeq


@var_var1: dd 10

@var_var2: dd 1

@Pshow_message0: db "ist 5",0

@Pshow_message1: db "ist nicht 5",0



segment .text

global _start_main

_start_main:

	push ebp

	mov ebp, esp

	push dword [@var_var1]

	push dword [@var_var2]

	call _set_vergleichswert_byvar

	add esp,8

	call _vergleiche_cmpeq

	cmp eax, 1

	jne near Le0

	push @Pshow_message0

	call _show_message

	add esp,4

	jmp near Lj0

Le0:

	push dword [@var_var1]

	push dword [@var_var2]

	call _set_vergleichswert_byvar

	add esp,8

	call _vergleiche_cmpeq

	cmp eax, 1

	jne near Le2

	push @Pshow_message1

	call _show_message

	add esp,4

	jMP near Lj2

Le2:

	jmp near Lj2

Lj2:

	jmp near Lj0

Lj0:

	push dword 0

	call _exit

	leave

	ret

mfg

Sergey

Link zu diesem Kommentar
Auf anderen Seiten teilen

Danke Perfiliev!

wenn Du anstelle der pcode.pas, die pcode.y gepostet hättest, wäre mir ein

klein wenig Sucharbeit ersparrt geblieben.

Aber naja, fürs erste geht das schon.

Danke es funktioniert.

Woher Du nur die ganzen Ideen herzauberst ;-)

Gruß

Jens

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo Perfiliev!

unter:

RapidShare: Easy Filehosting

habe ich eine abgeänderte Yacc-Datei hochgeladen.

Ich habe alle möglichen Varianten

+ num = num

+ num = exp

+ exp = num

+ exp = exp

primitiv programmiert.

Klappt auch so weit gut mit


var1 = 10.3

var2 = 2.1


if var1 = var2 ...

allerdings tritt jetzt das ein Problem auf, wenn ich:

var0 = 1.2

var1 = 10.2

var3 = 1.1 + var0      // <-- hier


if var3 = ....-

dann wird das AssemblerFile derart verstopft ...

kannst Du mal nachschauen und ggf. eine Lösung posten?

Vielen Dank

Jens

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...