Question

En plus de faire du vrai travail, j'ai des démangeaisons. Mon souhait est d'écrire un moteur de vue qui imite étroitement un système de modèles d'une autre langue (Template Toolkit / Perl). C’est un de ceux-là si j’avais le temps / le fais pour apprendre quelque chose d’un nouveau genre de projets.

J'ai passé du temps à regarder CoCo / R et ANTLR, et honnêtement, ça me fait mal au cerveau, mais une partie de CoCo / R s'enfonce. Malheureusement, la plupart des exemples concernent la création d'un compilateur qui lit le code source , mais aucun ne semble couvrir la création d’un processeur pour les modèles.

Oui, c’est la même chose, mais je ne peux pas vous expliquer comment définir le langage des modèles où la source est principalement le code HTML, plutôt que le code réel analysé et exécuté.

Existe-t-il de bonnes ressources pour les débutants sur ce genre de choses? J'ai pris un ganer chez Spark, qui ne semblait pas avoir la grammaire dans le dépôt.

C’est peut-être excessif, et on pourrait simplement tester-remplacer la syntaxe du modèle avec c # dans le fichier et le compiler. http://msdn.microsoft.com/en-us/magazine/ cc136756.aspx # S2

Si vous étiez à ma place et que vous n'étiez pas un expert en création de langage, par où commenceriez-vous?

Était-ce utile?

La solution

La grammaire Spark est implémentée avec un langage spécifique à un domaine courant.

Il est déclaré en quelques couches. Les règles qui reconnaissent la syntaxe html sont déclarées dans MarkupGrammar.cs - ils sont basés sur des règles de grammaire copiées directement à partir de la spécification xml.

Les règles de balisage font référence à un sous-ensemble limité de règles de syntaxe csharp déclarées dans CodeGrammar.cs - il s’agit d’un sous-ensemble, car Spark doit seulement reconnaître suffisamment de csharp pour ajuster les guillemets simples autour des chaînes en guillemets, faire correspondre les accolades de curley, etc.

Les règles individuelles elles-mêmes sont de type ParseAction < !> lt; TValue > délégué qui accepte un Position et renvoyez un ParseResult . ParseResult est une classe simple qui contient l’élément de données TValue analysé par l’action et une nouvelle instance de Position qui a été avancée au-delà du contenu ayant généré la TValue.

Cela n’est pas très utile en soi jusqu’à ce que vous introduisiez un petit nombre d'opérateurs , comme décrit dans Analyse de la grammaire d'expression , qui peut combiner des actions d'analyse simples pour construire des expressions très détaillées et robustes sur la forme de différentes constructions de syntaxe.

La technique consistant à utiliser un délégué comme action d'analyse provient d'un billet de blog de Luke H Combinateurs d'analyseurs monadiques utilisant C # 3.0 . J'ai également écrit un article sur Création d'un domaine spécifique Langue d'analyse .

Il est également tout à fait possible, si vous le souhaitez, de référencer l'assembly Spark.dll et d'hériter d'une classe de CharGrammar de base afin de créer une grammaire entièrement nouvelle pour une syntaxe particulière. C'est probablement le moyen le plus rapide de commencer à expérimenter cette technique, et vous en trouverez un exemple dans CharGrammarTester.cs .

Autres conseils

Étape 1. Utilisez des expressions régulières (substitution d’expression régulière) pour fractionner la chaîne de votre modèle d’entrée en une liste de jetons, par exemple, fractionner

.
hel<b>lo[if foo]bar is [bar].[else]baz[end]world</b>!

à

write('hel<b>lo')
if('foo')
write('bar is')
substitute('bar')
write('.')
else()
write('baz')
end()
write('world</b>!')

Étape 2. Convertissez votre liste de jetons en un arbre de syntaxe:

* Sequence
** Write
*** ('hel<b>lo')
** If
*** ('foo')
*** Sequence
**** Write
***** ('bar is')
**** Substitute
***** ('bar')
**** Write
***** ('.')
*** Write
**** ('baz')
** Write
*** ('world</b>!')

class Instruction {
}
class Write : Instruction {
  string text;
}
class Substitute : Instruction {
  string varname;
}
class Sequence : Instruction {
  Instruction[] items;
}
class If : Instruction {
  string condition;
  Instruction then;
  Instruction else;
}

Étape 3. Écrivez une fonction récursive (appelée interprète), qui peut parcourir votre arbre et y exécuter les instructions.

Autre approche alternative (au lieu des étapes 1 à 3) si votre langue prend en charge eval () (telle que Perl, Python, Ruby): utilisez une substitution d'expressions rationnelles pour convertir le modèle en chaîne éval () dans le langage hôte et exécutez eval () pour instancier le modèle.

Il y a tellement de choses à faire. Mais cela fonctionne pour une simple déclaration GET plus un test. C'est un début.

http://github.com/claco/tt.net/

En fin de compte, j’avais déjà trop de temps dans ANTLR pour essayer la méthode de loudejs. Je voulais passer un peu plus de temps sur l'ensemble du processus plutôt que sur l'analyseur / lexer. Peut-être que dans la version 2, je pourrai essayer Spark lorsque mon cerveau comprendra un peu plus les choses.

L'analyseur Vici (anciennement LazyParser.NET) est une source ouverte. tokenizer / template parser / analyseur d'expression qui peut vous aider à démarrer.

Si ce n'est pas ce que vous recherchez, vous pouvez trouver des idées en consultant le code source.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top