Beitragen

Wir freuen uns über Beiträge von jedem, auch wenn du neu im Bereich Open Source bist. Es mag zunächst entmutigend klingen, zu einem Compiler beizutragen, aber tu es einfach, denn es ist nicht so kompliziert, wie es aussieht. Wir werden bei allen technischen Problemen helfen und deinen Beitrag verbessern, damit er eingefügt werden kann.

Grundeinstellung

Um Beizutragen solltest du folgendes vorbereitet haben:

  • Dein Benutzername + E-Mail

  • Deine ~/.gitconfig

  • Deine Shell Eingabe sollte den aktuellen Branch Namen anzeigen

LFortran abspalten

Schritt 1. Erstelle einen Fork des Projekt Repositorys

Schritt 2: Richte deinen SSH key mit GitHub ein

Schritt 3: Klone das Projekt Repository von GitHub und richte dein Remote-Repository ein

git clone https://github.com/lfortran/lfortran.git
cd lfortran
git remote add REMOTE_NAME git@github.com:YOUR_GITHUB_ID/lfortran.git

:fontawesome-solid-edit: REMOTE_NAME ist der Name deines Remote-Repositorys und kann prinzipiell beliebig sein, beispielsweise dein Vorname.

:fontawesome-solid-edit: YOUR_GITHUB_ID ist deine Nutzer-ID auf GitHub und sollte Teil deines Accountpfades sein.

Du kannst git remote -v verwenden um zu überprüfen ob der neue Remote korrekt eingerichtet ist.

Sende einen neuen Merge request

Schritt 1. Erstellen Sie einen neuen Zweig

git checkout -b fix1

Schritt 2. Nehmen Sie Änderungen in der/den betreffenden Datei(en) vor

Schritt 3: Committe deine Änderungen:

git add FILE1 (FILE2 ...)
git commit -m "YOUR_COMMIT_MESSAGE"

Hier gibt es sehr hilfreiche Tipps zum Schreiben guter Commit-Messages.

Schritt 4: Überprüfe, dass deine Änderungen gut aussehen

git log --pretty=oneline --graph --decorate --all

Schritt 5: Sende den merge-request

git push REMOTE_NAME fix1

Der Befehl pushed den neuen Branch fix1 in dein remote Repository REMOTE_NAME, welches du zuvor erstellt hast. Zusätzlich wird ein Link angezeigt, welcher geklickt werden kann um einen neuen merge request zu starten. Nach dem Klicken, schreibe einen Titel und eine kurze Beschreibung, anschließend klicke auf den „Create“-Button. Du bist nun fertig.

Neue Funktionen hinzufügen

Das folgende Beispiel zeigt die Schritte die erforderlich sind um den binären Operator ^ zu erstellen, welcher den Mittelwert der beiden Operanden berechnet.

Neue(s) Token erstellen

Wir erweitern den tokenizer.re und den parser.yy um den Token ^. Wir werden außerdem LFortran in parser.cpp sagen, wie der neue Token ausgegeben werden soll.

:fontawesome-solid-code: src/lfortran/parser/tokenizer.re

// "^" { RET(TK_CARET) }

:fontawesome-solid-code: src/lfortran/parser/parser.yy

%token TK_CARET "^"

:fontawesome-solid-code: src/lfortran/parser/parser.cpp

std:string token2text(const int token)
{
    switch (token) {
        T(TK_CARET, "^")
    }
}

Der hinzugefügte Code wird mit lfortran --show-tokens examples2/expr2.f90 getestet

Parsen des neuen Tokens

Nun muss der neue Operator geparsed werden. Wir fügen ihn zum AST hinzu, indem wir den BinOp um den Caret-Operator erweitern und die AST.asdl -Datei anpassen. Anschließend fügen wir ihn in parse.yy hinzu um den neuen AST in semantics.h richtig zu parsen und zu generieren. Abschließend erweitern wir pickle.cpp, sodass der neue Operator sich selbst ausgeben kann.

:fontawesome-solid-code:grammar/AST.asdl

operator = Add | Sub | Mul | Div | Pow | Caret

:fontawesome-solid-code:src/lfortran/parser/parser.yy

%left "^"

expr
    : id { $$=$1; }
    | expr "^" expr { $$ = CARET($1, $3, @$); }

:fontawesome-solid-code:src/lfortran/parser/semantics.h

#define CARET(x,y,l) make_BinOp_t(p.m_a, l, EXPR(x), operatorType::Caret, EXPR(y))

:fontawesome-solid-code:src/lfortran/pickle.cpp

std::string op2str(const operatorType type)
{
    switch (type) {
        case (operatorType::Caret) : return "^";
    } // now the caret operator can print itself

}

Der Abschnitt lässt sich mit lfortran --show-ast examples/expr2.f90 testen

Implementieren der Semantik des neuen Tokens

Zuerst erweitern wir den ASR in ASR.asdl und fügen ^ als eine BinOp-operator Option hinzu.

:fontawesome-solid-code:src/libasr/ASR.asdl

binop = Add | Sub | Mul | Div | Pow | Caret

:fontawesome-solid-code:src/lfortran/semantics/ast_common_visitor.h

namespace LFortran {
class CommonVisitorMethods {
public:
  inline static void visit_BinOp(Allocator &al, const AST::BinOp_t &x,
                                 ASR::expr_t *&left, ASR::expr_t *&right,
                                 ASR::asr_t *&asr) {
    ASR::binopType op;
    switch (x.m_op) {

    case (AST::Caret):
      op = ASR::Caret;
      break;
    }
    if (LFortran::ASRUtils::expr_value(left) != nullptr &&
        LFortran::ASRUtils::expr_value(right) != nullptr) {
      if (ASR::is_a<LFortran::ASR::Integer_t>(*dest_type)) {
        int64_t left_value = ASR::down_cast<ASR::IntegerConstant_t>(
                                 LFortran::ASRUtils::expr_value(left))
                                 ->m_n;
        int64_t right_value = ASR::down_cast<ASR::IntegerConstant_t>(
                                  LFortran::ASRUtils::expr_value(right))
                                  ->m_n;
        int64_t result;
        switch (op) {
        case (ASR::Caret):
          result = (left_value + right_value)/2;
          break;
        }
  }
}
}
}
}

Anschließend wandeln wir ihn vom AST zum ASR um, indem wir src/lfortran/semantics/ast_common_visitor.h ergänzen.

Zusätzlich fügen wir ihn in die „Compile time evaluation“ hinzu, die durch Ausdrücke wie z.B. e = (2+3)^5 ausgelöst wird. Ein Ausdruck wie beispielsweise e = x^5 wird nur zur Laufzeit evaluiert.

Dieser Abschnitt lässt sich mit lfortran --show-asr examples/expr2.f90 testen

Implementierung des neuen Tokens in LLVM

Zur Implementierung in LLVM erweitern wir die BinOp-Übersetzung um die Verarbeitung des neuen Operators. Wir addieren im ersten Schritt die beiden Zahlen und dividieren diese anschließend durch zwei. :fontawesome-solid-code:src/lfortran/codegen/asr_to_llvm.cpp

    void visit_BinOp(const ASR::BinOp_t &x) {
        if (x.m_value) {
            this->visit_expr_wrapper(x.m_value, true);
            return;
        }
        this->visit_expr_wrapper(x.m_left, true);
        llvm::Value *left_val = tmp;
        this->visit_expr_wrapper(x.m_right, true);
        llvm::Value *right_val = tmp;
        if (x.m_type->type == ASR::ttypeType::Integer ||
            x.m_type->type == ASR::ttypeType::IntegerPointer) {
            switch (x.m_op) {

                case ASR::binopType::Caret: {
                    tmp = builder->CreateAdd(left_val, right_val);
                    llvm::Value *two = llvm::ConstantInt::get(context,
                        llvm::APInt(32, 2, true));
                    tmp = builder->CreateUDiv(tmp, two);
                    break;
                };
}
}
}

Dieser Abschnitt lässt sich mit lfortran --show-llvm examples/expr2.f90 testen

Wenn LLVM nun funktioniert, können wir die endgültige ausführbare Datei testen, indem wir:

lfortran examples/expr2.f90
./a.out

Und es sollte 6 ausgegeben werden.

Es funktioniert auch interaktiv:

$ lfortran
Interactive Fortran. Experimental prototype, not ready for end users.
  * Use Ctrl-D to exit
  * Use Enter to submit
  * Use Alt-Enter or Ctrl-N to make a new line
    - Editing (Keys: Left, Right, Home, End, Backspace, Delete)
    - History (Keys: Up, Down)
>>> 4^8                                                                  1,4   ]
6
>>> integer :: x                                                         1,13  ]
>>> x = 4                                                                1,6   ]
>>> x^8                                                                  1,4   ]
6

Kontakt aufnehmen

Wenn du Fragen hast oder Hilfe brauchst, wende dich bitte an unsere Mailinglist oder and den Chat.

Bitte beachte, dass von allen Teilnehmern an diesem Projekt erwartet wird, dass sie unseren Verhaltenskodex befolgen. Mit der Teilnahme an diesem Projekt erklärst du dich damit einverstanden, diese Bedingungen einzuhalten. Siehe CODE_OF_CONDUCT.md.

Durch das Einreichen eines Beitrags stimmst du der Lizenzierung deines Beitrags unter LFortrans BSD Lizenz zu, es sei denn, es ist ausdrücklich anders vermerkt.