Macro ändert Pointernamen

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
Josh
Beiträge: 1028
Registriert: 04.08.2009 17:24

Re: Macro ändert Pointernamen

Beitrag von Josh »

Sicro hat geschrieben:
Josh hat geschrieben:Nein, das ist sehr wohl die Aufgabe des Lexers.
Ein Lexer prüft keine vorherigen oder nachfolgenden Tokens. Er arbeitet überhaupt nicht mit Tokens, sondern erstellt sie nur, und zwar aus Zeichenfolgen, die einem bestimmtem Muster verlaufen.
Der Parser verarbeitet danach nur noch die Tokens und keine einzelnen Zeichen mehr.
Das einzige was in diesem Zusammenhang relevant ist, ist dein erster Satz und das ist falsch. Ein Lexer kann durchaus auf den vorhergehenden Token zurückblicken oder auf das folgende Zeichen (ein folgender Token ist ja noch nicht erstellt, ein Beispiel in Pb wäre das Tilde-Zeichen) vorausschauen und daraus Rückschlüsse ziehen. Weiter unten hast du einen Link auf einen Wiki-Artikel gesetzt, ich empfehle dir, diesen auch zu lesen.

Sicro hat geschrieben:
Josh hat geschrieben:Ein Lexer ordnet den Tokens zu, ob es sich um einen Bezeichner, Operator, Literal, Trennzeichen oder sonst was handelt.
Korrekt. Ich behaupte, aber nirgends was anderes.
Ja, aber wenn du einem Token einen Tokentyp zuordnest, dann solltest du es richtig machen und nicht (wie von dir weiter unten angegeben) das Sternchen einfach als Operator kennzeichnen, obwohl so ca. eine 50/50 Chance besteht, dass es falsch ist. Nochmals, das Sternchen bei einem Pointer ist in Pb Bestandteil des Bezeichners und KEIN Operator. '*AnyPointer' ist EIN Token.

Sicro hat geschrieben:
Josh hat geschrieben:Da 'a' nur ein Bezeichner sein kann, kann kein weiterer Bezeichner folgen und somit ist das '*' ein Operator und 'b' in weiterer Folge wieder ein Bezeichner.
Dem Lexer ist es egal, ob die Syntax des Codes stimmt oder nicht. Er erstellt einfach die Tokens, ohne irgendetwas Weiteres zu prüfen. Das, was du im Zitat schreibst, prüft der Parser, nicht der Lexer.
Das stimmt, dem Lexer ist der Syntax ziemlich egal, so stört es den Lexer in keinster Weise, ob eine öffnende Klammer auch eine schließende Klammer hat, oder ob ein 'Procedure' auch ein 'EndProcedure' hat. Aber was der Lexer benötigt um einen Token RICHTIG zu erstellen, das holt er sich aus dem Kontext der Befehlszeile (wie oben von mir nach dem ersten Zitat bereits beschrieben).

Sicro hat geschrieben:
Josh hat geschrieben:Alles andere wäre auch widersinnig. Der Parser könnte z.B. nicht mehr erkennen, dass bei 'a = b + * c' ein Syntax-Fehler auszugeben ist, da der Parser von Leerzeichen/Tabs nichts mehr weiß.
Es ist nicht so üblich, dass Lexer bei Leerzeichen Tokens erstellen, aber ausgeschlossen ist es nicht.
Hier kannst du es nachlesen: https://en.wikipedia.org/wiki/Lexical_analysis
Die deutsche Version des Wikipedia-Artikels ist leider nicht so umfangreich beschrieben.
In dem Wikipedia-Artikel findest du die relevanten Textstellen, wenn die Textsuchfunktion des Browsers mit "whitespace" fütterst.

[bezeichner_a] [operator_=] [bezeichner_b] [operator_+] [operator_*] [leerzeichen] [bezeichner_c]
"c" ist somit keine Pointer-Variable, weil zwischen "*" und Bezeichner kein Leerzeichen sein darf.
Zwischen den anderen Tokens können natürlich ebenfalls Leerzeichen-Tokens sein, habe ich jetzt aber der einfachheitshalber mal weggelassen, weil der Parser selber entscheiden kann, ob er das Leerzeichen-Token an dieser Position berücksichtigt oder ignoriert.
Und warum sollte das einer tun? Naja, wenn es sich einer absichtlich schwer machen will, dann kann er es natürlich auch so machen und unnötige (und später im Parser extrem störende) Leerzeichen-Token einfügen um anschließend im Parser Fehler des Lexers auszubügeln zu können.
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Macro ändert Pointernamen

Beitrag von Nino »

Josh hat geschrieben:Ein Lexer kann durchaus auf den vorhergehenden Token zurückblicken oder auf das folgende Zeichen
So ist es. Es ist ja gerade der Zweck des Lexers, den Input in einzelne Tokens aufzuteilen. Dazu muss er natürlich auch in jedem Einzelfall "entscheiden", ob * ein separates Token ist (Operator) oder der Beginn eines Bezeichners. Macht ein Lexer das nicht, so erfüllt er seine Aufgabe nicht.

Aus praktischer Sicht: Da es nunmal diese beiden Möglichkeiten für * in PureBasic gibt, muss PureBasic auch insgesamt korrekt damit umgehen können -- nicht nur der Compiler. Für mich ist es klar ein Bug im Makro-Preprocessor.
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Macro ändert Pointernamen

Beitrag von Sicro »

Sicro hat geschrieben:Ein Lexer prüft keine vorherigen oder nachfolgenden Tokens. Er arbeitet überhaupt nicht mit Tokens, sondern erstellt sie nur, und zwar aus Zeichenfolgen, die einem bestimmtem Muster verlaufen.
Der Parser verarbeitet danach nur noch die Tokens und keine einzelnen Zeichen mehr.
Josh hat geschrieben:Das einzige was in diesem Zusammenhang relevant ist, ist dein erster Satz und das ist falsch.
Josh hat geschrieben:Ein Lexer kann durchaus auf den vorhergehenden Token zurückblicken oder auf das folgende Zeichen (ein folgender Token ist ja noch nicht erstellt, ein Beispiel in Pb wäre das Tilde-Zeichen) vorausschauen und daraus Rückschlüsse ziehen.
https://en.wikipedia.org/wiki/Lexical_analysis
Wikipedia hat geschrieben:A lexical analyzer generally does nothing with combinations of tokens, a task left for a parser.
Wikipedia hat geschrieben:Generally lexical grammars are context-free, or almost so, and thus require no looking back or ahead, or backtracking, which allows a simple, clean, and efficient implementation. This also allows simple one-way communication from lexer to parser, without needing any information flowing back to the lexer.
Wikipedia hat geschrieben:When a token class represents more than one possible lexeme, the lexer often saves enough information to reproduce the original lexeme, so that it can be used in semantic analysis. The parser typically retrieves this information from the lexer and stores it in the abstract syntax tree.
Josh hat geschrieben:Weiter unten hast du einen Link auf einen Wiki-Artikel gesetzt, ich empfehle dir, diesen auch zu lesen.
Ich poste in der Regel keine Links zu Internetseiten, die ich nicht vorher gelesen habe. Der Link ist aus meiner Linksammlung als ich mich vor längerem ausführlich über Lexer und Parser informiert habe.
Josh hat geschrieben:Ja, aber wenn du einem Token einen Tokentyp zuordnest, dann solltest du es richtig machen und nicht (wie von dir weiter unten angegeben) das Sternchen einfach als Operator kennzeichnen, obwohl so ca. eine 50/50 Chance besteht, dass es falsch ist.
So funktionieren aber kontextlose Lexer.
Josh hat geschrieben:Nochmals, das Sternchen bei einem Pointer ist in Pb Bestandteil des Bezeichners[...] '*AnyPointer' ist EIN Token.
Der Macro-Code in deinem erstem Post hier veranschaulicht, dass dem nicht so ist.
Die ASM-Ausgabe des PBCompilers zeigt ebenfalls etwas anderes:

Code: Alles auswählen

; stringVariable$  = "string"
  MOV    rsi,_S1
  LEA    rdi,[v_stringVariable$]
  CALL   SYS_FastAllocateStringFree4
; *pointerVariable = 0
  MOV    qword [p_pointerVariable],0
; integerVariable  = 123
  MOV    qword [v_integerVariable],123
; quadVariable     = 456
  MOV    qword [v_quadVariable],456
(Ursprüngliche PB-Codes stehen in den Zeilen, die mit dem Strichpunkt-Zeichen beginnen)
Nino hat geschrieben:Für mich ist es klar ein Bug im Makro-Preprocessor.
In der PB-Hilfe steht bei der Macro-Beschreibung nichts darüber, das Macros Namen von Variablen ersetzen (nehmen wir hier mal an, "*" wäre Bestandteil des Variable-Namens), sondern das der Macro-Name (Macro-Aufruf) durch den Macro-Inhalt ersetzt wird. Und so funktionieren die Macros auch, die in den ersten zwei Posts des Threads enthalten sind. Somit kein Regelbruch, kein Bug.

https://en.wikipedia.org/wiki/Lexical_analysis
Wikipedia hat geschrieben:There are exceptions, however. Simple examples include: semicolon insertion in Go, which requires looking back one token; concatenation of consecutive string literals in Python,[10] which requires holding one token in a buffer before emitting it (to see if the next token is another string literal); and the off-side rule in Python, which requires maintaining a count of indent level (indeed, a stack of each indent level). These examples all only require lexical context, and while they complicate a lexer somewhat, they are invisible to the parser and later phases.
Wie einleitend geschrieben wird sind das aber Ausnahmen und nicht das normale Vorgehen von einem Lexer.

Wenn ihr immer noch der Meinung seid, dass es ein Bug ist, dann meldet ihn halt im englischem Forum und Fred wird dann aus seiner Sicht entscheiden, ob es ein Bug ist.
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Macro ändert Pointernamen

Beitrag von Nino »

Sicro hat geschrieben:
Nino hat geschrieben:Für mich ist es klar ein Bug im Makro-Preprocessor.
In der PB-Hilfe steht bei der Macro-Beschreibung nichts darüber, das Macros Namen von Variablen ersetzen (nehmen wir hier mal an, "*" wäre Bestandteil des Variable-Namens), sondern das der Macro-Name (Macro-Aufruf) durch den Macro-Inhalt ersetzt wird.
Ja und :?:
Ich bin mir nicht sicher ob du verstanden hast, worum es hier geht ...
Der Makro-Name soll nur an den Stellen im Quelltext durch den Makro-Inhalt ersetzt werden, an denen er als eigenständiges Token auftaucht. Das ist doch der Knackpunkt in dieser Sache :!:
Deshalb wird auch im folgenden Code

Code: Alles auswählen

Macro XXX
  YYY
  .
EndMacro

Define aXXX      ; Zeile 6
Define *XXX
in Zeile 6 der Makro-Name richtigerweise nicht durch den Makro-Inhalt ersetzt. Und in Zeile 7 sollte es ebenfalls nicht geschehen. Es passiert aber doch, das ist der Bug.
Sicro hat geschrieben:Wie einleitend geschrieben wird sind das aber Ausnahmen und nicht das normale Vorgehen von einem Lexer.
Was Ausnahmen sind und was nicht ist eine Frage der Statistik, darum geht es hier überhaupt nicht. Wenn eine Situation eintritt, in welcher der Lexer zunächst nicht "weiß" welches Zeichen zu welchem Token gehört, so muss er halt Schritte unternehmen, um das herauszufinden. Was hat das damit zu tun wie häufig so eine Situation eintritt? Gar nichts.

Das Ganze läuft, wie gesagt, auf folgendes hinaus (und mir ist unklar, was daran schwer zu verstehen ist):
Nino hat geschrieben:Es ist ja gerade der Zweck des Lexers, den Input in einzelne Tokens aufzuteilen. Dazu muss er natürlich auch in jedem Einzelfall "entscheiden", ob * ein separates Token ist (Operator) oder der Beginn eines Bezeichners. Macht ein Lexer das nicht, so erfüllt er seine Aufgabe nicht.

Aus praktischer Sicht: Da es nunmal diese beiden Möglichkeiten für * in PureBasic gibt, muss PureBasic auch insgesamt korrekt damit umgehen können -- nicht nur der Compiler.
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Macro ändert Pointernamen

Beitrag von Sicro »

Nino hat geschrieben:
Sicro hat geschrieben:
Nino hat geschrieben:Für mich ist es klar ein Bug im Makro-Preprocessor.
In der PB-Hilfe steht bei der Macro-Beschreibung nichts darüber, das Macros Namen von Variablen ersetzen (nehmen wir hier mal an, "*" wäre Bestandteil des Variable-Namens), sondern das der Macro-Name (Macro-Aufruf) durch den Macro-Inhalt ersetzt wird.
Ja und :?:
Es kann also laut der Beschreibung in der PB-Hilfe schon kein Bug sein. Laut der Beschreibung könnte es auch sein, dass der PB-Compiler die Macro-Namen so ersetzt:

Code: Alles auswählen

ReplaceString(codeNachdemMacroDefinitionBlock$, macroName$, macroInhalt$)
Somit ist

Code: Alles auswählen

*XXX => *YYY
XXX$ => YYY$
entsprechend der Beschreibung korrekt.
Aber wir wissen es ja besser als die PB-Hilfe, dass die Macros Tokens ersetzen. Da stimmt ihr mir ja zu und das beweist auch dein nachfolgender Code, in dem die Variable "aXXX" nicht vom Macro "XXX" ersetzt wird.

Nino hat geschrieben:Der Makro-Name soll nur an den Stellen im Quelltext durch den Makro-Inhalt ersetzt werden, an denen er als eigenständiges Token auftaucht.
Deshalb wird auch im folgenden Code

Code: Alles auswählen

Macro XXX
  YYY
  .
EndMacro

Define aXXX      ; Zeile 6
Define *XXX 
in Zeile 6 der Makro-Name richtigerweise nicht durch den Makro-Inhalt ersetzt. Und in Zeile 7 sollte es ebenfalls nicht geschehen. Es passiert aber doch, das ist der Bug.
Die Macro-Aufrufe werden wie schon geschrieben nur auf Lexer-Ebene ersetzt, daher wird "*XXX" als zwei Tokens gelesen und das zweite Token ("XXX") passt zum Macro-Name.


https://en.wikipedia.org/wiki/Lexical_analysis
Wikipedia hat geschrieben:There are exceptions, however. Simple examples include: semicolon insertion in Go, which requires looking back one token; concatenation of consecutive string literals in Python,[10] which requires holding one token in a buffer before emitting it (to see if the next token is another string literal); and the off-side rule in Python, which requires maintaining a count of indent level (indeed, a stack of each indent level). These examples all only require lexical context, and while they complicate a lexer somewhat, they are invisible to the parser and later phases.
Sicro hat geschrieben:Wie einleitend geschrieben wird sind das aber Ausnahmen und nicht das normale Vorgehen von einem Lexer.
Ich war an diesem Tag wohl bereits zu müde, um das richtig zu verstehen. Als Überschrift steht dort "Context-sensitive lexing". Die rede ist also nicht von dem Lexer, sondern um den Prozess "Lexen". Es bleibt also ausnahmslos dabei: Ein Lexer erstellt Tokens und nur der Parser betrachtet Zusammenstellungen mehrerer Tokens. Für "Kontextabhängiges Lexen" kommt der Parser ins Spiel.
Nino hat geschrieben:Was Ausnahmen sind und was nicht ist eine Frage der Statistik, darum geht es hier überhaupt nicht. Wenn eine Situation eintritt, in welcher der Lexer zunächst nicht "weiß" welches Zeichen zu welchem Token gehört, so muss er halt Schritte unternehmen, um das herauszufinden. Was hat das damit zu tun wie häufig so eine Situation eintritt? Gar nichts.
"Was Ausnahmen sind und was nicht ist eine Frage der Statistik". Bis jetzt habe ich immer wieder nur gelesen, dass Lexer Zeichen zu Tokens gruppiert und nur der Parser mit Zusammenstellungen von Tokens arbeitet, nicht der Lexer. Somit sehe ich keine Kehrwendung von "Ausnahme" zu "neuem Standard".
Wenn es wirklich eine Lexer-Ausnahme gegeben hätte (siehe mein Missverständnis oben bezüglich "Context-sensitive lexing"), die den Lexer kontextabhängig arbeiten lässt, dann wäre das hier sehr wohl relevant gewesen, weil für das Lexen von "*PointerVariable" als ein Token der Lexer kontextabhängig und somit nach dem Ausnahme-Verfahren arbeiten müsste. Demnach wären eure Aussagen hier:
Lexer-Standard-Verfahren: Bug!
Lexer-Ausnahme-Verfahren: Richtig!
Wenn der Lexer ohne Kontext die Tokens nicht richtig zuordnen kann, hift der Parser: https://en.wikipedia.org/wiki/The_lexer_hack

Beim Lexer meine ich mit Kontext die anderen Tokens, weil bei Zeichen darf sich der Lexer ja umschauen, nur nicht bei anderen Tokens.

Ich sehe deshalb nur ein Feature-Request für richtig, wenn ihr euch ein anderes Verhalten der Macro-Auflösung wünscht, und kein Bug-Report.

-------------

Ich habe noch etwas weiter nachgeforscht.

Kopiert mal folgenden Code in eure PB-IDE und führt in aus:

Code: Alles auswählen

Macro BinaryNumber
  101
EndMacro

Macro HexNumber
  A
EndMacro

Macro Identifier
  TestIdentifier
EndMacro
Macro Identifier2
  TestIdentifier2
EndMacro

Debug %BinaryNumber
Debug $HexNumber

Identifier$ = "StringVariable: Ein Test"
Debug TestIdentifier$

*Identifier = 123
Debug *TestIdentifier

;#Identifier = "Constant: Ein Test"
;Debug #TestIdentifier

Procedure Identifier()
  Debug "Procedure: Ein Test"
EndProcedure
TestIdentifier()

Structure TestStruc
  Array Identifier.i(0)
  Identifier2.i[1]
EndStructure
Test.TestStruc
Test\TestIdentifier(0)  = 123
Test\TestIdentifier2[0] = 456
Debug Test\TestIdentifier(0)
Debug Test\TestIdentifier2[0]
Das Verhalten ist auch bei den anderen Bezeichner-Prefixen/Suffixen durchgehend konsistent, außer bei den Konstanten.
Wenn "*PointerVariable" ein einzelnes Token wäre, könnte man mit einem Macro diese Variable nicht ersetzen, weil ein Macro-Name kein "*" enthalten darf.
Procedure/Array/List/Map-Namen könnte man ebenfalls nicht ersetzen, weil die öffnende Klammer Bestandteil des Tokens wäre und Macro-Namen aber nicht nur eine öffnende Klammer am Ende haben dürfen.
Nur normale Variablen könnte man dann mit Macros ersetzen, weil nur die im Namen Zeichen enthalten, die auch bei den Macro-Namen verwendet werden können.

Und ja, in der PureBasic-Sprache gehört das Sternzeichen zur Pointer-Variable und wird aber später beim Token weggelassen (Token-Typ auf "Pointer-Variable" stellen reicht ja), weil bei der ASM-Ausgabe ist das Sternchen wieder weg (siehe ASM-Ausgabe bei einem vorherigem Post von mir) und der PB-Compiler macht denke ich nicht sowas:

Code: Alles auswählen

asmPointerVariableName$ = ReplaceString(originalPointerVariableName$, "*", "p_")
Wir reden hier aber von der Macro-Verarbeitung und da sieht es anders aus.


Wie es wirklich unter der Haube läuft, wissen natürlich nur die PB-Entwickler.
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Macro ändert Pointernamen

Beitrag von Nino »

Ich habe dem, was ich geschrieben habe nichts hinzuzufügen und bin daher jetzt raus aus dieser "Diskussion".
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Macro ändert Pointernamen

Beitrag von GPI »

Ich möchte nur nochmals drauf hinweisen, das es ein sehr schlechter Programmierstiel ist, Proceduren, Strukturen, Variablen, Labels etc. alle die gleichen Namen zu verpassen. Ja es ist in PB möglich, gibt aber genügend Sprachen wo das nicht geht. Es macht den Code auch imo schwerer lesbar. Damit umgeht man die ganze Problematik.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Macro ändert Pointernamen

Beitrag von Nino »

@GPI:
Ich stimme Dir voll und ganz zu.
Antworten