Palladium



  • Hallo liebe Leute,
    ich entwickele gerade zu lern Zwecken eine eigene Programmiersprache.
    Das Ziel ist Konzepte zu verstehen und zu lernen.
    Wo stehe ich gerade, ich habe einen Lexer entwickelt der eine beliebige anzahl an Tokens voraussehen kann.
    Des Weiteren habe ich eine VM entwickelt, diese ist Stack und Registerbasiert.
    Sie hat jetzt schon die Möglichkeit Speicher zu verwalten,
    kann Funktionsaufrufe durchführen, bedingte und unbedingte Sprünge und natürlich kann sie addieren!
    Wer lust hat mit mir in den Kaninchenbau tiefer einzusteigen ist total Willkommen. Hier der Link https://github.com/pmqtt/palladium



  • @c_new
    Nee sorry, ich grusele mich immer noch vor dem GNU Bison. 😉

    BTW: Wäre mal interresant welche moderenen Lexer es gibt.



  • @c_new
    BTW:
    Mach mir mal einen Gefallen. Wirf alle Makros raus. So was wie RETURN_IF_VALID, ERROR_IF_CHAR oder ERROR_IF_CHAR_EQ geht einfach nicht, da:

    • Kontrollfluß nicht ersichtlich ist
    • Makros nicht debugbar sind
    • Eine inline Funktion es auch macht
    • Makros nicht typsicher sind. Welchen Typ hat z.B. F bei `RETURN_IF_VALID?


  • @Quiche-Lorraine
    Ich ergänze:

    • Namespaces ignorieren


  • @Quiche-Lorraine
    RETURN_IF_VALID durch eine Inline Funktion zu ersetzen ist nicht möglich! Genaus so gilt das für die anderen!
    Das ist lustigerweise immer die Aussage von ChatGPT: Ersetze die Makros durch inline Funktionen. Da gibt es nichts zu ersetzen. Da die Makros ein if() return ersetzten.

    Aber danke für das Feedback.



  • @DocShoe Was meinst du mit namespaces ignorieren ?



  • @c_new Tatsächlich ist das ein Use-Case den ich auch auf Arbeit immer wieder im production Code finde. Ich mag es nicht. Glücklicherweise gibt es mit c++23 ein std::expected (oder auch std::optional - das hat entsprechende Operationen auch bekommen). Alternativ tun es auch andere expected Implementierungen von github.
    Durch dessen monadic-functions (and_then, or_else, etc.), lassen sich diese Fälle häufig in die Sprache transferieren.

    Wenn ich mir z.B. das hier ansehe,...

    if (opt_c) {
            RETURN_IF_VALID(lex_hex_number(opt_c, value));
            RETURN_IF_VALID(lex_bin_number(opt_c, value));
            RETURN_IF_VALID(lex_float_number(opt_c, value));
            ERROR_IF_CHAR(opt_c, std::isdigit, "Invalid integer number");
            _stream->prev();
    }
    

    EDIT: Blödsinn folgt. Aber das zeigt nur, wie schwer das eigentlich zu greifen ist, was hinter deinen Macros steckt.
    EDIT2: Korrigiertes folgt.

    ... dann ließe sich das sich auch so lösen:

    if (opt_c) {
    
        if (std::optional result = lex_hex_number(opt_c, value)
                                   .or_else([&]{ return lex_bin_number(opt_c, value); }
                                   .or_else([&]{ return lex_float_number(opt_c, value); })
        {
            return // mach irgendwas mit deinem token
        }
    
        if (std::isdigit(*opt_c)) {
            return err("Invalid integer number"); // könnte man als std::unexpected modellieren
        }
    
        _stream->prev();
    }
    


  • @DNKpp Lustigerweise ist RETURN_IF_VALID eine Prüfung für meine ResultOr<optional<Token>, Error> Klasse und diese prüft ja
    if(res.ok()){ ....}

    return lex_hex_number(...).some(
                        [&]( const ResultOr<std::optional<Token>,Error> & t)=> auto 
                        {
                                  if(!token)  
                                      return lex_bin_number().some(...);
                                  return token;
                         }
    

    man könnte sich das so überlegen auf jedenfall! Aber hier stellt sich die Frage, ob so eine Verschachtelung besser zu verstehen ist.

    Dann finde ich es besser:

    auto res = lex_hex_number(...);
    if(res){
            return res;
    }
    res = lex_bin_number(...);
    .
    .
    .
    

    Da man die tiefe Verschachtelung vermeidet.



  • Hi Leute,
    ich habe mal einen Versuch für eine kleine Syntax durchgeführt, diese sieht so aus:

    translation_unit ::= function
    function ::= "fn" identifier "(" ")" "->" type "{" statements "}"
    statements ::= (statement)*
    statement ::= variable_declaration | constant_declaration | loop | return_statement
    variable_declaration ::= "let" identifier ":" type "=" expression ";"
    constant_declaration ::= "const" identifier ":" type "=" expression ";"
    loop ::= "while" "(" condition ")" "{" statements "}"
    return_statement ::= "return" expression ";"
    expression ::= integer | string_literal | array_initialization | binary_expression
    array_initialization ::= "[" expression ";" expression "]"
    binary_expression ::= identifier operator expression
    condition ::= binary_expression
    identifier ::= /[a-zA-Z_][a-zA-Z0-9_]*/
    integer ::= /\d+/
    string_literal ::= /".*"/
    operator ::= "<" | "=" | "+" | "*" | "/"
    type ::= "i64" | "string" | "[i64;" identifier "]"
    

    einen Parser für diese Syntax ist auch fertig, wobei Parser ein zu großes Wort ist, ich würde eher sagen, er entscheidet ob ein String durch diese Grammatik produziert werden kann.
    Hier kann man sich mal den Parser anschauen:
    https://github.com/pmqtt/palladium/blob/main/src/Parser.cpp

    An euch mal eine Frage, wie würdet ihr gerne, eine Syntax für Arrays haben?



  • @c_new sagte in Palladium:

    An euch mal eine Frage, wie würdet ihr gerne, eine Syntax für Arrays haben?

    Nicht die C-Syntax 🐸 Also die Klammern sollten nur direkt beim type stehen dürfen.

    @c_new sagte in Palladium:

    einen Versuch für eine kleine Syntax durchgeführt, diese sieht so aus

    EBNF?

    @c_new sagte in Palladium:

    ich würde eher sagen, er entscheidet ob ein String durch diese Grammatik produziert werden kann

    Ich glaube (TM), das ist sprachlich nicht richtig, ein String kann doch zur Grammatik passen oder nicht, aber er wird nicht durch diese "produziert"?



  • @Unbekannt sagte in Palladium:

    Ich glaube (TM), das ist sprachlich nicht richtig, ein String kann doch zur Grammatik passen oder nicht, aber er wird nicht durch diese "produziert"?

    Ja, das ist intuitiv etwas komisch, wenn man es vom Parsen der Sprache her betrachtet, aber in der Theoretischen Informatik nennt man das so. Die aufgelisteten Ersetzungsregeln nennt man auch "Produktionsregeln".



  • @Finnegan Danke für die Erklärung, dann war es vom Sprachgebrauch her doch richtig.

    Mich hat nur der Vertausch von aktiv und passiv irritiert.


Anmelden zum Antworten