Pourquoi le compilateur C++ donne-t-il des erreurs après les lignes plutôt que sur elles?

cette question m'est venue à l'esprit aujourd'hui au travail alors que j'avais encore une affaire de ménage avec mon compilateur. Malgré mon buff pinky (en raison de toute la pression de point-virgule que je fais au travail), j'ai réussi à en manquer un avant une déclaration if . De toute évidence, il en est résulté une erreur de compilation:

erreur C2143: syntaxe error: missing '; 'before' if '

alors je me suis demandé pourquoi tu ne peux pas me dire la réplique il manque le point-virgule au lieu de la ligne après ."et j'ai commencé à expérimenter d'autres erreurs de syntaxe similaires:

erreur C2065: 'myundéclaré': identificateur non déclaré

erreur C2143: syntaxe error: missing ') 'before' if '

etc...

maintenant, toutes ces erreurs me conduiraient, de la même façon ,à la ligne après le problème et se plaindre de quelque chose avant la déclaration if .

considérer ce qui suit:

SomeFunction(x) //Notice, there is no ';' here

if(bSomeCondition)
{
    ...
}

j'obtiens deux erreurs de compilation:

(ligne 265) erreur C2065: 'x': identificateur non déclaré

(Ligne 266) error C2143: erreur de syntaxe : manquant ';' avant 'si'

cependant, la première erreur me dit correctement la ligne nombre, malgré le point-virgule manquant. Cela me laisse penser que le compilateur ne se laisse pas prendre par l'analyse et qu'il est capable de dépasser le problème du point-virgule. Alors, pourquoi le compilateur insiste-t-il pour que les erreurs grammaticales soient rapportées de cette façon? Les autres erreurs (non grammaticales) sont rapportées sur les lignes qu'elles trouvent. Est-ce que cela a à voir avec le compilateur qui fait plusieurs passes? Fondamentalement, j'espère que quelqu'un avec une connaissance pratique du compilateur C++ pourrait expliquer spécifiquement ce que le compilateur fait que nécessite la déclaration des erreurs dans cet "avant".

9
demandé sur Chad La Guardia 2011-08-16 01:43:45

9 réponses

la réponse courte à la question plus générale de" pourquoi les messages d'erreur c/c++ sont nuls "est" parfois C++ est vraiment difficile à analyser " (il n'a pas en fait de grammaire libre de contexte). Cependant, ce n'est pas vraiment une raison valable - on peut encore fabriquer des outils qui enregistrent de meilleures informations de diagnostic que la plupart des compilateurs C++.

la réponse la plus pratique est "les auteurs de compilateurs ont hérité de codebases héritées qui n'ont pas évalué les messages d'erreur", combiné avec une dose légère de "les auteurs de compilateurs sont paresseux", surmonté de"rapports de Diagnostic n'est pas un problème passionnant". La plupart des rédacteurs de compilateurs ajouteraient une nouvelle fonctionnalité de langage ou une amélioration de la performance codegen de 3%, plutôt que de faire un remaniement significatif sur la base de code pour permettre un rapport d'erreur décent. La question spécifique "pourquoi les erreurs ne sont-elles pas correctement localisées sur la ligne qui les a 'causées'" en est un exemple. Il n'y a pas vraiment une raison technique les compilateurs ne peuvent généralement pas comprendre qu'un ; est manquant , et puis vous parler de la portée source du dernier ; sans énoncé-même en présence de C++'S invariance générale des espaces. C'est juste que le stockage de cette information a (en grande partie) été historiquement ignoré.

cela dit, les nouveaux compilateurs qui ne sont pas gênés par des décennies de vieux code font beaucoup mieux. Jetez un oeil au clang compiler , qui se targue sur les messages d'erreur sensible. La page sur les diagnostics montre à quel point ils sont meilleurs que GCC. Un exemple pour ce cas étant:

  $ gcc-4.2 t.c
  t.c: In function 'foo':
  t.c:5: error: expected ';' before '}' token
  $ clang t.c
  t.c:4:8: error: expected ';' after expression
    bar()
         ^
         ;

ou, de manière plus impressionnante:

  $ cat t.cc
  template<class T>
  class a {}
  class temp {};
  a<temp> b;
  struct b {
  }
  $ gcc-4.2 t.cc
  t.cc:3: error: multiple types in one declaration
  t.cc:4: error: non-template type 'a' used as a template
  t.cc:4: error: invalid type in declaration before ';' token
  t.cc:6: error: expected unqualified-id at end of input
  $ clang t.cc
  t.cc:2:11: error: expected ';' after class
  class a {}
            ^
            ;
  t.cc:6:2: error: expected ';' after struct
  }
   ^
   ;

regardez, Il nous dit même ce qu'il faut taper pour résoudre le problème! < / clang_salespitch>

21
répondu Adam Wright 2011-08-15 22:21:11

, Parce qu'en C++, espace blanc n'a pas d'importance, dans l'ensemble. C'est donc un code valide:

SomeFunction(x)

;if(bSomeCondition)
{
    ...
}

donc le message du compilateur indique simplement qu'un point-virgule n'est pas apparu quelque part avant le if .

12
répondu Oliver Charlesworth 2011-08-15 21:46:48

dans ce code:

SomeFunction(x)
if (y) {
}

comme vous l'avez dit, l'erreur serait déclarée à la ligne 2 comme missing ';' before 'if' .

il n'y a pas de problème avec la ligne 1. Il est parfaitement valide sans un point-virgule, et plusieurs expressions sont possibles en plus d'un point-virgule (comme un point, ou un opérateur mathématique, ou une tâche, ou un pointeur, etc.).

ainsi, signaler l'erreur sur la ligne précédente peut ne pas toujours avoir de sens, prenez cet exemple:

SomeFunction(x)
+= 10
- 5
// blank line
// blank line
if (y) {
}

quelle ligne a l'erreur? La ligne avec le - 5 ? Ou l'une des lignes de commentaire? Pour le compilateur, l'erreur est en fait un "si", car c'est le premier endroit que quelque chose peut être détecté comme étant mauvais. Pour signaler une autre ligne, le compilateur aurait du rapport de la dernière correctement analysé jeton comme l'erreur, plutôt que le premier endroit où l'erreur est détectée. Cela sonne un peu à l'envers, et dire que //blank line1 manque un le point-virgule est encore plus déroutant, car le changer en //blank line; ne changerait pas et ne corrigerait pas l'erreur.

soit dit en passant, ce n'est pas unique à C ou C++. C'est une façon commune pour signaler des erreurs dans la plupart des analyseurs.

6
répondu SoapBox 2011-08-15 21:53:44

tout simplement, en raison de la façon dont l'analyse est faite. Quand l'analyseur attend ; , et rencontre if , l'erreur est dans le if . La façon la plus saine de le déclarer est de dire ; était attendue avant if .

4
répondu Jon Purdy 2011-08-15 21:53:15

, Le compilateur est l'espace agnostique. Il ne sait pas (ou s'en soucie) qu'il y a un retour de chariot ou des onglets ou des espaces entre vos déclarations. tout ce qui compte, c'est ce qui est après ou avant les demi-colonnes, ou après/avant les parenthèses ('{ ' ,'}') qui terminent et commencent les classes et les fonctions. C'est pourquoi:)

3
répondu djhaskin987 2011-08-15 21:46:04

parce que quand il est fait parsing cette ligne il ne sait pas que vous vouliez un point-virgule là encore. Regardons un exemple:

int mystuff

cette ligne manque-t-elle un point-virgule? Tout dépend de ce qui s'en vient. Par exemple la construction suivante est parfaitement ok:

int mystuff
   = 1;

Je ne l'écrirais jamais comme ça, mais pour le compilateur c'est ok.

3
répondu harald 2011-08-15 21:48:52

parce que le code suivant serait correct:

SomeFunction(x)

;if(bSomeCondition)
{
}

c'est parce que les espaces vides sont ignorés.

3
répondu cor3ntin 2011-08-15 21:50:00

la réponse courte: vous pouvez mettre ; dans la ligne 266, et puis ça va aller. De le compilateur considère que l'erreur est là.

vous pourriez vouloir essayer clang , bien que je ne sais pas si il donne un meilleur message d'erreur pour ce type particulier d'erreur, mais en général il donne beaucoup messages d'erreur plus clairs .

2
répondu Karoly Horvath 2011-08-15 21:48:28

c'est parce que le compilateur vérifie pour 1 Déclaration entière. Permettez-moi de donner un exemple:

int a,b,c
c=a+b;
cout<<c;

ce code génère une erreur de compilation, que"; est attendu avant c / ligne 2", cela se produit parce que le compilateur regarde d'abord les int A,b,c de la ligne 1 et le compilateur n'a aucune idée s'il y aura une autre variable ou une autre instruction et donc le compilateur passe à la deuxième ligne(parce que les espaces blancs sont autorisés), et puis il voit qu'il y a "c=A+b", qui est une instruction, et ainsi le compilateur sait que quelque chose ne va pas, puisqu'il attendait soit une variable, soit un point-virgule(;). Et donc, il nous dit qu'il s'attendait à un ; avant une déclaration.

si longue histoire courte, le compilateur ne cherche pas un point-virgule après une instruction (si c'était le cas, nous pourrions ne pas être en mesure d'utiliser des espaces blancs dans nos codes), il cherche ; juste avant l'autre instruction, parce que le compilateur n'a aucune idée de combien de temps la première instruction serait.

1
répondu Aniruddh 2013-12-02 21:04:45