PythonsyntaxError問題解析

5525 ワード

これは先日たまにあった問題で、自分のpythonに対する理解が一致していないことに気づいたので、ネットで調べてみると、PythonのBug(ただし、ドキュメントではサポートしていないと言っていた)がちょうど最近pythonのソースコードを見ていたので、ソースコードで分析しました.
1.まず、質問をします.
「python文字列で特殊文字を計算し、エスケープの役割を果たし、エスケープnが車に戻る、エスケープなど、これは問題ないはずです.では通常a=「」は文法の問題があり、右の文字列を意味しているので、文字列に右かっこが1つ足りないのは明らかですが、pythonにはrオペレータ(全称元文字列オペレータ)があります.文字列内の内容を字面の意味で解析し、特殊な処理をしないので、a=r」「出力は」で、車に戻るのではなく、なぜ」です.ああ、goto 1もう一度見てみましょう.では、今問題が来ました.rの機能によって、a=r」「ああ、大丈夫だと思います.rの場では、は意味を変えることができませんから.」しかし、今は文法の間違いをあげます.syntaxError.
2.そして、私はこう言いたい.
実は私はさっき言い間違えました.これは文法の間違いではありません.これは文法の間違いです.(Bの言い方を少し装って、文法の文法の概念があいまいなのはネット上で少し見ることができます).なぜかというとpythonのソースコードについていくと、Parsertokenizerに問題があることがわかりました.c内、pythonは文字列オブジェクトの文法解析部分を解析する.コードは次のとおりです.
/* String */
letter_quote:
    if (c == '\'' || c == '"') {  
        Py_ssize_t quote2 = tok->cur - tok->start + 1;  
        int quote = c;  
        int triple = 0;  
        int tripcount = 0;  
        for (;;) {  
            c = tok_nextc(tok);  
            if (c == '
') { if (!triple) { tok->done = E_EOLS; tok_backup(tok, c); return ERRORTOKEN; } tripcount = 0; tok->cont_line = 1; /* multiline string. */ } else if (c == EOF) { if (triple) tok->done = E_EOFS; else tok->done = E_EOLS; tok->cur = tok->inp; return ERRORTOKEN; } else if (c == quote) { tripcount++; if (tok->cur - tok->start == quote2) { c = tok_nextc(tok); if (c == quote) { triple = 1; tripcount = 0; continue; } tok_backup(tok, c); } if (!triple || tripcount == 3) break; } else if (c == '\\' ) { tripcount = 0; c = tok_nextc(tok); if (c == EOF) { tok->done = E_EOLS; tok->cur = tok->inp; return ERRORTOKEN; } } else tripcount = 0; } *p_start = tok->start; *p_end = tok->cur; return STRING; }

実は簡単です.いくつかの場所で話をしなければなりません.
  • はletter_quote:このジャンプラベル、注目して、最後に発表してください.
  • tok_nextcは入力ストリームから次の文字を取得する.
  • tok_backupは文字を入力ストリームに戻す.
  • tripleとtripcountの2つの変数は三重引用符処理に関係する、tripleタグが現在三重引用符モードにあるかどうか、1に等しい場合、現在三重引用符モードにあることを示し、tripcountは連続する引用符数を記録する.

  • Ok、残りは少しcベースでかじることができます.ここで簡単に分析すると、if(c=''''|||='''')の現在の文字は'または"文字列オブジェクトの構文解析プロセスに入るため、pythonは'と"2つの引用符文字をサポートします.forループには4つのelse ifがありますが、pythonの文字列には4種類の特別文字があることを示しています.
  • 車を返します.三重引用符以外のモードで、リターンが検出された場合、対応するエラーコードを設定して失敗を返すと、関連するエラーの定義は次のとおりです:
  • #define E_EOFS      23  /* EOF in triple-quoted string */  
    #define E_EOLS      24  /* EOL in single-quoted string */  
    

    これは単引用符モードでは、車に戻って試すことはできないようですが、pythonの経験があるので、行尾にを追加すれば、車に戻って入力することができます.次の行でやり直します.はい、覚えておいてください.#を入力します.中からも分かるように、三引用符モードでは、帰りは勝手に負けることができる.
  • EOFファイルの末尾(入力フローが停止しました).この単純な除暴は、現在のモードに基づいてエラーコードを設定し、失敗を返します.
  • quote引用符if(tok->cur-tok->start==quote 2)をスキップする.単看if(!triple|tripcount==3).三引用符モードで、また「触る」というquoteがなければ、現在の文字列の文法解析は終わり、breakが出ると、一つの文字列がkoになる(ニマ、少し簡単に言う).振り返ってif(tok->cur-tok->start==quote 2)というのが、三重引用符を判断する場所です.本文の核心内容とは関係なく、話はやめましょう.
  • '',やっとこの品物に着いた.処理も簡単で、コアはc=tok_nextc(tok)は、次の文字を入力ストリームから取り出して、他は何も気にしない.まだ文法段階なので、エスケープ文字の解析はできません.では、多くの質問に答えが見つかりました.
  • にを追加して、単行モードは1つのに入力することができて、pythonが1つのに解析した後で、直接後ろの車を入力ストリームから取り出して、同時に説明して、車に戻って必ずの後ろについて、彼の後ろの1つの文字だけを取るためです.
  • 」「なぜ失敗したのか、解析のために後にを取るべきです.それでは、次の解析の時、直面するのは、Syntax EOL in single-quoted string
  • です.
    OK,pythonのstringオブジェクトに対する文法解析はこうなった.そんなにたくさん話して、まだrオペレータを言っていません.文法の段階で、彼の処理は怠けています.コードは以下の通りです.
    case 'r':  
    case 'R':  
        c = tok_nextc(tok);  
        if (c == '"' || c == '\'')  
        {  
            goto letter_quote;  
        }  
    

    ニマ、gotoから文字列解析部分です.(?:どんな表情もしないで、仕事を他の人に振ったの?r:语法分析の段阶で、俺は何ができるんだ!!).r元のオペレータはpythonの文法上の内容に属するべきであるため、文法分析段階では、彼の処理方式は通常の文字列の処理方式である(r:賛一).だから「」に直面する時もSyntax EOL in single-quoted stringを報告しなければならない.
    3.後の話
    実はこの問題を解決するのはやはり簡単で、表示変数を追加します
    int bInRMode = 0;  
    
    case 'r':  
    case 'R':  
        c = tok_nextc(tok);  
        if (c == '"' || c == '\'')  
        {  
            bInRMode = 1; //        
            goto letter_quote;  
        }
        else if (c == '\\' ) {  
        tripcount = 0;  
        c = tok_nextc(tok);  
        if (c == EOF) {  
            tok->done = E_EOLS;  
            tok->cur = tok->inp;  
            return ERRORTOKEN;  
        }  
        if( c !='
    ' && bInRMode){ tok_backup(tok ,c); } }

    解析の際には、特殊な処理が必要となる.rモードで、は普通の文字であるべきで、文字を外す機能があるべきではないので、私はコードをつけて取った文字をまた詰めました.本来else if(c='')ではここで直接処理できるのですが、リターン特殊処理をしないと、一重引用符モードでは送リターンできないので、後接に対して、rの機能は採用しません.