C'est celui annoncé dans la pratique EP du département FMS de l'Université Meiji le 17 septembre 2020. Eh bien, je m'en fiche, alors jetez un œil. J'ai mis le Code source sur github.
Le programme lui-même est implémenté en utilisant un langage appelé Processing, qui semble être une couverture de java. L'écran d'exécution se compose d'un éditeur de texte, d'une console et d'un écran d'aperçu.
Fondamentalement, il peut être écrit dans la même syntaxe que java. Il y a certaines parties qui sont différentes de java, donc je vais vous expliquer un peu.
La déclaration de variable a la syntaxe suivante.
let a = 10;
println(a); // -> 10
println(typeof(a)); // -> int
let b: float = 10;
println(typeof(b)); // -> float
Types intégrés actuellement disponibles
int
float
bool
string
4 types et leurs arrangements. Si vous en avez envie, je veux l'augmenter bientôt. La déclaration du tableau peut être écrite comme suit.
let arr1 = {0, 1, 2};
let arr2 = {{0, 1}, {1, 2}};
let arr3 = int[2][2]; // make {{0, 0}, {0, 0}}
Aussi, il y a Rust dans un langage avec une grammaire similaire, mais dans le cas de Rust, si vous le déclarez avec let
, cela devient une constante, et si vous ajoutez mut
, cela devient une variable, alors que dans ce langage, let
La variable est déclarée avec. Je n'ai pas encore fait de déclaration constante, mais je pense en faire une déclaration `` const '' comme JavaScript.
Vous pouvez également écrire ce qui suit.
let c, d = 10, 20;
println(c, d); // -> 10 20
c, d = d, c; // swap
println(c, d); // -> 20 10
Les fonctions peuvent être définies avec la syntaxe suivante.
fn add(a: int, b: int) -> int {
return a + b;
}
Comme il est fait par beaucoup de travail urgent, il existe de nombreuses fonctions intégrées qui ne peuvent pas être prises en charge par rapport à d'autres langages, et il y a beaucoup de problèmes tels que ne pas pouvoir prendre en charge l'orientation objet en premier lieu. s'il vous plaît, pardonnez-moi...
Ensuite, voyons comment ce programme fonctionne.
Génère une fenêtre (écran correspondant) dans l'écran d'aperçu. Cela peut être fait de la même manière que le traitement.
Dans cet exemple, l'écran avec le rapport correspondant à la fenêtre 800x600 s'affiche sur l'écran d'aperçu. Vous pouvez également spécifier la couleur d'arrière-plan en utilisant la fonction `` background () '', tout comme Processing.
Utilisez la fonction println () '' pour imprimer une chaîne sur la console. Si vous ne souhaitez pas imprimer de saut de ligne en fin de ligne, vous pouvez également utiliser la fonction
print () ''.
La possibilité d'entrer dans la console n'a pas encore été implémentée. Pardon.
Similaire au traitement, vous pouvez écrire un traitement image par image en définissant la fonction `` draw () ''. L'exemple suivant implémente le comportement consistant à changer progressivement la couleur d'arrière-plan du noir au blanc.
Implémentation de la fonction à appeler lorsque la souris est cliquée si les fonctions mouseX
, mouseY '' et
mousePressed () '' qui indiquent les coordonnées de la souris sont définies. Ainsi, vous pouvez écrire le processus suivant pour inverser la partie cliquée et ses carrés supérieur, inférieur, gauche et droit.
Le code est en rupture de stock, je le posterai donc séparément.
size(500, 500);
let board = int[5][5];
let count = 0;
board[0][2] = 1;
board[1][1] = 1;
board[1][2] = 1;
board[2][3] = 1;
board[2][4] = 1;
board[3][3] = 1;
fn draw() -> void {
background(0);
fill(255, 255, 0);
count = 0;
for(let i = 0; i < 5; i++) {
for(let j = 0; j < 5; j++) {
if(board[i][j] == 1) {
rect(100 * i, 100 * j, 100, 100);
}
else {
count++;
}
}
}
if(count == 25) {
textSize(32);
textAlign(CENTER);
text("CLEAR!", width / 2, height / 2);
}
}
fn mousePressed() -> void {
let x = mouseX / 100;
let y = mouseY / 100;
for(let i = max(0, x - 1); i <= min(4, x + 1); i++) {
board[i][y] = 1 - board[i][y];
}
for(let i = max(0, y - 1); i <= min(4, y + 1); i++) {
board[x][i] = 1 - board[x][i];
}
board[x][y] = 1 - board[x][y];
}
Dans le programme ci-dessus, certaines fonctions que vous connaissez dans Traitement sont apparues. Certaines des fonctions disponibles dans Processing ont également été implémentées pour être utilisées dans ce langage homebrew. Les fonctions intégrées actuellement disponibles sont toutes les suivantes, avec ou sans traitement.
size()
background()
fill()
stroke()
strokeWeight()
textSize()
textAlign()
text()
circle()
rect()
ellipse()
println()
print()
millis()
random()
Passons maintenant à l'implémentation interne détaillée. À partir de ce moment, cela peut être un peu difficile pour ceux qui n'ont pas une connaissance insuffisante du traitement ou qui n'ont pas beaucoup d'expérience en programmation.
Il est implémenté en utilisant pleinement la fonction keyPressed '',
keyPressed () '', la fonction keyTyped () '', etc. Tout d'abord, jetons un coup d'œil au code suivant dans la fonction
draw () ''.
if(keyPressed) {
if(prevKey.equals(String.valueOf(key))) {
if(keyt < dur) keyt++;
else {
keyt = dur / 2;
if(key != CODED) keyTyped();
}
}
else {
keyt = 0;
if(key != CODED) keyTyped();
}
}
else {
keyt = 0;
prevKey = "";
}
prevKey
est une variable qui contient la clé précédemment entrée. keyt
représente le nombre d'images écoulées depuis la saisie de la clé. dur '' est la valeur définie comme seuil pour
keyt ''.
Si keyt '' dépasse le seuil
dur '' alors que la même clé que la dernière fois est entrée, remplacer dur / 2 '' par
keyt '' et key '' Lorsqu'il ne s'agit pas d'une clé codée telle que ou Control, la fonction
keyTyped () '' est appelée. Si une touche différente de la précédente est saisie, keyt
n'est pas coché et 0 '' est affecté à
keyt. De plus, la fonction
keyPressed () '' a l'implémentation suivante.
void keyPressed() {
if(key == CODED) {
if(keyCode == LEFT) {
cursor.prev();
beforeCursor.prev();
}
else if(keyCode == RIGHT) {
cursor.next();
beforeCursor.next();
}
else if(keyCode == UP) {
cursor.up();
beforeCursor.up();
}
else if(keyCode == DOWN) {
cursor.down();
beforeCursor.down();
}
else {
keyFlags.put(keyCode, true);
}
}
}
cursor
, beforeCursor
sont des objets de type Cursor
et ont les méthodes line
, row
pour représenter les lignes et les colonnes. curseur '' représente la position actuelle du curseur.
beforeCursorest utilisé pour implémenter la sélection de plage, je vais donc l'expliquer plus tard. De plus,
keyFlagsest un objet de type
HashMap <Integer, Boolean> '', et indique si keyCode
indiquant une clé codée autre que la croix est entré.
Cette fonction keyPressed () '' déplace le curseur lorsque la touche croisée est enfoncée et change les
keyFlags '' lorsqu'une autre touche codée est saisie. .. De plus, pour changer les keyFlags
lorsque la touche dont keyFlags
est true
est relâchée, la fonction `` keyReleased () '' est définie comme suit.
void keyReleased() {
if(key == CODED) {
if(keyFlags.get(keyCode) != null) {
keyFlags.put(keyCode, false);
}
}
keyPressed = false;
}
Le processus de changement de keyPressed '' en
false '' ne devrait pas être nécessaire, mais si vous ne l'écrivez pas pour une raison quelconque, le comportement de keyPressed
sera étrange, donc je l'écrirai.
La fonction `` keyTyped () '' décrit le comportement correspondant à chaque touche saisie. Si vous l'écrivez ici, ce sera long, donc si vous voulez le voir, vous voudrez peut-être le vérifier depuis Lien du code source.
La chaîne saisie est stockée dans un objet de type ʻArrayList <String>
`ligne par ligne. Il les affiche simplement dans l'ordre.
Lorsque le nombre de lignes dépasse la plage d'affichage de l'éditeur, la barre de défilement s'affiche sur le côté droit de l'éditeur. La hauteur à laquelle la chaîne de caractères est sortie change en fonction de la position de la barre de défilement.
Pour vous appeler un éditeur, si vous pouvez simplement entrer des caractères, ce n'est pas différent du Bloc-notes, vous avez donc besoin de certaines fonctions. Les fonctions de l'éditeur actuellement implémenté sont les suivantes.
(
pour )
et }
pour {
Lors de la mise en œuvre de la sélection de plage, l'un des beforeCursor '' et du
curseur '' est le début de la plage et l'autre est la fin de la plage. Le reste est foiré dans la fonction `` keyTyped () '', donc si vous êtes intéressé, jetez un œil.
La console stocke également la chaîne dans un objet de type ʻArrayList <String>
`. L'affichage est le même que celui de l'éditeur.
Le langage implémenté cette fois est un simple langage d'interprétation typé dynamiquement. Cependant, je n'aime pas les langages typés dynamiquement, donc le code ressemble à un langage typé statiquement faisant l'inférence de type. Le flux de traitement est un peu spécial, et l'analyse de la phrase originale et l'analyse de la syntaxe sont effectuées, et l'arbre de syntaxe abstraite est interprété et exécuté, mais celui implémenté cette fois est une implémentation approximative qui omet diverses choses. Je suis. Par exemple, envisagez d'exécuter le code suivant.
let a = 10;
À ce stade, la classe `` Lexer '' produit le résultat de calcul suivant.
[
Token("let", "let"),
Token("id", "a"),
Token("expr", "expr"),
Token("int", "10"),
Token("endExpr", "endExpr"),
Token("endLet", "endLet")
]
C'est un objet de type «ʻArrayList Token '' a deux champs,
kind '' et value ''.
Token (a, b) '' est écrit comme Token '' avec la valeur de
kind '' comme a '' et
valeur '' comme b ''. Considérez-le comme représentant un objet type. Ensuite, ce tableau est interprété comme une séquence d'instructions et exécuté. L'exécution de l'instruction
let '' se fait par le code suivant.
.
.
.
else if(res.get(i).kind.equals("let")) {
ArrayList<String> vars = new ArrayList<String>();
ArrayList<String> values = new ArrayList<String>();
i++;
String type = "", exprType = "";
if(res.get(i).kind.equals("type")) {
type = res.get(i).value;
i++;
}
while(!res.get(i).kind.equals("endLet")) {
if(res.get(i).kind.equals("id")) {
vars.add(res.get(i).value);
varNames.add(loc + "$" + res.get(i).value);
}
else if(res.get(i).kind.equals("expr")) {
ArrayList<Token> expr = new ArrayList<Token>();
i++;
int exprNum = 0;
while(exprNum > 0 || !res.get(i).kind.equals("endExpr")) {
if(res.get(i).kind.equals("expr")) exprNum++;
if(res.get(i).kind.equals("endExpr")) exprNum--;
expr.add(res.get(i));
i++;
}
exprType = calc(expr, loc);
values.add(expr.get(0).value);
}
i++;
}
int vs = values.size();
for(int j = 0; j < vars.size(); j++) {
if(j < vs) {
if(type.isEmpty()) {
variables.put(loc + "$" + vars.get(j), new Variable(exprType, vars.get(j), values.get(j)));
}
else {
variables.put(loc + "$" + vars.get(j), new Variable(type, vars.get(j), values.get(j)));
}
}
else {
if(type.isEmpty()) {
variables.put(loc + "$" + vars.get(j), new Variable(exprType, vars.get(j), values.get(vs - 1)));
}
else {
variables.put(loc + "$" + vars.get(j), new Variable(type, vars.get(j), values.get(vs - 1)));
}
}
}
}
res
est une variable de type ʻArrayList <Token>
qui reçoit le résultat du calcul de
Lexer``. `` Variables '' est une variable de type `` HashMap <String, Variable> '' qui stocke des variables. `` varNames`` est une variable de type
ʻArrayList
qui stocke les noms des variables avec la portée à l'esprit. La gestion de l'étendue variable utilise $ ''. Plus précisément, le nom de portée de la variable ```a
dans la zone globale est main $ a
, et la variable définie dans la fonction func () '' dans la zone globale. Le nom considérant la portée de ```a
est main $ func $ a
.
Puisque ʻexpr`` to
ʻendExpr représente une expression, passez la colonne` `Token
de ʻexpr`` à
ʻendExprà la fonction
calc () . Ce faisant, vous pouvez calculer la formule. De cette façon, vous pouvez exécuter l'instruction
let ''.
Pour les autres instructions, la colonne Token '' est générée et exécutée de la même manière, donc reportez-vous à l'implémentation de la fonction
statement () '' pour l'implémentation détaillée de chacune.
Il y a beaucoup d'autres parties qui peuvent être expliquées sur la mise en œuvre, mais la fraîcheur est la vie de l'histoire, donc je voudrais terminer l'explication ici car je souhaite publier un article le jour où ce travail est annoncé. Si vous avez des demandes, des questions, des suggestions, des suggestions, des railleries, des ridicules, etc. que vous aimeriez que nous ajoutions des commentaires, veuillez commenter cet article ou répondre directement à Mon compte Twitter. Ou envoyez un DM.
Nous nous excusons profondément pour la mise en œuvre, les explications diverses et les fins diverses. Pardon.
Si vous souhaitez obtenir une explication plus détaillée et plus polie de l'implémentation du système de traitement du langage, veuillez consulter cet article.
Recommended Posts