Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Projets de programmation


Index du Forum » Projets de programmation » Compylateur
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Compylateur

Posté le 08/05/2020 14:00

Bonjour à tous !

Il y a quelques temps j'ai fait un 'compilateur' qui permet d'exécuter un algorithme en langage naturel en le 'traduisant' en Python. Le code est atroce et repose sur un remplacement entre les commandes en langage naturel et les commandes en Python (à coup de dictionnaires et de tests conditionnels )… J'aimerais faire de ce projet un 'vrai' compilateur (on reste sur du Python ). Et j'ai quelques questions :

- La phase d'analyse lexicale repose pour l'instant sur une recherche et un replacement, avec un dictionnaire qui contient en clés les commandes en langage naturel, et en items, les commandes correspondantes en Python… Je me doute que ce n'est pas pertinent… En fait l'analyse lexicale est mélangée à la phase d'analyse syntaxique.

- Comment faire pour basculer du langage naturel au Python ? Faut-il forcément passer par un hard code, ou est-ce que d'autre technique plus esthétiques existent ?

- L'analyse syntaxique est un bête replace basé sur un dico… Du coup ça revient à la question précédente : comment éviter le hard code ?

- La phase sémantique… Je ne suis pas sûr d'avoir bien compris toutes les subtilités… Dans mon cas, après le remplacement bête et méchant, la syntaxe Python n'est pas bonne, du coup je passe à travers différents tests conditionnels pour avoir un 'vrai' script fonctionnel… Encore une fois le hard code à coup de if me plaît moyen…

- En derniers je refait un passage sur mon code généré et j'ajoute les alinéas. Est-ce que je devrais les gérer plus tôt (je pense à la phase d'analyse syntaxique… mais le placement des alinéas dépend du contexte du code, et sur une ligne donnée je vois pas trop comment faire…

Merci d'avance !


Précédente 1, 2, 3, 4, 5, 6 ··· 10 ··· 18, 19, 20 Suivante
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 11/05/2020 08:52 | #


Ah ok du coup la méthode : TOKEN(classe_du_token, valeur) est bien… ? Imaginons que le lexer me renvoie ça :
TOKEN(COM, 'if')
TOKEN(MOT, 'a')
TOKEN(VERBE, 'est')
TOKEN(COMP, 'supérieur')
TOKEN(PREP, 'à')
TOKEN(CHIFFRE, '12')


Ce serait bien ? Et si dans le code il se base sur le fait d'avoir un TOKEN(COM, 'if') pour savoir que a est un mot et non un verbe, c'est bon… ?
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Lephenixnoir En ligne Administrateur Points: 24645 Défis: 170 Message

Citer : Posté le 11/05/2020 08:58 | #


Ton flux de tokens a une bonne tête oui. Par contre :

Et si dans le code il se base sur le fait d'avoir un TOKEN(COM, 'if') pour savoir que a est un mot et non un verbe, c'est bon… ?

Non, surtout pas ! Le lexer doit traiter les mots indépendamment du contexte. Dans cette situation, tu devrais plutôt laisser MOT "a" (← cette notation est plus courte donc si tu permets, je vais écrire comme ça) et laisser le parser décider dans le contexte si c'est un verbe ou un nom de variable. En particulier, après un COM "if" le parser demandera un nom de variable donc tu pourras automatique faire une "promotion".
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 11/05/2020 09:01 | #


Okay, du coup les tokens MOT vont être un peu fourre-tout ?
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Lephenixnoir En ligne Administrateur Points: 24645 Défis: 170 Message

Citer : Posté le 11/05/2020 09:03 | #


Oui, dans ton cas il y a pas mal d'ambiguité donc le parser aura pas mal de boulot.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 11/05/2020 09:06 | #


Okay !

Pour le lexer je pensais faire des grandes listes : verbe = ["prend", "demander", "est"…] c'est bien ? (le système de liste est aussi valable pour les perposition, les commandes, les comparaison… )
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Lephenixnoir En ligne Administrateur Points: 24645 Défis: 170 Message

Citer : Posté le 11/05/2020 09:26 | #


Tu peux, mais il faut utiliser des ensembles : verbe = { "prend", "demander", "est" ... } si tu veux pas faire exploser la complexité temporelle du truc.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 11/05/2020 09:31 | #


Des ensembles ? Je connais pas…

Pour l'instant j'ai ce code qui marche un peu :

class Token ():
    def __init__ (self, classe, valeur):
        self.classe = classe
        self.valeur = valeur

    def gen (self):
        return "TOKEN({0}, '{1}')".format(self.classe, self.valeur)

class Token_list ():
    def __init__ (self):
        self.liste = list()

    def add (self, token):
        self.liste.append (token)

    def gen (self):
        for i in self.liste:print(i.gen())

def lexer(prgm_src):
    verbe = ["est", "prend", "demander", "saisir", "allant"]
    prep = ["à", "la", "le", "que", "de", "ou", "entre", "plus", "moins"]
    com = ["si", "alors", "sinon", "pour", "tant"]
    comp = ["supérieur", "inférieur", "égal", "différent", "grand", "petit"]
    detect = [verbe, prep, com, comp]

    mot = prgm_src.split(" ")
    l_token = Token_list()
    for i in mot:
        token = str()
        for j in range(len(detect)):
            if i.lower() in detect[j]:token = ["VERBE", "PREP", "COM", "COMP"][j]
        if i.isdigit(): token = "CHIFFRE"
        elif not len(token):token = "MOT"
        l_token.add(Token(token, i))
    return l_token.gen()


Ajouté le 11/05/2020 à 09:50 :
C'est quoi l'intérêt des ensembles ici ?
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Lephenixnoir En ligne Administrateur Points: 24645 Défis: 170 Message

Citer : Posté le 11/05/2020 09:51 | #


Un ensemble c'est similaire à une liste mais :
• Ce n'est pas ordonné (il n'y a pas d'élément numéro 1/2/3, il n'y a pas de positions), c'est juste un gros sac d'éléments
• Tester si une valeur est dans l'ensemble (avec in) est beaucoup, beaucoup plus rapide qu'avec une liste, surtout quand l'ensemble contient beaucoup d'éléments
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 11/05/2020 09:51 | #


Ah ok Merci !

Ajouté le 11/05/2020 à 09:56 :
Pour le moment je teste juste des petits trucs basiques avec le lexer Pour l'instant le vocabulaire lui fait un peu défaut

Mais avec le code source : Si a est supérieur ou égal à 15 j'obtiens :
(COM, 'Si')
(MOT, 'a')
(VERBE, 'est')
(COMP, 'supérieur')
(LOGI, 'ou')
(COMP, 'égal')
(PREP, 'à')
(CHIFFRE, '15')


"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Lephenixnoir En ligne Administrateur Points: 24645 Défis: 170 Message

Citer : Posté le 11/05/2020 10:01 | #


Voilà, ça c'est une bonne sortie de lexer
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 11/05/2020 10:03 | #


Okay, niquel Prochaine étape : je prend mon bouquin de math et je regarde tous les programmes en langages naturel pour noter le max de mots possible

(je gère même plus petit que au niveau du lexer )

Ajouté le 12/05/2020 à 09:34 :
J'ai simplifié le code du lexer Je pense continuer à ajouter des mots et optimiser le code encore un peu et commencer le parser du coup…

J'ai du coup quelques questions…

- Quelle sortie on attend d'un parser (le lexer renvoie une liste, mais le parser ?)

- Les tokens vont être analysés par groupe… ? si les tokens ne matchent avec aucun pattern, je fait comment ? Je renvoie une erreur en mode : ERREUR : ARRÊTEZ DE CODER AVEC LES PIEDS NOM DE DIEU !!
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 12/05/2020 09:38 | #


Un parseur renvoie un AST.

Si les tokens ne matchent avec aucun pattern, tu renvoies une erreur oui
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 12/05/2020 09:44 | #


Okay, merci !!

AST, c'est quoi ? Un Arbre de Syntaxe … ? Et concrètement au niveau du code faut-il créer un objet ou est-ce qu'il y a des alternatives déjà existante… ? (sans parler d'utiliser un parser déjà fait )
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 12/05/2020 09:55 | #


Doit sûrement y avoir des trucs déjà existants mais tu peux facilement créer le tien (si ton but est d'apprendre et non de sortir la feature aussi vite que possible )

Perso j'avais utilisé un objet avec les propriétés :
- texte (nom de la fonction ou constante)
- args (les arguments de la fonction, s'il y en a)
- children (pour les structures)
- parent
- expectedType (pour les optimisations sur les casts)
- type

Après tu itères sur l'AST pour faire les optimisations (si besoin), et tu convertis l'AST en python ou autre.
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Lephenixnoir En ligne Administrateur Points: 24645 Défis: 170 Message

Citer : Posté le 12/05/2020 10:00 | #


Les tokens vont être analysés par groupe… ? si les tokens ne matchent avec aucun pattern, je fait comment ?

Le parser renverra "erreur de syntaxe", avec un peu de chance tu pourras dire à quel ligne/colonne. Inutile d'essayer de corriger l'erreur et de continuer à parser. Si le programme est syntaxiquement invalide, c'est comme {[}] : il ne veut rien dire.

Pour le parser il faut que tu utilises un générateur de parser, et en gros tu auras ce genre de situations :

• Le parser va reconnaître un motif comme A B C D et il sait que ça donne un noeud d'AST que j'appelle X
• Dans la définition de la grammaire, tu pourras mettre du code pour dire ce qu'il se passe quand ce motif est reconnu
• Et dans ce code le parser te donnera A, B, C et D, et tu devras renvoyer X, une classe de ton choix

Par exemple dans yacc ça donnerait :

X = A B C D { return makeXNode($1, $2, $3, $4); }

Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 12/05/2020 10:03 | #


Le but et d'apprendre comment se passe la compilation et de la comprendre ouaip !

Je conçois bien tes arguments, mais j'ai un peu de mal avec expectedType et type…

En lisant ça : https://en.wikipedia.org/wiki/Abstract_syntax_tree je pense simplifier un peu en gardant :
- le 'type' (ex. variable, constante)
- le 'paramètre' et son nom (ex. nom = 'a', valeur = 0)
- les enfants
- les parents


@Lephe : Okay, perso j'ai pas sauvé le numéro de la ligne, mais je peux changer ça Pour la reconnaissance de motifs ça sent le hard code x) En plus il faut gérer les promotions des tokens MOT
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Lephenixnoir En ligne Administrateur Points: 24645 Défis: 170 Message

Citer : Posté le 12/05/2020 10:08 | #


La promotion des tokens MOT c'est juste une règle en plus, cf. #175962.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 12/05/2020 10:11 | #


Okay ! Merci !

Pour le lexer j'envisage d'ajouter un token NOM est-ce pertinent ?

Gérer avec le lexer les parenthèses, crochets et accolades… c'est pas très utile, en langage naturel c'est très peu répandu de mettre des parenthèses… non ?
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Lephenixnoir En ligne Administrateur Points: 24645 Défis: 170 Message

Citer : Posté le 12/05/2020 10:17 | #


Écris ta grammaire, tu verras si t'as besoin de NOM.

Les parenthèses c'est un exemple enfin. x)
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 12/05/2020 10:20 | #


Le truc "expectedType" c'est plus un truc pour me simplifier la vie.

Si on a "A + B[0]" ça fera un AST :


{
    "text": "_add",
    "type": "
    "args": [{
        "text": "A",
        "type": "int",
        "expectedType": "numberOrVector",
    },{
        "text": "_valueInArray",
        "type": "int",
        "expectedType": "numberOrVector",
        "parent": "_add",
        "args": [{
            "text": "B",
            "type": "int[],
            "parent": "_valueInArray",
        },{
            "text": "0",
            "type": "numberLiteral",
            "parent": "_valueInArray",
        }]
    }]
}


Ton AST peut être un peu différent, par exemple en pratique j'utilise une pseudo fonction "_number_".

Dans mon langage si on donne un array à une fonction qui n'accepte pas un array, le premier élément de cet array est pris. Ca fait que ça peut être optimisé en "A + B".

Du coup faut dire que quand tu optimises ton AST, si tu as la fonction "_valueInArray" et que la valeur est 0, et que le type de l'argument où est "_valueInArray" n'est pas un array, tu peux optimiser en donnant directement l'array. C'est là que "expectedType" intervient, s'il n'était pas là il faudrait faire un lookup "quel type est attendu sur la fonction _add et sur le 2ème argument". Il n'est pas obligatoire mais il simplifie la vie (et rend le truc plus rapide vu qu'il n'y a pas de lookup à faire).
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 12/05/2020 10:27 | #


Ouaip je vais commencer par écrire la grammaire c'est une bonne idée

Oui, mais je répondais pas à ton exemple c'était une réflexion plus générale sur l'utilité pour le lexer de gérer les parenthèse et co

Au niveau du langage naturel, j'ai un petit problème : les fonctions mathématiques, j'ai vu plusieurs algo où c'est juste marqué : f est une fonction mathématiques et après ils utilisent f(x) n'importe quel humain comprends que f(x) est une fonction quelconque… mais le compilo va pas aimer la blague Du coup ça fait partit des limites ou une alternative est possible ? (à la limite c'est pas non plus le plus pressé…)
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Précédente 1, 2, 3, 4, 5, 6 ··· 10 ··· 18, 19, 20 Suivante

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 46 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd