Bis jetzt sind Sie wahrscheinlich mit einer oder mehreren Programmiersprachen vertraut. Aber haben Sie sich jemals gefragt, wie Sie Ihre eigene Programmiersprache erstellen könnten? Und damit meine ich
Eine Programmiersprache ist jede Regelmenge, die Zeichenketten in verschiedene Arten von Maschinencode-Ausgaben umwandelt.
Kurz gesagt, eine Programmiersprache ist nur eine Reihe vordefinierter Regeln. Und um sie nützlich zu machen, benötigen Sie etwas, das diese Regeln versteht. Und diese Dinge sind Compiler, Interpreter usw. Wir können also einfach einige Regeln definieren und dann, um sie zum Laufen zu bringen, können wir jede bestehende Programmiersprache verwenden, um ein Programm zu erstellen, das diese Regeln versteht, was unser Interpreter sein wird.
Compiler
Ein Compiler wandelt Code in Maschinencode um, den der Prozessor ausführen kann (z. B. C++-Compiler).
Interpreter
Ein Interpreter durchläuft das Programm Zeile für Zeile und führt jeden Befehl aus.
Möchten Sie es ausprobieren? Lassen Sie uns gemeinsam eine super einfache Programmiersprache erstellen, die magentafarbene Ausgaben in der Konsole erzeugt. Wir werden sie Magenta nennen.

Einrichtung unserer Programmiersprache
Ich werde Node.js verwenden, aber Sie können jede Sprache verwenden, um dem zu folgen, das Konzept wird dasselbe bleiben. Lassen Sie mich beginnen, indem ich eine `index.js`-Datei erstelle und die Dinge einrichte.
class Magenta {
constructor(codes) {
this.codes = codes
}
run() {
console.log(this.codes)
}
}
// For now, we are storing codes in a string variable called `codes`
// Later, we will read codes from a file
const codes =
`print "hello world"
print "hello again"`
const magenta = new Magenta(codes)
magenta.run()
Was wir hier tun, ist die Deklaration einer Klasse namens `Magenta`. Diese Klasse definiert und initialisiert ein Objekt, das für die Protokollierung von Text in der Konsole mit beliebigem Text verantwortlich ist, den wir über eine `codes`-Variable bereitstellen. Und vorerst haben wir diese `codes`-Variable direkt in der Datei mit ein paar "Hallo"-Nachrichten definiert.

OK, jetzt müssen wir einen sogenannten Lexer erstellen.
Was ist ein Lexer?
Okay, sprechen wir kurz über die englische Sprache. Nehmen Sie die folgende Phrase
Wie geht es Ihnen?
Hier ist "How" ein Adverb, "are" ein Verb und "you" ein Pronomen. Wir haben auch ein Fragezeichen ("?") am Ende. Wir können jeden Satz oder jede Phrase wie diese in viele grammatikalische Komponenten in JavaScript zerlegen. Eine andere Möglichkeit, diese Teile zu unterscheiden, besteht darin, sie in kleine Token zu zerlegen. Das Programm, das den Text in Token zerlegt, ist unser Lexer.

Da unsere Sprache sehr klein ist, hat sie nur zwei Arten von Token mit jeweils einem Wert
SchlüsselwortZeichenkette
Wir hätten eine reguläre Expression verwenden können, um Tokens aus dem `codes`-String zu extrahieren, aber die Leistung wäre sehr langsam. Ein besserer Ansatz ist es, jeden Charakter des `code`-Strings zu durchlaufen und Tokens zu erfassen. Erstellen wir also eine `tokenize`-Methode in unserer `Magenta`-Klasse – die unser Lexer sein wird.
Vollständiger Code
class Magenta {
constructor(codes) {
this.codes = codes
}
tokenize() {
const length = this.codes.length
// pos keeps track of current position/index
let pos = 0
let tokens = []
const BUILT_IN_KEYWORDS = ["print"]
// allowed characters for variable/keyword
const varChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'
while (pos < length) {
let currentChar = this.codes[pos]
// if current char is space or newline, continue
if (currentChar === " " || currentChar === "\n") {
pos++
continue
} else if (currentChar === '"') {
// if current char is " then we have a string
let res = ""
pos++
// while next char is not " or \n and we are not at the end of the code
while (this.codes[pos] !== '"' && this.codes[pos] !== '\n' && pos < length) {
// adding the char to the string
res += this.codes[pos]
pos++
}
// if the loop ended because of the end of the code and we didn't find the closing "
if (this.codes[pos] !== '"') {
return {
error: `Unterminated string`
}
}
pos++
// adding the string to the tokens
tokens.push({
type: "string",
value: res
})
} else if (varChars.includes(currentChar)) {
let res = currentChar
pos++
// while the next char is a valid variable/keyword charater
while (varChars.includes(this.codes[pos]) && pos < length) {
// adding the char to the string
res += this.codes[pos]
pos++
}
// if the keyword is not a built in keyword
if (!BUILT_IN_KEYWORDS.includes(res)) {
return {
error: `Unexpected token ${res}`
}
}
// adding the keyword to the tokens
tokens.push({
type: "keyword",
value: res
})
} else { // we have a invalid character in our code
return {
error: `Unexpected character ${this.codes[pos]}`
}
}
}
// returning the tokens
return {
error: false,
tokens
}
}
run() {
const {
tokens,
error
} = this.tokenize()
if (error) {
console.log(error)
return
}
console.log(tokens)
}
}
Wenn wir dies in einem Terminal mit `node index.js` ausführen, sollten wir eine Liste von Token in der Konsole sehen.

Definition von Regeln und Syntaxen
Wir wollen sehen, ob die Reihenfolge unserer Codes einer Regel oder Syntax entspricht. Aber zuerst müssen wir definieren, was diese Regeln und Syntaxen sind. Da unsere Sprache so klein ist, hat sie nur eine einfache Syntax: ein `print`-Schlüsselwort, gefolgt von einer Zeichenkette.
keyword:print string
Erstellen wir also eine `parse`-Methode, die unsere Token durchläuft und prüft, ob eine gültige Syntax gebildet wurde. Wenn ja, werden die notwendigen Maßnahmen ergriffen.
class Magenta {
constructor(codes) {
this.codes = codes
}
tokenize(){
/* previous codes for tokenizer */
}
parse(tokens){
const len = tokens.length
let pos = 0
while(pos < len) {
const token = tokens[pos]
// if token is a print keyword
if(token.type === "keyword" && token.value === "print") {
// if the next token doesn't exist
if(!tokens[pos + 1]) {
return console.log("Unexpected end of line, expected string")
}
// check if the next token is a string
let isString = tokens[pos + 1].type === "string"
// if the next token is not a string
if(!isString) {
return console.log(`Unexpected token ${tokens[pos + 1].type}, expected string`)
}
// if we reach this point, we have valid syntax
// so we can print the string
console.log('\x1b[35m%s\x1b[0m', tokens[pos + 1].value)
// we add 2 because we also check the token after print keyword
pos += 2
} else{ // if we didn't match any rules
return console.log(`Unexpected token ${token.type}`)
}
}
}
run(){
const {tokens, error} = this.tokenize()
if(error){
console.log(error)
return
}
this.parse(tokens)
}
}
Und schauen Sie mal – wir haben bereits eine funktionierende Sprache!

Okay, aber Codes in einer Zeichenkettenvariable zu haben, ist nicht so spaßig. Also legen wir unsere Magenta-Codes in eine Datei namens `code.m`. So können wir unsere Magenta-Codes von der Compiler-Logik trennen. Wir verwenden `.m` als Dateierweiterung, um anzuzeigen, dass diese Datei Code für unsere Sprache enthält.
Lassen Sie uns den Code aus dieser Datei lesen
// importing file system module
const fs = require('fs')
//importing path module for convenient path joining
const path = require('path')
class Magenta{
constructor(codes){
this.codes = codes
}
tokenize(){
/* previous codes for tokenizer */
}
parse(tokens){
/* previous codes for parse method */
}
run(){
/* previous codes for run method */
}
}
// Reading code.m file
// Some text editors use \r\n for new line instead of \n, so we are removing \r
const codes = fs.readFileSync(path.join(__dirname, 'code.m'), 'utf8').toString().replace(/\r/g, "")
const magenta = new Magenta(codes)
magenta.run()
Gehen Sie eine Programmiersprache erstellen!
Und damit haben wir erfolgreich eine winzige Programmiersprache von Grund auf neu erstellt. Sehen Sie, eine Programmiersprache kann so einfach sein wie etwas, das eine bestimmte Aufgabe erfüllt. Sicher, es ist unwahrscheinlich, dass eine Sprache wie Magenta jemals nützlich genug sein wird, um Teil eines beliebten Frameworks zu sein, aber jetzt wissen Sie, was dazu gehört, eine zu erstellen.
Den Himmel gesetzt sind wirklich die Grenzen. Wenn Sie tiefer eintauchen möchten, folgen Sie diesem Video, das ich erstellt habe und in dem ich ein fortgeschritteneres Beispiel durchgehe. In diesem Video habe ich auch gezeigt, wie Sie Ihrer Sprache Variablen hinzufügen können.
Sehr schöne Einführung in Interpreter! Dies ist ein Thema, das ich nicht oft und nicht so klar behandelt sehe. Danke für die Erstellung!
Das war ganz, ganz toll
Was für eine komplexe Sprache. Dieses Beispiel wird eine gute Referenz für mich sein, danke für die Informationen.
Ich fand es toll!
Das Leben ist einfach und wir verkomplizieren es nur mit unserer Angst.
Ich würde nicht sagen, dass dieses Beispiel alles gelöst hat, aber das Video ist sehr gut.
Vielen Dank!
In dem Moment, in dem Sie Mathematik zu Ihrer Sprache hinzufügen möchten, wird all dieser Code sofort nutzlos. Sie müssen einen Parser separat erstellen, um tatsächlich etwas Gutes zu machen und nicht alles fest zu codieren.
Was ist das Beste für die Website-Geschwindigkeit:-
Einen eigenen Compiler für C++ bauen oder Go verwenden oder eine private Sprache erstellen?
Ich habe eine Version in Python namens Arbito erstellt, aber alles, was Sie tun können, ist `disp Hello World!` einzugeben. Andernfalls erhalten Sie die Meldung "
Syntax Error: error in line (line)".