Autor Thema: Eigene Programmiersprache  (Gelesen 2550 mal)

Survari

  • Beiträge: 2
    • Profil anzeigen
    • Triploit auf Github
Gespeichert
« am: 18. December 2016, 13:10 »
Hey !

Bevor ich mi meinem Beitrag Anfange, denke ich das es angebracht wäre wenn ich mich mal hier vorstelle:
Mich nennt man Survari, ich bin 13 und bin ein totaler Low-Level Fanatiker, auch wenn ich nicht wirklich Assembler kann (Schande über mich  :-D ). Ich programmiere seit eineinhalb Jahren C++ und bin ein leidenschaftlicher Linux-Nutzer. Außer C++ hab ich schon viele Sprachen ausprobiert. "Können", tue ich noch Java und ne andere kleine Programmiersprache auf die ich gleich zurückkommen werde  :wink: Im IRC war ich bis jetzt auch schon ein paar mal, besonders wegen tyndur
Ich hab mich hier vor ein paar Monaten angemeldet, da ich mit dem OS-Development anfangen wollte, hab da aber zu hoch gegriffen (wie ich denke alle in meinem Alter). Für eine Übung wär's zwar gut, aber da muss ich mich erst nochmal richtig mit beschäftigen.

Seit diesem Sommer arbeite ich an einer kleinen Programmiersprache, die ich erst in Java programmiert hatte, jetzt vor einem Monat aber zu C++ umgestiegen bin. Ich denke das die Sprache schon ein bisschen kann. Ihr Syntax ist dem von Assembler (keiner Spezifisch) ähnlich und ist schon so weit das man Variablen, Funktionen, Sprungmarken, Headerdateien und weiteres anlegen kann. Sie soll ein ein Projekt zum üben, aber auch ein kleiner "High-Level-Assembler" werden. Es ist auch möglich die Sprache in C++ umzuwandeln, also in die Ausgangssprache. Vielleicht ist das jetzt noch nichts allzu großes, aber ich würde mich vielleicht über etwas Feedback freuen, besonders da sich hier die Experten herumtreiben was Programmierung betrifft :-D !

Das letzte Update habe ich gerade eben hochgeladen und eine Dokumentation sowie Beispielcode ist auch verfügbar.
, sonnst hier mal ein kleines Additionsprogramm:

{main}
  defi z1,[0];
  say "Zahl eingeben: ";
  inp z1;

  add [2], z1;
  say  "Deine Zahl ergibt mit 2 addiert: ";
  prv  z1;@

  end;
  endf;

(Hab ichs doch gleich das erste mal mit dem Code-Tag verhauen  :-D )

Schönen Sontag euch noch  :-)
« Letzte Änderung: 08. January 2017, 18:56 von Survari »
Es gibt 11 arten von Menschen: Die, die Binärcode verstehen, die, die es nicht tun und die, denen dieser Witz auf die nerven geht.

Svenska

  • Beiträge: 1 778
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 31. December 2016, 00:12 »
Das letzte Update habe ich gerade eben hochgeladen und eine Dokumentation sowie Beispielcode ist auch verfügbar.
Das ist aber lieb. Magst du uns auch verraten, wohin und wo? :-D

Wenn ich an Assembler denke, habe ich immer eine Low-Level-Umgebung (Mikrocontroller, Startup-Code o.ä.) im Hinterkopf. Von daher stellt sich bei mir direkt die Frage, ob say, inp oder prv Basisbefehle oder ein Teil der Runtime sind. Irgendwo vorher käme noch die Frage, ob es eine Runtime gibt, wie groß sie (in etwa) ist und was sie kann.

Ein paar andere Fragen fallen mir spontan ein, aber da könnte die Dokumentation helfen. Sowas wie:
  • Warum schreibst du Immediates in eckige Klammern? (ARM- und x86-(Intel-)Assembler nutzen das für Dereferenzierung.)
  • Warum hast du einen Funktionskopf, aber zwei Funktionsenden (end und endf)?
  • Welche Datentypen gibt es (ich sehe "int" und "konstanter String", echte Strings wären interessant)?
  • Fehlt in der zweiten Zeile zufällig ein Semikolon? :-D

MasterLee

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 31. December 2016, 23:41 »
Das ist aber lieb. Magst du uns auch verraten, wohin und wo? :-D
Guckst du Profil!
Hab mir das mal angeschaut das kompiliert nach C++ oder früher halt Java(Sprache).
Ich hatte mich auch mal an einen Assembler der nach Java(Bytecode) kompiliert. Allerdings hab ich denn jetzt aufgegeben WebAssembly ist zwar auch irgendwie scheiße aber nicht so schlimm wie Java.
Rebol []

toByte: func [value] [back tail to-binary value]
toInt: func [value] [skip tail to-binary value -4]
toShort: func [value] [skip tail to-binary value -2]
toUTF8: func [value /local x] [x: to-binary value join toShort length? x x]

constant_pool: []
access_flags: #{0000}
interfaces: []
fields: []
methods: []

toConstantPool: func [value] [i: index? find constant_pool value either equal? i none [length? append constant_pool value] [i]]
constantUTF8: func [value] [toConstantPool join #{01} toUTF8 value]
constantString: func [value] [toConstantPool join #{08} toShort constantUTF8 value]
constantClass: func [name] [toConstantPool join #{07} toShort constantUTF8 name]
constantNameAndType: func [name type] [toConstantPool rejoin [#{0C} toShort constantUTF8 name toShort constantUTF8 type]]
constantFieldRef: func [class name type] [toConstantPool rejoin [#{09} toShort constantClass class toShort constantNameAndType name type]]
constantMethodRef: func [class name type] [toConstantPool rejoin [#{0A} toShort constantClass class toShort constantNameAndType name type]]

FieldDescriptor: [
  [
    'byte (fd: "B" fd_c: 1) |
    'char (fd: "C" fd_c: 1) |
    'double (fd: "D" fd_c: 2) |
    'float (fd: "F" fd_c: 1) |
    'int (fd: "I" fd_c: 1) |
    'long (fd: "J" fd_c: 2) |
    set x string! (fd: rejoin ["L" x ";"] fd_c: 1) |
    'short (fd: "S" fd_c: 1) |
    'boolean (fd: "Z" fd_c: 1)
  ]
  opt [
    set x integer! (fd: copy fd insert/dup fd "[" x fd_c: 1)
  ]
]

MethodDescriptor: [
  (md: copy "(" md_pc: 0)
  into [
    any [
      FieldDescriptor
      (append md fd md_pc: add md_pc fd_c)
    ]
  ] ( append md ")") [
    FieldDescriptor (md_rc: fd_c) |
    'void (fd: "V" md_rc: 0)
  ]
  (append md fd)
]

datei: open/new %Test.class
write datei #{CAFEBABE} ; magic
write datei toShort 3 ; minor_version
write datei toShort 45 ; major_version
if not parse [
  public super "Test" "java/lang/Object" []
  public "<init>" [] void [
    aload_0
    invokespecial "java/lang/Object" "<init>" [] void
    return
  ]
  public static "main" ["java/lang/String" 1] void [
    getstatic "java/lang/System" "out" "java/io/PrintStream"
    ldc_w string "Hallo, Welt!"
    invokevirtual "java/io/PrintStream" "println" ["java/lang/String"] void
    return
  ]
] [
  any [
    'public (access_flags: or~ access_flags #{0001}) |
    'final (access_flags: or~ access_flags #{0010}) |
    'super (access_flags: or~ access_flags #{0020}) |
    'interface (access_flags: or~ access_flags #{0200}) |
    'abstract (access_flags: or~ access_flags #{0400}) |
    'synthetic (access_flags: or~ access_flags #{1000}) |
    'annotation (access_flags: or~ access_flags #{2000}) |
    'enum (access_flags: or~ access_flags #{4000})
  ]
  set x string! (this_index: constantClass x)
  set x string! (super_index: constantClass x)
  into [any [set x string! (append interfaces constantClass x)]]
  any [
    (field: copy #{0000})
    any [
      'public (field: or~ field #{0001}) |
      'private (field: or~ field #{0002}) |
      'protected (field: or~ field #{0004}) |
      'static (field: or~ field #{0008}) |
      'final (field: or~ field #{0010}) |
      'volatile (field: or~ field #{0040}) |
      'transient (field: or~ field #{0080}) |
      'synthetic (field: or~ field #{1000}) |
      'enum (field: or~ field #{4000})
    ]
    set x string! (append field toShort constantUTF8 x)
    FieldDescriptor
    (append field toShort constantUTF8 fd)
    (append field toShort 0 append fields field)
  ]
  any [
    (method: copy #{0000} max_locals: 1)
    any [
      'public (method: or~ method #{0001}) |
      'private (method: or~ method #{0002}) |
      'protected (method: or~ method #{0004}) |
      'static (method: or~ method #{0008} max_locals: 0) |
      'final (method: or~ method #{0010}) |
      'synchronized (method: or~ method #{0020}) |
      'bridge (method: or~ method #{0040}) |
      'varargs (method: or~ method #{0080}) |
      'native (method: or~ method #{0100}) |
      'abstract (method: or~ method #{0400}) |
      'strict (method: or~ method #{0800}) |
      'synthetic (method: or~ method #{1000}) |
    ]
    set x string! (append method toShort constantUTF8 x)
    MethodDescriptor
    (append method toShort constantUTF8 md max_locals: add max_locals md_pc)
    (code: copy #{})
    opt [
      into [
        any [
          'aload_0 (append code #{2A} max_locals: max max_locals 1) |
          'getstatic copy x_cmd [2 string!] FieldDescriptor (append code rejoin [#{B2} toShort constantFieldRef x_cmd/1 x_cmd/2 fd]) |
          'iconst_0 (append code #{03}) |
          'invokespecial copy x_cmd [2 string!] MethodDescriptor (append code rejoin [#{B7} toShort constantMethodRef x_cmd/1 x_cmd/2 md]) |
          'invokevirtual copy x_cmd [2 string!] MethodDescriptor (append code rejoin [#{B6} toShort constantMethodRef x_cmd/1 x_cmd/2 md])|
          'ldc_w (append code #{13}) [
            'string set x string! (append code toShort constantString x)
          ] |
          'return (append code #{B1}) |
          set x word! (print rejoin ["Unk.Inst.: " x] break)
        ]
      ]
    ]
    (either empty? code [append method toShort 0 ] [
      append method rejoin [toShort 1 toShort constantUTF8 "Code"
        toInt add 12 length? code
        toShort 5
        toShort max_locals
        toInt length? code
        code
        toShort 0
        toShort 0
      ]
    ] append methods method)
  ]
  end
] [print "Invalid Syntax"]
write datei toShort add 1 length? constant_pool ; constant_pool_count
write datei rejoin constant_pool ; constant_pool[constant_pool_count-1]
write datei access_flags ; access_flags
write datei toShort this_index ; this_class
write datei toShort super_index ; super_class
write datei toShort length? interfaces ; interfaces_count
foreach interface interfaces [write datei toShort interface] ; interfaces[interfaces_count]
write datei toShort length? fields ; fields_count
write datei rejoin fields ; field_info fields[fields_count]
write datei toShort length? methods ; methods_count
write datei rejoin methods ; methods[methods_count]
write datei toShort 0 ; attributes_count       
; attributes[attributes_count]


close datei
Kurz hinter if not parse [ beginnt das Programm das kompiliert wird

Survari

  • Beiträge: 2
    • Profil anzeigen
    • Triploit auf Github
Gespeichert
« Antwort #3 am: 05. January 2017, 18:54 »
Es war so klar das ich irgendetwas vergesse... Hier erstmal der Link: https://github.com/Triploit-org/ny-6

Ich empfehle, wenn, ein stabiles Release (EDIT: empfehle V3.4.9, Sprungmarken müssen noch einmal ausgebessert werden) herunterzuladen, denn ich habe ein paar Funktionen eingefügt die viele Bugs erzeugen und bisher noch keine Zeit gehabt sie zu fixen.

Dann mal zu Svenska:

Die Sprache hat eine Virtuelle Laufzeitumgebung (wenn du das meinst), aber nur wenn sie interpretiert wird, beim Compiler, ist C++ ja für den Rest verantwortlich ;)

1. (Zu Punkt 1) Damit ich mit dem Parser leichteres Spiel habe ;) Ich öehne nicht direkt an Assembler an, nutze nur einen ähnlichen Syntax und ähnliche Befehle.
2. (... 2) Die Zwei Funktionsenden kommen daher, da "end" das Programm beendet und "endf" die Funktion schließt. "end" bewirkt überall im Code ein exit(0). "endf" ist wieder eine erleichterung für den Parser, um den Benutzer zu verstehen.
3. Es gibt wie du schon herausgefunden hast, einmal einen Integer und zum anderen 'nen String den man sich als Typ auswählen kann.
4. Ja, es fehlt, wird aber vom Parser soweit ignoriert. :D

Zu MasterLee:

Danke für deine tolle Ergänzung wegen der Website ;) , ich hätte es mal trotzdem hinschreiben sollen :)
Deine Sprache sieht echt hammer aus! Ich würde sowas nicht hinbekommen, der Parser würde mich umhauen :D Ob es die irgendwo zum Download gibt?



MfG :)
« Letzte Änderung: 05. January 2017, 19:15 von Survari »
Es gibt 11 arten von Menschen: Die, die Binärcode verstehen, die, die es nicht tun und die, denen dieser Witz auf die nerven geht.

MasterLee

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 05. January 2017, 21:43 »
Danke für deine tolle Ergänzung wegen der Website ;) , ich hätte es mal trotzdem hinschreiben sollen :)
Deine Sprache sieht echt hammer aus! Ich würde sowas nicht hinbekommen, der Parser würde mich umhauen :D Ob es die irgendwo zum Download gibt?
Das war eigentlich der Parser mit einen Stück Beispiel Kode. Der Kode ist folgender:
  public super "Test" "java/lang/Object" []
  public "<init>" [] void [
    aload_0
    invokespecial "java/lang/Object" "<init>" [] void
    return
  ]
  public static "main" ["java/lang/String" 1] void [
    getstatic "java/lang/System" "out" "java/io/PrintStream"
    ldc_w string "Hallo, Welt!"
    invokevirtual "java/io/PrintStream" "println" ["java/lang/String"] void
    return
  ]
Und das ist eigentlich quasi normaler JAVA-VM Kode
Das was über und unter den Kode Teil steht es wie gesagt der Code des Kompilers der dann den Bytecode erzeugt. Der Parser ist über das Standard Rebol parse realisiert. Genau das parse mit dem sich Rebol selber parst. Oder anders gesagt mein Kode ist eigentlich nur die Anfänge der Spezifizierung einer Rebol DSL für die Erzeugung von Java Bytecode.

Svenska

  • Beiträge: 1 778
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 06. January 2017, 03:42 »
Naja, wenn es dir allein um den Parser geht, kannst du auch gleich die übliche Konvention von vielen Assemblersprachen benutzen. Das macht es jedenfalls einfacher, in die Sprache einzusteigen (weil es dann für dein Einstieg nur ein High-Level-Assembler ist und keine eigene Sprache). Bei kleinen ARMs gibt es z.B. #4 (Immediate), R1 (Wert), [R2] (Dereferenzierung) und ein paar für dich eher uninteressantere Varianten. Die Unix-Welt fällt da etwas raus, die finde ich persönlich auch deutlich schlechter lesbar.

Ansonsten ist deine Sprache halt schlicht ein kleiner Assembler, ganz nett. Wenn du ein paar Programme damit geschrieben hast (also jenseits von Hallo-Welt), dann weißt du schon, was ganz gut funktioniert und was total scheiße ist. ;-)

Die Runtime ist eigentlich viel wichtiger als die Kernsprache (und die Entscheidung, was in die Runtime gehört und was nicht). Davon hängt ab, was du überhaupt machen kannst und wie gut bestimmte Dinge funktionieren.

Zum Parser gibt's eigentlich nur zu sagen, dass man den zwar handklopfen kann, aber nicht muss. Zu lex und yacc gibt es sicher auch deutsche Tutorials, wenn du dir das auf Englisch nicht antun möchtest, aber das sind klassische Ansätze dazu. Damit kannst du deiner Sprache eine deutlich mächtigere Grammatik geben - und eine ordentliche Syntaxprüfung (aber keine ordentlichen Fehlermeldungen, das bleibt dann bei "syntax error in line 42").
« Letzte Änderung: 06. January 2017, 03:44 von Svenska »

 

Einloggen