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: 5500 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 ··· 5, 6, 7, 8, 9, 10, 11 ··· 18, 19, 20 Suivante
Shadow15510 Hors ligne Administrateur Points: 5500 Défis: 18 Message

Citer : Posté le 01/06/2020 13:30 | #


Du coup je peux faire un truc comme :

class GlobalVar():
    def __init__(self):
        self.l_token = TokenList()
        self.token_ahead = Token()


et je déclare en global : gl_var = GlobalVar() ?
"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: 24237 Défis: 170 Message

Citer : Posté le 01/06/2020 13:32 | #


Plutôt ça.

class Parser:
    def __init__(self, l_token):
        self.l_token = l_token
        self.token_ahead = l_token.get_next_token()

    def expect(self):
        # use self.l_token and self.token_ahead

    def atome(self):
        return self.expect([ "NUM", "VAR" ])

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

Citer : Posté le 01/06/2020 13:34 | #


Ah ok… je commence à voir le truc… Je retouche mon code

Ajouté le 01/06/2020 à 13:40 :
J'ai terminé le code est poussé sur le git

Il est pas commenté, mais les différentes parties du code sont bien séparée

Ajouté le 01/06/2020 à 16:05 :
J'ai réussi à faire une somme ! Il détecte les variables et les chiffres… Ce n'est pas encore récursif, mais la génération de l'AST fonctionne le programme affiche les tokens et l'AST. Pour le dernier, les différents niveaux sont symbolisés par des alinéas.

J'ai mis à jour le git : https://gitea.planet-casio.com/Shadow/Compylateur
"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: 24237 Défis: 170 Message

Citer : Posté le 01/06/2020 16:10 | #


Parfait ! T'es bien parti là. Faudra penser à créer ta classe d'AST à un moment car tu en auras besoin assez vite
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5500 Défis: 18 Message

Citer : Posté le 01/06/2020 16:11 | #


Elle est déjà faite

Avec une classe Branch pour ajouter des branches dans l'idée l'AST accepte des branches de type Branch qui peuvent être récursives

Edit : Le code de l'AST :
# --- Abstract Syntax Tree (AST) --- #

class AST():
    def __init__(self):
        self.branch = list()

    def add_branch(self, branch):
        self.branch.append(branch)

class Branch():
    def __init__(self, title, value, *sub_branch):
        self.title = title
        self.value = value
        self.sub_branch = list(sub_branch)

    def add_sub_branch(self, *sub_branch):
        for i in sub_branch: self.sub_branch.append(i)

    def gen(self):
        return self.title, self.value, self.sub_branch

def AST_gen(branch, tab = 0):
    for i in branch:
        print(tab * "  " + "{0} : {1}".format(i.gen()[0], i.gen()[1]))
        if i.gen()[2]: AST_gen(i.gen()[2], tab + 1)


Ajouté le 01/06/2020 à 16:21 :
J'ai juste un petit problème, token_ahead correspond au token regardé, mais j'ai pas de token d'avance ^^'
"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: 24237 Défis: 170 Message

Citer : Posté le 01/06/2020 16:27 | #


Ton alternance AST/Branche ne, euh... ne sert à rien. Voilà comment on fait normalement :

class ASTNode:
    def __init__(self, children = []):
        self.children = children
    def add_child(self, child):
        self.children.append(child)

class PlusNode(ASTNode):
    def __init__(self, children = []):
        ASTNode.__init__(self, children)
    def __str__(self):
        return "Plus({})".format(",".join(str(c) for c in self.children)))

etc, avec une classe par type de noeud qui va bien (ou alors tu ajoutes juste à ASTNode un nom de noeud si tu préfères faire comme ça).

J'ai juste un petit problème, token_ahead correspond au token regardé, mais j'ai pas de token d'avance ^^'

C'est le prochain token qui sortira quand tu appelleras expect(). Donc c'est bon.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5500 Défis: 18 Message

Citer : Posté le 01/06/2020 16:33 | #


C'est le prochain token qui sortira quand tu appelleras expect(). Donc c'est bon.


Justement, non x) ça marchais pas, au niveau de "l'armoçage" du parser j'avais un token_ahead sur VAR | NUM mais avec expect qui me renvoyais un None parce que je n'ai rien avant… Du coup j'ai du décalé pour ne plus avoir de problème, donc token_ahead est le token en cours de lecture et expect sert juste à lire le token et à vérifier que c'est le bon type…

Je comprends pas le code de l'AST… dans l'absolu, c'est grave qu'il soit comme ça le mien ? Ou est-ce que ça va gêner plus tard ?
C'est pas une alternance, dans mon code AST est le 'tronc' de l'arbre mais toutes les branches sont de type Branch, et dans les branches, je ne reviens pas à un autre AST.
"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: 24237 Défis: 170 Message

Citer : Posté le 01/06/2020 17:30 | #


Ah donc en fait ton AST c'est un objet AST qui contient des Branch qui contient des Branch et ainsi de suite ? Dans ce cas tu n'as pas besoin de l'objet AST tout en haut.
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 01/06/2020 17:33 | #


Yup, surtout que techniquement c'est pas des branches mais des nodes. Une branche ça connecte 2 nodes.
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Shadow15510 Hors ligne Administrateur Points: 5500 Défis: 18 Message

Citer : Posté le 01/06/2020 17:37 | #


Ouaip c'est ça
L'objet AST contient une liste de Branch qui elles sont récursives. Plusieurs Branch peuvent partir de l'AST.

J'ai pas trop regardé la théorie… j'ai fait ça au pif… x) Le coup des nodes, ça me parle pas du 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: 24237 Défis: 170 Message

Citer : Posté le 01/06/2020 17:41 | #


Ben un "node" c'est une "Branch" dans ton code. On appelle ça un noeud en référence au noeuds des arbres desquels partent les branches. Donc normalement pour coder un arbre tu n'as qu'un seul type d'éléments, qui contient des enfants du même type. C'est tout.
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 01/06/2020 17:41 | #




Les nodes c'est les cercles, les branches c'est les traits. Si ton objet Branch a une info autre que "node x est relié à node y" c'est pas une branche
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Shadow15510 Hors ligne Administrateur Points: 5500 Défis: 18 Message

Citer : Posté le 01/06/2020 17:44 | #


Ouaip… en gros mon code est foutu comme ça :

AST
- Branch #1 : titre, valeur
    - Branch #1 : titre, valeur
    - Branch #2 : titre, valeur
- Branch #2 : titre, valeur
    - Branch #1 : titre, valeur
    - Branch #2 : titre, valeur

"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: 24237 Défis: 170 Message

Citer : Posté le 01/06/2020 17:51 | #


Voilà, mais ça sert à rien d'avoir le AST en haut. Tu peux avoir ça :

Node:
  - type = "program"
  - children = [
    Node:
      - type = "statement"
      - children = [
        Node:
          - type = "variable"
          - name = "a"
          - children = []
        Node:
          - type = "int"
          - value = 42
          - children = []
      ]
  ]

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

Citer : Posté le 01/06/2020 18:09 | #


Ouaip… c'est juste… là j'en ai un peu marre, mais du coup je vais voir pour l'enlever

Ajouté le 01/06/2020 à 19:17 :
Au sujet du parser, j'ai retouché le code : token_ahead est devenu : token_watch et expect est devenu read. Ça colle mieux à la réalité…

Pour supprimer l'objet AST, je ferais ça demain je vois grosso-modo comment faire : rajouter une branche type = programme qui englobe tout vu que c'est récursif ça ne posera aucun problème…
"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: 24237 Défis: 170 Message

Citer : Posté le 01/06/2020 20:00 | #


Shadow15510 a écrit :
Au sujet du parser, j'ai retouché le code : token_ahead est devenu : token_watch et expect est devenu read. Ça colle mieux à la réalité…

Comme tu veux, mais sache que les conventions c'est bien lookahead et expect

Pour supprimer l'objet AST, je ferais ça demain je vois grosso-modo comment faire : rajouter une branche type = programme qui englobe tout vu que c'est récursif ça ne posera aucun problème…

Exactement ! Et cette branche sera produite par la fonction associée au symbole d'entrée de ta grammaire.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5500 Défis: 18 Message

Citer : Posté le 01/06/2020 20:17 | #


Rhôoo les conventions… J'en respecte aucune sur pas mal de plans, je vais pas commencer… Plus sérieusement, j'ai pas trouver comment amorcer le parser autrement doit y avoir une subtilité qui m'a échappée… ?

symbole d'entrée de ta grammaire
là je crois qu'on tiens la subtilité… xD C'est quoi ?
"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: 24237 Défis: 170 Message

Citer : Posté le 01/06/2020 20:19 | #


Aucune subtilité ne t'a échappé, c'est juste des noms. Toute la méthode est juste jusque-là.

Le symbole d'entrée c'est celui qui représente un programme entier. J'en ai donné un exemple tout à l'heure (ici).
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5500 Défis: 18 Message

Citer : Posté le 01/06/2020 20:23 | #


Ah ok… mais comment je peux amorcer le parser pour le premier token ? Si je respecte les… conventions… je contrôle le token suivant et je renvoie le type du token précédent…mais quand je contrôle le premier token je renvoie un token qui… n'existe pas… Avec ma méthode, le token renvoyer est celui qui est analysé… du coup j'ai pas de dé-phasage et pas d'erreur…
"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: 24237 Défis: 170 Message

Citer : Posté le 01/06/2020 20:29 | #


Tu dois charger le premier token dans le lookahead dès la création du parser, c'est tout (?)
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5500 Défis: 18 Message

Citer : Posté le 02/06/2020 08:41 | #


Aha c'est ça que j'ai pas

Pour l'AST, j'ai effectivement confondu les Nodes et les Branchs, je corrige ça en même temps que je supprime l'objet inutile !

Du coup je ré-essaye de repartir sur un truc plus académique avec token_ahead et expect

Ajouté le 02/06/2020 à 09:07 :
J'ai compris le problème de token_ahead et expect… je vais essayer d'expliquer, mais je promet rien xD

En gros mes tokens c'est ça :

   +-----+  +-----+  +-----+
X  | VAR |  |  +  |  | VAR |
   +-----+  +-----+  +-----+


Avec X le token_ahead au tout début, avant le parser.

- Initialisation du parser, token_ahead regarde VAR et renvoie rien.
- atome_1 = parser.atome() là on a un problème token_ahead regarde + et renvoie une erreur syntaxe car il attend VAR.
- Arrêt de l'exécution

Si je n'initialise par token_ahead :
- atome_1 = parser.atome() : token_ahead passe sur VAR, tout va bien c'est ce que l'on attend, mais cela renvoie le token précédent, soit un magnifique… None.
- la valeur de
atome_1 ne veut plus rien dire, et même si je n'ai pas d'erreurs par la suite, c'est complètement inexploitable…
"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 ··· 5, 6, 7, 8, 9, 10, 11 ··· 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 74 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