IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++Builder Discussion :

Coder DFM parser


Sujet :

C++Builder

  1. #1
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 766
    Par défaut Coder DFM parser
    Je jette une bouteille à la mer ...

    Un fichier DFM est utilisé dans le monde Delphi/ C++ Builder pour la définition des écrans
    Une entête .h, une source .cpp et un DFM crée une unité


    Qui à déjà coder un parser de fichier DFM? Idéalement en C++?
    Que penser-vous de ma proposition (*)

    Les raisons du pourquoi de ce DFM parser ne sont pas importantes

    Les 2 problèmes:
    1. Je n'ai pas trouvé la grammaire d'un fichier DFM
    2. Il n'y a pas de forcément de délimiteurs. Par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        Caption = 
          #201'videmment, si ceci est votre premi'#232're visite, nous vous inviton' +
          's '#224' consulter la FAQ en cliquant sur le lien ci-dessus. Vous dev' +
          'rez peut-'#234'tre vous inscrire avant de pouvoir envoyer des message' +
          's : cliquez sur le lien d'#39'inscription ci-dessus pour cela. Pour ' +
          'commencer '#224' lire les messages, s'#233'lectionnez le forum que vous vo' +
          'ulez visiter depuis la liste ci-dessous.'
        WordWrap = True

    Et en plus, après réflexion et commencer à en faire un, j'ai l'impression que faire une machine à états directement est une erreur.
    Parce que cette machine va devenir assez grosse pour gérer tous le cas. Et donc la maintenance assez pénible à un moment.
    Surtout parce que ne connaissant pas la grammaire, il y a toujours un risque de rajouter une correction.

    Ce que je pense faire c'est:
    1. Découper le fichier en token (algo 1)
    2. Donner ces token à une machine à états (algo 2)
    3. Cette machine va utiliser des XXX pour analyser les valeurs, construire un arbre, ...


    Et ainsi l'algo 1 et l'algo 2 devraient rester assez petits et ne pas être modifiés dans le temps.
    En effet pour la machine le seul point changeant ce sont les valeurs et éventuellement le 'object', 'inherited' (j'ai vu passer un 'inline')
    Juste rajouter un XXX.


    Mais pour l'algo 1:
    1) On ne peut pas découper "bêtement" en fonction des espaces. Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        Header.Font.Name = 'Segoe UI'

    2) On ne peut pas découper "bêtement", pour chaque ligne, en fonction ni des : ou ni des =. Exemple (non réel mais possible)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        Caption =
          #201'videmment, si ceci est votre premi'#232're visite: nous vous inviton' +
          's '#224' consulter la FAQ en cliquant sur le lien ci-dessus (= dev.net). Vous dev'

    Par contre, j'ai remarqué qu'il y avait 4 lignes distinctes
    • ligne 1: <space * - indentation>["object" | "inherit"]<space +>[nom]<space *>':'<space +>[type]<space *>{<space * ou + ???>'['<chiffre? nombre>']'}<EOL>
    • ligne 2: <space * - indentation>[key]<space * ou + ???>'='<space * ou + ???>{<space * ou + ???>[value]}<EOL>
    • ligne 3: <space * - indentation>[chunk of value]<space * ou + ???><EOL>
    • ligne 4: <space * - indentation>"end"<space * ou + ???><EOL>



    Et justement je sais découper ces lignes, et aussi quelle action entreprendre
    *) ligne 1, on cherche le ':', et ensuite on découpe les 2 parties avec les <spaces> au centre
    Action: créer un nouveau fils

    *) ligne 2, on cherche le '='
    Action: ajouter une nouvelle propriété et en fonction prendre/ attendre la valeur

    *) ligne 3, on ne la découpe pas
    Action: prendre ou ignorer la valeur. C'est notre XXX qui décide.

    *) ligne 4, on ne la découpe pas
    Action: le nouveau fils est fini, on repasse au parent


    Et donc ma proposition (*) pour découper mon fichier DFM (algo 1). La machine à états derrière sera triviale si on n’interprète pas les valeurs.
    Précondition: un fichier commence toujours par une ligne 1. Est-ce que des lignes vides sont autorisées avant je ne sais pas.


    Sur une ligne XXX,
    *) Si l'indentation est égale à l'indentation de la ligne précédente/ du bloc courant -> donc on a soit une ligne 1 soit une ligne 2

    *) Si l'indentation est supérieure à l'indentation de la ligne précédente/ du bloc courant -> donc on a une ligne 3
    On peut renforcer le test: Par défaut, l'indentation est 2 espaces par niveau.
    Donc ce serait (indentation + 2) (**)

    *) Si l'indentation est inférieure à l'indentation de la ligne précédente/ du bloc courant -> donc on a une ligne 4
    On peut renforcer le test: le 'end' est toujours au même niveau que le 'object'/ 'inherit' (**)



    ** -> mais il faut impérativement des fichiers bien formés. Donc le choix entre un algo strict ou pas.

  2. #2
    Membre éclairé
    Homme Profil pro
    Développeur C++
    Inscrit en
    Avril 2011
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Développeur C++
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2011
    Messages : 50
    Par défaut
    Bonjour,

    En faisant une petite recherche, j'ai trouvé trois liens intéressants : [1], [2], [3].
    Peut-être l'un d'entre eux pourra-t-il convenir.

  3. #3
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 766
    Par défaut
    Citation Envoyé par mcc39 Voir le message
    Il y a pleins de manques, rien qu'en lisant son site (après il faudrait faire des tests)

    Il ne gère pas les chaînes qui commencent par l'Unicode (*), ni les chaînes trop longues (*), ni le Z-Order ou assimilé (**)

    * ->
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
         Caption =
          #201'videmment, si ceci est votre premi'#232're visite: nous vous inviton' +
          's '#224' consulter la FAQ en cliquant sur le lien ci-dessus (= dev.net). Vous dev'
    ** -> C'est le '[' XXX ']'
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    object device_frame: Tdevice_frame [2]

    Citation Envoyé par mcc39 Voir le message
    Code assez difficile à lire

    Mais à ce que je comprends, il passe par la classe non documentée TParser.
    Difficile parce que c'est un système de "callback".

    Donc une bonne boîte noire que tu ne sais pas vraiment ce qu'elle fait.
    Le truc positif c'est la classe qui est utilisée par Embarcadero (à ce que j'ai compris)

    Moi je veux une grosse flexibilité (je sais je suis ch*ant)

  4. #4
    Membre Expert
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Billets dans le blog
    1
    Par défaut
    Salut,
    pour ma part je suis partit de l'approche inverse en recréant tous les fichiers DFM par de la partie "Resource" de l'exécutable ou de La DLL contenant les Forms Delphi ou C++ builder
    L'analyse du Stream Résultant permet d'extraire ensuite tous les forms contenues dans la partie RC_Data

    cdlt
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  5. #5
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 766
    Par défaut
    Citation Envoyé par DjmSoftware Voir le message
    pour ma part je suis partit de l'approche inverse en recréant tous les fichiers DFM par de la partie "Resource" de l'exécutable ou de La DLL contenant les Forms Delphi ou C++ builder
    L'analyse du Stream Résultant permet d'extraire ensuite tous les forms contenues dans la partie RC_Data
    Je ne l'ai pas précisé , mais moi c'est un outil pour:

    1) Extraire tous les uis et modifier les fichiers .h/ .cpp en ajoutant à la classe tous les uis en attributs, en modifiant le constructeur pour mettre les uis à NULL et en ajoutant 3-4 méthodes (create_ui, setup_ui, parent_ui, destroy_ui, ...)

    2) Et comme j'ai une version localisée pour chaque écran (screen_XXX -> screen_XXX_fr, screen_XXX_us, ... (*)), extraire toutes les chaînes de caractères des fichiers DFM localisés pour mettre mes tables de caractères à jour (ce ne sont pas que des tables, j'ai aussi pleins de fonctions dedans notamment get_screen_XXX_text)


    * -> les écrans localisés 'inherit' l'écran

  6. #6
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 766
    Par défaut
    Un autre exemple de valeur à gérer : la définition des colonnes est sur plusieurs lignes
    C'est actuellement le genre de truc que je ne gère pas et que je voudrais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
        object list_keys: TVirtualDrawTree
          Left = 10
          Top = 4
          Width = 331
          Height = 130
          BevelEdges = []
          BevelInner = bvNone
          BevelOuter = bvNone
          Color = clWhite
          Header.AutoSizeIndex = 0
          Header.Font.Charset = DEFAULT_CHARSET
          Header.Font.Color = clBlack
          Header.Font.Height = -11
          Header.Font.Name = 'Tahoma'
          Header.Font.Style = []
          Header.Options = [hoShowImages, hoVisible]
          TabOrder = 2
          TreeOptions.MiscOptions = [toFullRepaintOnResize, toWheelPanning]
          TreeOptions.PaintOptions = [toThemeAware]
          TreeOptions.SelectionOptions = [toFullRowSelect]
          Columns = <
            item
              Options = [coEnabled, coParentBidiMode, coParentColor, coVisible, coFixed]
              Position = 0
              Width = 220
            end
            item
              Options = [coEnabled, coParentBidiMode, coParentColor, coVisible, coFixed]
              Position = 1
              Width = 80
            end>
        end

  7. #7
    Membre Expert
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Billets dans le blog
    1
    Par défaut
    salut
    Ci-dessous un exemple de parser DFM qui pourrait peut être t'inspirer
    C'est du Delphi mais c'est très bien documenté
    http://www.felix-colibri.com/papers/...fm_parser.html

    Cdlt
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  8. #8
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 766
    Par défaut
    Citation Envoyé par DjmSoftware Voir le message
    C'est du Delphi mais c'est très bien documenté
    http://www.felix-colibri.com/papers/...fm_parser.html
    J'ai répondu au post 3: en lisant le site, il y a des manques. Donc il faut faire une série de tests.

    Et en plus, c'est typiquement ce que je disais dans le post initial: tu codes une machine à états incomplète, et l'algo fait déjà ~120 lignes

  9. #9
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 766
    Par défaut
    Un petit up :

    Nom : IHM.JPG
Affichages : 353
Taille : 58,7 Ko

    L'idée de reconnaître les lignes en fonction des indentations semble fiable ... pour mes besoins
    J'ai codé un parser en pur C (vanilla C comme certains disent)

    J'ai mis du temps parce que le plus gros problème ce sont les allocations mémoire que je voulais avoir un nombre minimal au possible

    1) Allocation mémoire 1/ 2
    On va extraire du fichier un grand nombre de chaînes de caractères (type, nom, clef ,valeur).
    Et à chaque fois c'est un new/ malloc.
    Comme je n'ai pas besoin d'un parser optimisé, j'ai préféré chargé tout le fichier en mémoire et ensuite avec un couple (pointeur, longueur) pointer toutes ces chaînes.
    Après avec du code 32 bits, un pointeur ou un décalage/ index, c'est la même chose (un entier de 32 bits)

    2) Allocation mémoire 2/ 2
    Après avoir extrait toutes ces chaînes, il faut les stocker.
    À moins de faire un parser en plusieurs passes (pour récupérer le nombre de fils et le nombre de propriétés), il faut obligatoirement utiliser des tableaux dynamiques.

    Et c'est pourquoi j'ai opté pour du C: parce qu'on a le realloc.
    En C++, il faut prendre un container (std::vector par exemple), éventuellement réserver une taille "beaucoup au pif" et s'en remettre au push back (et espérer qu'il ne fasse pas trop de réallocations)
    En C, on aura toujours cette taille "beaucoup au pif". Mais on peut décider si on veut faire grandir son tableau morceaux par morceaux (de manière régulière) soit avec un facteur d'agrandissement (de manière plus rapide)

    Après on peut utiliser une liste chaînée. Mais à chaque maillon, on a une allocation.

    3) Allocation mémoire 2 bis/ 2
    Avec un tableau dynamique, on ne peut pas prendre l'adresse d'une case (pour pointer sur un objet). Parce qu'il peut être réalloué.

    Ou alors faire un tableau de pointeurs. Mais à chaque fois on a une allocation (comme avec la liste chaînée).

    Donc, j'ai codé le truc classique: tout avec des indices de tableaux.

    4) La gestion des erreurs du parser
    Comme on va tester un type de ligne, puis, en cas d'échec, tester éventuellement un autre et ainsi de suite, on ne peut pas vraiment savoir si une ligne est mal formée ou si ce n'est pas le bon type de ligne.
    À moins, qu'on arrive à reconnaître les premiers éléments d'une ligne et décider dans ce cas si la ligne est mal-formée ou non.

    Donc mon parser gère assez mal les erreurs de fichier mal formé
    Dans un autre sens, je n'ai pas besoin d'un parser ultra performant et tous les fichiers que je vais processer sont bien formés.
    Mais en cas d'erreurs, c'est un peu pénible pour trouver le problème.

    5) Je voulais afficher les propriétés d'un objet comme ces fils

    Et donc le modèle "un tableau d'objets, et chaque objet contient un tableau de propriétés" n'est plus suffisant.

    Il faut un tableau qui regroupe tout et qu'il ne fasse pas de distinctions objets/ propriétés (*)
    * La distinction est un peu implicite: une propriété est obligatoirement une feuille, mais un objet vide sans fils est aussi une feuille.

    Donc j'ai changé mon modèle: j'ai introduit la notion d'élément qui peut être soit un objet (objet) soit un objet (inherited) soit une propriété.

    Et donc, j'ai une petite optimisation: j'ai un gros tableau d'éléments et j'ai supprimé tous ces [petits] tableaux au niveau des objets.

    Mais avec un gros tableau c'est un peu pénible: il faut parcourir tous les fils éléments pour extraire soit tous les fils soit toutes les propriétés.
    Pour aider un peu, pour chaque élément j'ai mis 2 compteurs : un nombre de fils et un nombre de propriétés.

  10. #10
    Membre Expert
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Billets dans le blog
    1
    Par défaut
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

Discussions similaires

  1. [JAXP] com.sun.xml.parser.ValidatingParser
    Par yolepro dans le forum Format d'échange (XML, JSON...)
    Réponses: 7
    Dernier message: 05/11/2008, 15h36
  2. parser un fichier dfm
    Par vieri31 dans le forum C++Builder
    Réponses: 4
    Dernier message: 26/04/2008, 00h23
  3. Parser XML
    Par miloux32 dans le forum XML/XSL et SOAP
    Réponses: 4
    Dernier message: 18/07/2003, 03h17
  4. Comment coder guillemets et cotes ?
    Par Vow dans le forum XML/XSL et SOAP
    Réponses: 4
    Dernier message: 14/05/2003, 12h11
  5. [langage] Continuer a parser une ligne
    Par D[r]eadLock dans le forum Langage
    Réponses: 5
    Dernier message: 30/09/2002, 18h49

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo