La manière forte
Vous voulez un analyseur syntaxique à descente récursive .
Pour obtenir la préséance, vous devez penser de manière récursive, par exemple, en utilisant votre exemple de chaîne,
1+11*5
pour le faire manuellement, vous devriez lire le document 1
puis voir le plus et commencer une nouvelle "session" d'analyse récursive commençant par 11
... et assurez-vous d'analyser l'élément 11 * 5
dans son propre facteur, ce qui donne un arbre d'analyse syntaxique avec 1 + (11 * 5)
.
Tout cela est si pénible à expliquer, surtout si l'on ajoute l'impuissance de C. Vous voyez, après avoir analysé le 11, si le * était en fait un + à la place, vous devriez abandonner la tentative de créer un terme et analyser à la place l'expression 11
comme un facteur. Ma tête est déjà en train d'exploser. C'est possible avec la stratégie récursive décente, mais il y a un meilleur moyen...
La méthode simple (et correcte)
Si vous utilisez un outil GPL comme Bison, vous n'avez probablement pas à vous soucier des problèmes de licence puisque le code C généré par Bison n'est pas couvert par la GPL (je ne suis pas sûr que les outils GPL n'imposent pas la GPL sur le code/binaire généré ; par exemple, Apple compile du code comme Aperture avec GCC et le vend sans avoir à le mettre sous licence).
Télécharger Bison (ou quelque chose d'équivalent, ANTLR, etc.).
Il existe généralement un exemple de code sur lequel vous pouvez simplement exécuter bison et obtenir le code C souhaité qui démontre cette calculatrice à quatre fonctions :
http://www.gnu.org/software/bison/manual/html_node/Infix-Calc.html
Regardez le code généré, et vous verrez que ce n'est pas aussi facile qu'il n'y paraît. De plus, les avantages de l'utilisation d'un outil comme Bison sont les suivants : 1) vous apprenez quelque chose (surtout si vous lisez le livre de Dragon et apprenez les grammaires), 2) vous évitez NIH en essayant de réinventer la roue. Avec un véritable outil de génération d'analyseur syntaxique, vous avez une chance de passer à l'échelle plus tard, en montrant aux autres personnes que vous connaissez que les analyseurs syntaxiques sont le domaine des outils d'analyse syntaxique.
Mise à jour :
Les personnes présentes ici ont donné de nombreux conseils judicieux. Ma seule mise en garde contre le fait de ne pas utiliser les outils d'analyse syntaxique, de se contenter de l'algorithme Shunting Yard ou d'un analyseur syntaxique récursif décent est que les petits langages jouets 1 pourraient un jour se transformer en de véritables grands langages avec des fonctions (sin, cos, log) et des variables, des conditions et des boucles for.
Flex/Bison peut très bien être surdimensionné pour un petit interprète simple, mais un analyseur syntaxique + évaluateur unique peut causer des problèmes à long terme lorsque des modifications doivent être apportées ou que des fonctionnalités doivent être ajoutées. Votre situation variera et vous devrez faire preuve de discernement. punir d'autres personnes pour vos péchés [2] et construire un outil moins qu'adéquat.
Mon outil préféré pour l'analyse syntaxique
Le meilleur outil au monde pour ce travail est le Parsec (pour les analyseurs décents récursifs) qui est fournie avec le langage de programmation Haskell. Elle ressemble beaucoup à BNF ou comme un outil spécialisé ou un langage spécifique à un domaine pour l'analyse syntaxique (exemple de code [3]), mais il s'agit en fait d'une bibliothèque ordinaire en Haskell, ce qui signifie qu'elle se compile au cours de la même étape de construction que le reste de votre code Haskell, que vous pouvez écrire du code Haskell arbitraire et l'appeler dans votre analyse syntaxique, et que vous pouvez mélanger d'autres bibliothèques. tous dans le même code . (Intégrer un tel langage d'analyse syntaxique dans un langage autre que Haskell donne lieu à de nombreuses lacunes syntaxiques, soit dit en passant. J'ai fait cela en C# et cela fonctionne assez bien mais ce n'est pas aussi joli et succinct).
Notes :
1 Richard Stallman dit, dans Pourquoi vous ne devriez pas utiliser Tcl
La principale leçon d'Emacs est que un langage d'extension ne doit pas être un simple "langage d'extension". Il devrait être un véritable langage de programmation, conçu pour écrire et maintenir programmes substantiels. Parce que les gens voudront le faire !
[2] Oui, je suis marqué à jamais par l'utilisation de ce "langage".
Notez également que lorsque j'ai soumis cette entrée, l'aperçu était correct, mais L'analyseur de SO, moins qu'adéquat, a mangé ma balise d'ancre fermée dans le premier paragraphe. ce qui prouve que les analyseurs syntaxiques ne sont pas à prendre à la légère car si vous utilisez des regex et des bidouillages ponctuels vous allez probablement vous tromper sur quelque chose de subtil et de petit .
[3] Extrait d'un analyseur Haskell utilisant Parsec : une calculatrice à quatre fonctions étendue avec des exposants, des parenthèses, des espaces pour la multiplication et des constantes (comme pi et e).
aexpr = expr `chainl1` toOp
expr = optChainl1 term addop (toScalar 0)
term = factor `chainl1` mulop
factor = sexpr `chainr1` powop
sexpr = parens aexpr
<|> scalar
<|> ident
powop = sym "^" >>= return . (B Pow)
<|> sym "^-" >>= return . (\x y -> B Pow x (B Sub (toScalar 0) y))
toOp = sym "->" >>= return . (B To)
mulop = sym "*" >>= return . (B Mul)
<|> sym "/" >>= return . (B Div)
<|> sym "%" >>= return . (B Mod)
<|> return . (B Mul)
addop = sym "+" >>= return . (B Add)
<|> sym "-" >>= return . (B Sub)
scalar = number >>= return . toScalar
ident = literal >>= return . Lit
parens p = do
lparen
result <- p
rparen
return result
0 votes
J'ai écrit un analyseur d'expression en C# sur mon blog. Il fait infix vers postfix sans la pile dans l'algorithme de la gare de triage. Il utilise seulement un tableau.
0 votes
Si j'ai bien compris, vous n'avez besoin d'analyser que des expressions arithmétiques. Utilisez Notation polonaise inversée