Megosztás a következőn keresztül:


6 Lexikális szerkezet

6.1 Programok

A C#-programok egy vagy több forrásfájlból állnak, más néven fordítási egységekből (14.2.§). Bár egy fordítási egység egy-az-egyhez levelezéssel rendelkezhet egy fájlrendszerbeli fájllal, az ilyen levelezésre nincs szükség.

Elméletileg a program három lépésből áll:

  1. Átalakítás, amely egy adott karakterrepertoárból és kódolási sémából konvertál egy fájlt Unicode-karakterek sorozatává.
  2. Lexikális elemzés, amely unicode bemeneti karakterek adatfolyamát tokenek adatfolyamává fordítja le.
  3. A szintaktikai elemzés olyan folyamat, amely a tokenek adatfolyamát végrehajtható kódra fordítja.

A megfelelő implementációknak el kell fogadniuk az UTF-8 kódolási formával kódolt Unicode-fordítási egységeket (a Unicode szabványnak megfelelően), és Unicode-karakterek sorozatává kell alakítaniuk őket. A implementációk további karakterkódolási sémákat (például UTF-16, UTF-32 vagy nem Unicode-karakterleképezéseket) is elfogadhatnak és átalakíthatnak.

Megjegyzés: A Unicode NULL karakter (U+0000) kezelése implementációfüggő. Erősen ajánlott, hogy a fejlesztők ne használják ezt a karaktert a forráskódjukban a hordozhatóság és az olvashatóság érdekében. Ha a karaktert karakter- vagy sztringkonstansban kell megadni, a feloldósorozatok \0 vagy \u0000 használhatók helyette. végjegyzet

Megjegyzés: A specifikáció hatókörén kívül esik annak meghatározása, hogy a Unicode-tól eltérő karakterábrázolást használó fájlok hogyan alakíthatók át Unicode-karakterek sorozatává. Az ilyen átalakítás során azonban azt javasoljuk, hogy a másik karakterkészlet szokásos sorelválasztó karakterét (vagy sorozatát) fordítsuk le a kétkarakterű sorozatra, amely a Unicode kocsivissza karakterből (U+000D) és a Unicode sorelváltási karakterből (U+000A) áll. Ennek az átalakításnak többnyire nincsenek látható hatásai; ez azonban hatással lesz a szó szerinti sztring literális tokenek értelmezésére (§6.4.5.6). Ennek a javaslatnak az a célja, hogy lehetővé tegye a szó szerinti karakterlánc literálnak, hogy ugyanazt a karaktersorozatot hozza létre, amikor a fordítási egység átkerül olyan rendszerek között, amelyek különböző, nem Unicode karakterkészleteket támogatnak, különösen eltérő karaktersorozatokat használnak a sorelválasztáshoz. végjegyzet

6.2 Nyelvtanok

6.2.1 Általános

Ez a specifikáció a C# programozási nyelv szintaxisát mutatja be két nyelvtan használatával. A lexikális nyelvhelyesség (6.2.3. §) meghatározza, hogy a Unicode-karakterek hogyan lesznek egyesítve a sorkijelölők, a szabad terület, a megjegyzések, a jogkivonatok és az előfeldolgozási irányelvek formájában. A szintaktikai nyelvtan (§6.2.4) határozza meg, hogy a lexikális nyelvtanból származó jogkivonatok hogyan lesznek kombinálva C#-programok formájában.

Minden terminálkaraktert az U+0020 és U+007F tartomány megfelelő Unicode-karaktereként kell értelmezni, szemben a többi Unicode-karaktertartomány hasonló megjelenésű karakterével.

6.2.2 Nyelvtani jelölés

A lexikális és szintaktikai nyelvtanokat az ANTLR nyelvhelyességi eszköz Kiterjesztett Backus-Naur formájában mutatjuk be.

Bár az ANTLR jelölést használja, ez a specifikáció nem tartalmaz teljes ANTLR-kész "referencia-nyelvtant" a C#-hoz; a lexer és elemző írása kézzel vagy egy olyan eszköz használatával, mint az ANTLR, nem tartozik a nyelvi specifikáció hatókörébe. Ezzel a minősítéssel ez a specifikáció megpróbálja minimalizálni a megadott nyelvtan és az ANTLR-ben történő lexer és elemző létrehozásához szükséges közötti rést.

Az ANTLR különbséget tesz lexikális és szintaktikai (az ANTLR által elemzőnek nevezett) nyelvtanok között azáltal, hogy a lexikális szabályokat nagybetűvel, az elemzési szabályokat pedig kisbetűvel kezdi a jelölésében.

Megjegyzés: A C#-lexikális nyelvtan (6.2.3.§) és a szintaktikai nyelvhelyesség (6.2.4. §) nem egyezik meg pontosan az ANTLR lexikális és elemző nyelvtanokra való felosztásával. Ez a kis eltérés azt jelenti, hogy néhány ANTLR-elemző szabályt használnak a C#-lexikális nyelvhelyesség megadásakor. végjegyzet

6.2.3 Lexikális nyelvtan

A C# lexikális nyelvtana a 6.3, 6.4 és 6.5. A lexikális nyelvhelyesség terminálszimbóluma a Unicode karakterkészlet karakterei, a lexikális nyelvhelyesség pedig azt határozza meg, hogy a karakterek hogyan lesznek egyesítve jogkivonatokké (6.4.§), szóközökké (6.3.4.§), megjegyzésekhez (6.3.3.3. §) és előfeldolgozási irányelvekhez (6.5. §).

A szintaktikai nyelvtan számos terminálszimbóluma nincs explicit módon tokenekként definiálva a lexikális nyelvtanban. Az ANTLR viselkedését előnyösen használják ki, mivel a grammatikában lévő szó szerinti karakterláncok implicit lexikális tokenekként kivonásra kerülnek; ez lehetővé teszi, hogy a kulcsszavak, operátorok stb. a grammatikában a tokennév helyett a szó szerinti ábrázolásukkal legyenek ábrázolva.

A C#-programokban minden fordítási egységnek meg kell felelnie a lexikális nyelvhelyesség bemeneti előállításának (6.3.1. §).

6.2.4 Szintaktikai nyelvtan

A C# szintaktikai nyelvtanát az alklámot követő záradékok, alklámok és mellékletek mutatják be. A szintaktikai nyelvtan terminálszimbólumai a lexikális nyelvtan által explicit módon meghatározott tokenek és implicit módon a nyelvtanban szereplő literálok (§6.2.3). A szintaktikai nyelvtan határozza meg, hogy a tokenek hogyan kombinálódnak C# programokká.

A C#-programok minden fordítási egységének meg kell felelnie a szintaktikai nyelvhelyesség compilation_unit szabályának (14.2. §).

6.2.5 Nyelvtani kétértelműségek

A következőhöz tartozó produkciók:

(a "egyértelmű produkciók") kétértelműségeket eredményezhetnek a kifejezések nyelvtanában.

Ezek az előállítások olyan szituációkban fordulnak elő, ahol egy kifejezésben érték fordulhat elő, és egy vagy több alternatívát kínálnak, amelyek a nyelvtani szerkezettel "identifier type_argument_list?" végződnek. Ez az opcionális type_argument_list , amely a lehetséges kétértelműséget eredményezi.

Példa: Az utasítás:

F(G<A, B>(7));

F két argumentummal, G < A-val és B > (7)-vel történő hívásként értelmezhető. Másik lehetőségként F egy argumentummal hívható meg, amely egy általános metódus G meghívása két típusargumentummal és egy normál argumentummal.

záró példa

Ha egy tokenek sorozata kontextusban elemezhető, mint az egyik egyértelműsített produkció, beleértve egy választható type_argument_list (§8.4.2), akkor meg kell vizsgálni a záró > tokent közvetlenül követő tokent, és ha igen:

  • az egyik ; ( ) ] } : ; , . ? == != | ^ && || & [vagy
  • az egyik relációs operátor < <= >= is as; vagy
  • egy környezeti lekérdezési kulcsszó jelenik meg egy lekérdezési kifejezésben.

akkor a type_argument_list a pontosított produkció részeként meg kell őrizni, és a tokenek sorrendjének bármely más lehetséges értelmezését el kell vetni. Ellenkező esetben a type_argument_list tokenek nem tekinthetők az egyértelműsített kifejezés részének, még akkor sem, ha a tokeneknek nincs más lehetséges elemzése.

Megjegyzés: Ezek a egyértelműsítési szabályok nem alkalmazhatók más produkciók elemzésekor, még akkor sem, ha hasonló végződésű "identifier type_argument_list?"-ként végződnek; az ilyen produkciókat a szokásos módon kell elemezni. Példák: namespace_or_type_name (§7.8); named_entity (§12.8.23); null_conditional_projection_initializer (§12.8.8); és qualified_alias_member (§14.8.1). végjegyzet

Példa: Az utasítás:

F(G<A, B>(7));

a szabály szerint egy argumentummal rendelkező hívásként F lesz értelmezve, amely egy általános metódus G hívása két típusargumentummal és egy normál argumentummal. A kijelentések

F(G<A, B>7);
F(G<A, B>>7);

A F hívásként lesz értelmezve két argumentummal. A kijelentés

x = F<A> + y;

A kifejezés kisebb, nagyobb és unáris plusz operátorként lesz értelmezve, mintha így lett volna írva: x = (F < A) > (+y), nem pedig mint egy simple_name egy type_argument_list, amelyet egy bináris plusz operátor követ. A nyilatkozatban

x = y is C<T> && z;

a tokent C<T> a namespace_or_type_name a type_argument_list néven értelmezi, mivel a type_argument_list után megjelenik az egyértelműsítő token &&.

A kifejezés (A < B, C > D) egy kételemű tömb, ahol mindkét elem egy-egy összehasonlítás.

A kifejezés (A<B,C> D, E) két elemet tartalmazó rekord, az első egy deklarációs kifejezés.

A meghívásnak M(A < B, C > D, E) három argumentuma van.

A meghívásnak M(out A<B,C> D, E) két argumentuma van, amelyek közül az első egy out deklaráció.

A kifejezés e is A<B> C deklarációs mintát használ.

Az esetcímke case A<B> C: deklarációs mintát használ.

záró példa

Relational_expression felismerésekor (§12.12.1), ha a "relational_expressionistípus" és a "relational_expressionisminta" alternatívák is alkalmazhatók, és a típus elérhető típusra oldható fel, akkor a "relational_expressionistípus" alternatívát kell választani.

6.3 Lexikális elemzés

6.3.1 Általános

Az egyszerűség kedvéért a lexikai nyelvtan a következő elnevezett lexer tokeneket határozza meg és használ hivatkozásként:

DEFAULT  : 'default' ;
NULL     : 'null' ;
TRUE     : 'true' ;
FALSE    : 'false' ;
ASTERISK : '*' ;
SLASH    : '/' ;

Bár ezek lexer szabályok, ezek a nevek nagybetűs betűkkel vannak beírva, hogy megkülönböztessék őket a szokásos lexer szabálynevektől.

Megjegyzés: Ezek a kényelmi szabályok kivételt jelentenek a literal stringek által definiált tokenek explicit tokenneveinek megadásának szokásos gyakorlattól eltérően. végjegyzet

A bemeneti termelés határozza meg a C#-fordítási egység lexikális szerkezetét.

input
    : input_section?
    ;

input_section
    : input_section_part+
    ;

input_section_part
    : input_element* New_Line
    | PP_Directive
    ;

input_element
    : Whitespace
    | Comment
    | token
    ;

Megjegyzés: A fenti nyelvtant az ANTLR elemzési szabályai írják le, a C#-fordítási egység lexikális szerkezetét határozza meg, nem lexikális tokeneket. végjegyzet

A C#-fordítási egység lexikális szerkezetét öt alapvető elem alkotja: Sorkijelölők (6.3.2.§), szóköz (6.3.4.§), megjegyzések (6.3.3.§), jogkivonatok (6.4. §) és előfeldolgozási irányelvek (6.5. §). Ezen alapvető elemek közül csak a tokenek jelentősek egy C#-program szintaktikai nyelvtanában (§6.2.4).

A C#-fordítási egység lexikális feldolgozása abból áll, hogy a fájlt tokenek sorozatává csökkenti, amely a szintaktikai elemzés bemenetévé válik. A sorvégjelek, a szóközök és a megjegyzések a tokenek elválasztására szolgálnak, az előfeldolgozási utasítások pedig a fordítási egység bizonyos részeinek kihagyását okozhatják, de ettől eltekintve ezek a lexikális elemek nem befolyásolják egy C# program szintaktikai szerkezetét.

Ha több lexikális nyelvtani produkció egy fordítási egységben szereplő karaktersorozatnak felel meg, a lexikális feldolgozás mindig a lehető leghosszabb lexikális elemet alkotja.

Példa: A karakterlánc // egy egysoros megjegyzés kezdeteként van feldolgozva, mert ez a lexikális elem hosszabb egyetlen / tokennél. záró példa

Egyes tokeneket lexikális szabályok határoznak meg; főszabály és egy vagy több alszabály. Az utóbbiak a nyelvtanban fragment azért vannak így megjelölve, hogy a szabály egy másik elem egy részét határozza meg. A töredékszabályok nem tekinthetők a lexikális szabályok felülről lefelé rendezett sorrendjének.

Megjegyzés: Az ANTLR fragment egy olyan kulcsszó, amely az itt definiált viselkedést hozza létre. végjegyzet

6.3.2 Sorelválasztók

A sorvégi jelek a C#-fordítási egység karaktereit sorokra osztják.

New_Line
    : New_Line_Character
    | '\u000D\u000A'    // carriage return, line feed
    ;

A forráskódszerkesztő eszközökkel való kompatibilitás érdekében, amelyek fájlvégpont-jelölőket adnak hozzá, és lehetővé teszik, hogy a fordítási egység megfelelően megszakított sorok sorozataként legyen megtekinthető, a következő átalakítások lesznek alkalmazva egy C#-program összes fordítási egységére:

  • Ha a fordítási egység utolsó karaktere egy Control-Z karakter (U+001A), akkor a rendszer törli a karaktert.
  • Egy kocsivissza karakter (U+000D) hozzáadódik a fordítási egység végéhez, ha a fordítási egység nem üres, és a fordítási egység utolsó karaktere nem kocsivissza (U+000D), soremelés (U+000A), következő sor karakter (U+0085), vonalelválasztó (U+2028) vagy bekezdéselválasztó (U+2029).

Megjegyzés: A további kocsivisszatérítés karakter lehetővé teszi, hogy a program egy PP_Directive-vel végződjön (§6.5), amely nem tartalmaz New_Line-t. végjegyzet

6.3.3 Megjegyzések

A megjegyzések két formája támogatott: a tagolt megjegyzések és az egysoros megjegyzések.

A tagolt megjegyzések a karakterekkel /* kezdődnek, és a karakterekkel */végződnek. A tagolt megjegyzések egy sor, egy sor vagy több sor egy részét foglalhatják el.

Példa: A példa

/* Hello, world program
   This program writes "hello, world" to the console
*/
class Hello
{
    static void Main()
    {
        System.Console.WriteLine("hello, world");
    }
}

tagolt megjegyzést tartalmaz.

záró példa

Az egysoros megjegyzés a karakterekkel // kezdődik, és a sor végéig terjed.

Példa: A példa

// Hello, world program
// This program writes "hello, world" to the console
//
class Hello // any name will do for this class
{
    static void Main() // this method must be named "Main"
    {
        System.Console.WriteLine("hello, world");
    }
}

több egysoros megjegyzést jelenít meg.

záró példa

Comment
    : Single_Line_Comment
    | Delimited_Comment
    ;

fragment Single_Line_Comment
    : '//' Input_Character*
    ;

fragment Input_Character
    // anything but New_Line_Character
    : ~('\u000D' | '\u000A'   | '\u0085' | '\u2028' | '\u2029')
    ;

fragment New_Line_Character
    : '\u000D'  // carriage return
    | '\u000A'  // line feed
    | '\u0085'  // next line
    | '\u2028'  // line separator
    | '\u2029'  // paragraph separator
    ;

fragment Delimited_Comment
    : '/*' Delimited_Comment_Section* ASTERISK+ '/'
    ;

fragment Delimited_Comment_Section
    : SLASH
    | ASTERISK* Not_Slash_Or_Asterisk
    ;

fragment Not_Slash_Or_Asterisk
    : ~('/' | '*')    // Any except SLASH or ASTERISK
    ;

A megjegyzések nem ágyaznak be. A karaktersorozatok /* , és */ nincs különleges jelentésük egy egysoros megjegyzésen belül, és a karaktersorozatok // , és /* nincs különleges jelentésük egy elhatárolt megjegyzésen belül.

A megjegyzések nem dolgozhatók fel karakter- és sztringkonstansokon belül.

Megjegyzés: Ezeket a szabályokat gondosan kell értelmezni. Az alábbi példában, például az elválasztott megjegyzés, amely mielőtt A kezdődik, B és C() között végződik. Ennek az az oka, hogy

// B */ C();

valójában nem egysoros megjegyzés, mivel // nincs különleges jelentése egy elhatárolt megjegyzésen belül, és így */ a szokásos különleges jelentése is van ebben a sorban.

Hasonlóképpen, a tagolt megjegyzés, amely D előtt kezdődik, a E előtt végződik. Ennek az az oka, hogy "D */ " valójában nem karakterlánc literál, mivel a kezdeti dupla idézőjel egy határolt megjegyzésben jelenik meg.

Az egy soros megjegyzésekben a /* és */ elemeknek nincs különleges jelentése, ezért egy forráskód blokk sorait úgy lehet megjegyzésekké alakítani, hogy mindegyik sor elejére // kerül. Általában nem érdemes ezeket a sorokat és /* utánuk elhelyezni*/, mivel ez nem foglalja össze megfelelően az elhatárolt megjegyzéseket a blokkban, és általában teljesen megváltoztathatja az ilyen elhatárolt megjegyzések szerkezetét.

Példakód:

static void Main()
{
    /* A
    // B */ C();
    Console.WriteLine(/* "D */ "E");
}

végjegyzet

Single_Line_Commentek és Delimited_Commentek meghatározott formátumai használhatók dokumentációs megjegyzésekként, a §D-ben leírtak szerint.

6.3.4 Szabad terület

Az üres terület olyan karakterek összességeként van meghatározva, amelyek a Unicode Zs osztályába tartoznak (ideértve a szóköz karaktert), valamint a vízszintes tabulátor karaktert, a függőleges tabulátor karaktert és a lapdobás karaktert.

Whitespace
    : [\p{Zs}]  // any character with Unicode class Zs
    | '\u0009'  // horizontal tab
    | '\u000B'  // vertical tab
    | '\u000C'  // form feed
    ;

6.4 Tokenek

6.4.1 Általános

Többféle token létezik: azonosítók, kulcsszavak, literálok, operátorok és szimbólumok. A szóközök és a megjegyzések nem tokenek, de elválasztóként szolgálnak a tokenek között.

token
    : identifier
    | keyword
    | Integer_Literal
    | Real_Literal
    | Character_Literal
    | String_Literal
    | operator_or_punctuator
    ;

Megjegyzés: Ez egy ANTLR-elemző szabály, amely nem definiál lexikális tokent, hanem a tokenfajták gyűjteményét. végjegyzet

6.4.2 Unicode karakter escape szekvenciák

A Unicode feloldósorozat egy Unicode kódpontot jelöl. A Unicode-feloldósorozatok feldolgozása azonosítókban (6.4.3.§), karakterkonstansokban (6.4.5.5.5.5. §), reguláris sztringkonstansokban (6.4.5.6. §) és interpolált reguláris sztringkifejezésekben történik (12.8.3. §). A Unicode-feloldósorozatok más helyen nem dolgozhatók fel (például operátort, írásjelet vagy kulcsszót alkotnak).

fragment Unicode_Escape_Sequence
    : '\\u' Hex_Digit Hex_Digit Hex_Digit Hex_Digit
    | '\\U' Hex_Digit Hex_Digit Hex_Digit Hex_Digit
            Hex_Digit Hex_Digit Hex_Digit Hex_Digit
    ;

A Unicode-karakterek feloldási sorozata az "\u" vagy "\U" karaktereket követő hexadecimális szám által létrehozott egyetlen Unicode-kódpontot jelöli. Mivel a C# karakter- és sztringértékekben a Unicode kódpontok 16 bites kódolását használja, a tartomány U+10000U+10FFFF egy Unicode kódpontja két Unicode helyettesítő kódegység használatával jelenik meg. A fenti U+FFFF Unicode-kódpontok karakterkonstansokban nem engedélyezettek. A fenti U+10FFFF Unicode-kódpontok érvénytelenek, és nem támogatottak.

A rendszer nem végez több fordítást. Például a "\u005Cu005C" sztringkonstans egyenértékű a "\u005C" és nem a "\" elemmel.

Megjegyzés: A Unicode értéke \u005C a "\" karakter. végjegyzet

Példa: A példa

class Class1
{
    static void Test(bool \u0066)
    {
        char c = '\u0066';
        if (\u0066)
        {
            System.Console.WriteLine(c.ToString());
        }
    }
}

"\u0066 többféle használati módot mutat be, amely a „f” betű menekülési sorozatát jelenti." A program egyenértékű a

class Class1
{
    static void Test(bool f)
    {
        char c = 'f';
        if (f)
        {
            System.Console.WriteLine(c.ToString());
        }
    }
}

záró példa

6.4.3 Azonosítók

Az ebben az alklámban megadott azonosítókra vonatkozó szabályok pontosan megfelelnek a Unicode szabvány 15. mellékletében javasoltaknak, azzal a kivételével, hogy az aláhúzás kezdeti karakterként engedélyezett (a C programozási nyelvhez hasonlóan), az azonosítókban Unicode-feloldósorozatok engedélyezettek, a "@" karakter pedig előtagként, hogy a kulcsszavakat azonosítóként lehessen használni.

identifier
    : Simple_Identifier
    | contextual_keyword
    ;

Simple_Identifier
    : Available_Identifier
    | Escaped_Identifier
    ;

fragment Available_Identifier
    // excluding keywords or contextual keywords, see note below
    : Basic_Identifier
    ;

fragment Escaped_Identifier
    // Includes keywords and contextual keywords prefixed by '@'.
    // See note below.
    : '@' Basic_Identifier
    ;

fragment Basic_Identifier
    : Identifier_Start_Character Identifier_Part_Character*
    ;

fragment Identifier_Start_Character
    : Letter_Character
    | Underscore_Character
    ;

fragment Underscore_Character
    : '_'               // underscore
    | '\\u005' [fF]     // Unicode_Escape_Sequence for underscore
    | '\\U0000005' [fF] // Unicode_Escape_Sequence for underscore
    ;

fragment Identifier_Part_Character
    : Letter_Character
    | Decimal_Digit_Character
    | Connecting_Character
    | Combining_Character
    | Formatting_Character
    ;

fragment Letter_Character
    // Category Letter, all subcategories; category Number, subcategory letter.
    : [\p{L}\p{Nl}]
    // Only escapes for categories L & Nl allowed. See note below.
    | Unicode_Escape_Sequence
    ;

fragment Combining_Character
    // Category Mark, subcategories non-spacing and spacing combining.
    : [\p{Mn}\p{Mc}]
    // Only escapes for categories Mn & Mc allowed. See note below.
    | Unicode_Escape_Sequence
    ;

fragment Decimal_Digit_Character
    // Category Number, subcategory decimal digit.
    : [\p{Nd}]
    // Only escapes for category Nd allowed. See note below.
    | Unicode_Escape_Sequence
    ;

fragment Connecting_Character
    // Category Punctuation, subcategory connector.
    : [\p{Pc}]
    // Only escapes for category Pc allowed. See note below.
    | Unicode_Escape_Sequence
    ;

fragment Formatting_Character
    // Category Other, subcategory format.
    : [\p{Cf}]
    // Only escapes for category Cf allowed, see note below.
    | Unicode_Escape_Sequence
    ;

Megjegyzés:

  • A fent említett Unicode-karakterosztályokról a Unicode Standard című témakörben olvashat bővebben.
  • A töredék Available_Identifier megköveteli a kulcsszavak és a környezetfüggő kulcsszavak kizárását. Ha a specifikáció nyelvtanát ANTLR-vel dolgozzák fel, akkor ezt a kizárást automatikusan kezeli az ANTLR szemantikája:
    • A kulcsszavak és a környezetfüggő kulcsszavak a nyelvtanban szószerinti karakterláncként fordulnak elő.
    • Az ANTLR implicit lexikai token szabályokat hoz létre ezekből a literálokból.
    • Az ANTLR ezeket az implicit szabályokat a nyelvtan explicit lexikális szabályai előtt veszi figyelembe.
    • Ezért a Available_Identifier töredék nem egyezik meg a kulcsszavakkal vagy a környezetfüggő kulcsszavakkal, mivel azok lexikális szabályai megelőzik.
  • A töredék Escaped_Identifier magában foglalja az escape-el jelölt kulcsszavakat és kontextuális kulcsszavakat, mivel ezek egy hosszabb tokent alkotnak, amely egy karakterrel kezdődik, és a lexikai feldolgozás mindig a lehető leghosszabb lexikai elemet formálja meg (§6.3.1).
  • Megvalósítási probléma, hogy egy implementáció hogyan kényszeríti ki az engedélyezett Unicode_Escape_Sequence értékekre vonatkozó korlátozásokat.

végjegyzet

Példa: Az érvényes azonosítók például a identifier1, _identifier2 és @if. záró példa

A megfelelő programokban az azonosítónak a Unicode Normalization Form C által definiált kanonikus formátumban kell lennie, a Unicode Standard Melléklet 15 szerint. A C normalizálási űrlapon nem szereplő azonosítók észlelésekor a viselkedés implementációban van definiálva; azonban nincs szükség diagnosztikára.

A "@" előtag lehetővé teszi a kulcsszavak azonosítóként való használatát, ami akkor hasznos, ha más programozási nyelvekkel együttműködik. A karakter @ valójában nem része az azonosítónak, ezért az azonosító más nyelveken normál azonosítóként, az előtag nélkül is látható. Az előtaggal @ rendelkező azonosítót verbatim azonosítónak nevezzük.

Megjegyzés: A @ előtag használata az olyan azonosítóknál, amelyek nem kulcsszavak, engedélyezett, de stílusbeli okokból erősen nem javasolt. végjegyzet

Példa: A példa:

class @class
{
    public static void @static(bool @bool)
    {
        if (@bool)
        {
            System.Console.WriteLine("true");
        }
        else
        {
            System.Console.WriteLine("false");
        }
    }
}

class Class1
{
    static void M()
    {
        cl\u0061ss.st\u0061tic(true);
    }
}

egy "class" nevű osztályt határoz meg egy "static" nevű statikus metódussal, amely egy "bool" nevű paramétert használ. Vegye figyelembe, hogy mivel a Unicode escape-ek nem engedélyezettek a kulcsszavakban, a "cl\u0061ss" token egy azonosító, és ugyanaz az azonosító, mint a "@class".

záró példa

Két azonosító azonosnak minősül, ha az alábbi átalakítások alkalmazása után azonosak, sorrendben:

  • Ha használatban van, a "@" előtag eltávolításra kerül.
  • Minden Unicode_Escape_Sequence a megfelelő Unicode-karakterévé alakul át.
  • Minden Formatting_Characterel lesz távolítva.

Az elnevezett _ azonosító szemantikája attól függ, hogy milyen környezetben jelenik meg:

  • Megnevezett programelemet jelölhet, például változót, osztályt vagy metódust vagy
  • A kidobás jelölésére használható (§9.2.9.2).

A két egymást követő aláhúzásjelet (U+005F) tartalmazó azonosítók a implementáció számára vannak fenntartva; ilyen azonosító definiálása esetén azonban nincs szükség diagnosztikára.

Megjegyzés: Előfordulhat például, hogy egy implementáció kiterjesztett kulcsszavakat biztosít, amelyek két aláhúzással kezdődnek. végjegyzet

6.4.4 Kulcsszavak

A kulcsszó egy azonosítóhoz hasonló karakterlánc, amely fenntartott, és nem használható azonosítóként, kivéve ha a @ karakter áll előtte.

keyword
    : 'abstract' | 'as'       | 'base'       | 'bool'      | 'break'
    | 'byte'     | 'case'     | 'catch'      | 'char'      | 'checked'
    | 'class'    | 'const'    | 'continue'   | 'decimal'   | DEFAULT
    | 'delegate' | 'do'       | 'double'     | 'else'      | 'enum'
    | 'event'    | 'explicit' | 'extern'     | FALSE       | 'finally'
    | 'fixed'    | 'float'    | 'for'        | 'foreach'   | 'goto'
    | 'if'       | 'implicit' | 'in'         | 'int'       | 'interface'
    | 'internal' | 'is'       | 'lock'       | 'long'      | 'namespace'
    | 'new'      | NULL       | 'object'     | 'operator'  | 'out'
    | 'override' | 'params'   | 'private'    | 'protected' | 'public'
    | 'readonly' | 'ref'      | 'return'     | 'sbyte'     | 'sealed'
    | 'short'    | 'sizeof'   | 'stackalloc' | 'static'    | 'string'
    | 'struct'   | 'switch'   | 'this'       | 'throw'     | TRUE
    | 'try'      | 'typeof'   | 'uint'       | 'ulong'     | 'unchecked'
    | 'unsafe'   | 'ushort'   | 'using'      | 'virtual'   | 'void'
    | 'volatile' | 'while'
    ;

A környezetfüggő kulcsszó egy azonosítószerű karaktersorozat, amely bizonyos kontextusokban különleges jelentéssel rendelkezik, de nem foglalt, és ezen környezeteken kívül, valamint a @ karakter előtagjaként is használható.

contextual_keyword
    : 'add'     | 'alias'      | 'ascending' | 'async'     | 'await'
    | 'by'      | 'descending' | 'dynamic'   | 'equals'    | 'from'
    | 'get'     | 'global'     | 'group'     | 'into'      | 'join'
    | 'let'     | 'nameof'     | 'notnull'   | 'on'        | 'orderby'
    | 'partial' | 'remove'     | 'select'    | 'set'       | 'unmanaged'
    | 'value'   | 'var'        | 'when'      | 'where'     | 'yield'
    ;

Megjegyzés: A kulcsszó és contextual_keyword elemzői szabályok, mivel nem vezetnek be új token-típusokat. Az összes kulcsszót és a környezetfüggő kulcsszavakat implicit lexikális szabályok határozzák meg, amikor a nyelvtanban literális sztringekként fordulnak elő (6.2.3.§). végjegyzet

A legtöbb esetben a környezetfüggő kulcsszavak szintaktikai helye olyan, hogy soha nem téveszthető össze a szokásos azonosítóhasználattal. Egy tulajdonságdeklaráción belül például az és get az set azonosítók különleges jelentéssel rendelkeznek (15.7.3. §). Ezeken a helyeken get vagy set kivételével soha nem megengedett más azonosító, így ezek használata nem ütközik az ezen szavak azonosítóként való alkalmazásával.

Bizonyos esetekben a nyelvhelyesség nem elegendő a környezeti kulcsszóhasználat és az azonosítók megkülönböztetéséhez. Minden ilyen esetben meg lesz adva, hogyan lehet egyértelműsíteni a kettőt. Az implicit módon beírt helyi változódeklarációkban (var) például a környezetfüggő kulcsszó ütközhet egy deklarált vartípussal, amely esetben a deklarált név elsőbbséget élvez az azonosító környezetfüggő kulcsszóként való használatával szemben.

Egy másik ilyen egyértelműsítés például a környezetfüggő kulcsszó await (12.9.8.1. §), amelyet csak akkor tekintünk kulcsszónak, ha egy deklarált asyncmetóduson belül van, de máshol azonosítóként is használható.

A kulcsszavakhoz hasonlóan a környezetfüggő kulcsszavak is használhatók szokásos azonosítóként a karakterrel való előtagolásukkal @ .

Megjegyzés: Ha környezetfüggő kulcsszavakként használják, ezek az azonosítók nem tartalmazhatnak Unicode_Escape_Sequences-t. végjegyzet

6.4.5 Literálok

6.4.5.1 Általános

A literál (12.8.2. §) egy érték forráskód-ábrázolása.

literal
    : boolean_literal
    | Integer_Literal
    | Real_Literal
    | Character_Literal
    | String_Literal
    | null_literal
    ;

Megjegyzés: A literál egy elemzőszabály, mivel más tokentípusokat csoportosít, és nem vezet be új tokentípust. végjegyzet

6.4.5.2 Logikai literálok

Két logikai literálérték van: true és false.

boolean_literal
    : TRUE
    | FALSE
    ;

Megjegyzés: boolean_literal egy elemző szabály, mivel más jogkivonattípusokat csoportosít, és nem vezet be új jogkivonattípust. végjegyzet

A "boolean_literal" típusa bool.

6.4.5.3 Egész szám literálok

Az egész számkonstansok a int, uint, long, és ulong típusú értékek írására szolgálnak. Az egész számkonstansnak három lehetséges formája van: decimális, hexadecimális és bináris.

Integer_Literal
    : Decimal_Integer_Literal
    | Hexadecimal_Integer_Literal
    | Binary_Integer_Literal
    ;

fragment Decimal_Integer_Literal
    : Decimal_Digit Decorated_Decimal_Digit* Integer_Type_Suffix?
    ;

fragment Decorated_Decimal_Digit
    : '_'* Decimal_Digit
    ;

fragment Decimal_Digit
    : '0'..'9'
    ;

fragment Integer_Type_Suffix
    : 'U' | 'u' | 'L' | 'l' |
      'UL' | 'Ul' | 'uL' | 'ul' | 'LU' | 'Lu' | 'lU' | 'lu'
    ;

fragment Hexadecimal_Integer_Literal
    : ('0x' | '0X') Decorated_Hex_Digit+ Integer_Type_Suffix?
    ;

fragment Decorated_Hex_Digit
    : '_'* Hex_Digit
    ;

fragment Hex_Digit
    : '0'..'9' | 'A'..'F' | 'a'..'f'
    ;

fragment Binary_Integer_Literal
    : ('0b' | '0B') Decorated_Binary_Digit+ Integer_Type_Suffix?
    ;

fragment Decorated_Binary_Digit
    : '_'* Binary_Digit
    ;

fragment Binary_Digit
    : '0' | '1'
    ;

Az egész szám literáljának típusa a következőképpen van meghatározva:

  • Ha a literálnak nincs utótagja, akkor az első ilyen típusú, amelyben az érték ábrázolható: int, uint, , longulong.
  • Ha a literál utótagja U vagy u, akkor rendelkezik azzal az első típussal, amelyben az értéke ábrázolható: uint, ulong.
  • Ha a literál L vagy l utótaggal rendelkezik, akkor az első olyan típus, amelyben az értéke ábrázolható, a következő: long, ulong.
  • Ha a literál utótagja UL, Ul, uL, ul, LU, Lu, lU, vagy lu, akkor ulong típusú.

Ha egy egész számkonstans által képviselt érték kívül esik a ulong típus tartományán, fordítási időhiba lép fel.

Megjegyzés: Stílusbeli ajánlásként azt javasoljuk, hogy a „L” használata helyett inkább a „l” literált használja, amikor long típusú literálokat ír, mivel a „l” betű könnyen összetéveszthető a „1” számmal. végjegyzet

Annak érdekében, hogy a int és long legkisebb lehetséges értékei egész számkonstansként írása történhessen, a következő két szabály létezik:

  • Amikor egy Integer_Literal ábrázolja az 2147483648 (2³¹) értéket, és az Integer_Type_Suffix nem jelenik meg közvetlenül az unáris mínusz operátor után (§12.9.3), akkor az eredmény (mindkét token) egy konstans int típusú, amelynek értéke −2147483648 (−2³¹). Minden más helyzetben az ilyen Integer_Literaluint típusú.
  • Ha egy Integer_Literal az értéket 9223372036854775808 (2⁶³) jelöli, és nincs Integer_Type_Suffix vagy Integer_Type_SuffixL vagy l jelenik meg tokenként közvetlenül egy egyesítetlen mínusz operátor token után (12.9.3. §), az eredmény (mindkét tokenből) a típusállandó long, amelynek értéke −9223372036854775808 (−2⁶³). Minden más helyzetben az ilyen Integer_Literal típusú.ulong

Példa:

123                  // decimal, int
10_543_765Lu         // decimal, ulong
1_2__3___4____5      // decimal, int
_123                 // not a numeric literal; identifier due to leading _
123_                 // invalid; no trailing _allowed

0xFf                 // hex, int
0X1b_a0_44_fEL       // hex, long
0x1ade_3FE1_29AaUL   // hex, ulong
0x_abc               // hex, int
_0x123               // not a numeric literal; identifier due to leading _
0xabc_               // invalid; no trailing _ allowed

0b101                // binary, int
0B1001_1010u         // binary, uint
0b1111_1111_0000UL   // binary, ulong
0B__111              // binary, int
__0B111              // not a numeric literal; identifier due to leading _
0B111__              // invalid; no trailing _ allowed

záró példa

6.4.5.4 Valós literálok

A valós literálokat a float, double és decimal típusú értékek írására használják.

Real_Literal
    : Decimal_Digit Decorated_Decimal_Digit* '.'
      Decimal_Digit Decorated_Decimal_Digit* Exponent_Part? Real_Type_Suffix?
    | '.' Decimal_Digit Decorated_Decimal_Digit* Exponent_Part? Real_Type_Suffix?
    | Decimal_Digit Decorated_Decimal_Digit* Exponent_Part Real_Type_Suffix?
    | Decimal_Digit Decorated_Decimal_Digit* Real_Type_Suffix
    ;

fragment Exponent_Part
    : ('e' | 'E') Sign? Decimal_Digit Decorated_Decimal_Digit*
    ;

fragment Sign
    : '+' | '-'
    ;

fragment Real_Type_Suffix
    : 'F' | 'f' | 'D' | 'd' | 'M' | 'm'
    ;

Ha a Real_Type_Suffix nincs megadva, akkor a Real_Literal típusa double. Ellenkező esetben a Real_Type_Suffix az alábbiak szerint határozza meg a valódi literál típusát:

  • Az F vagy f utótaggal rendelkező valós literál típusa float.

    Példa: A literálok 1f, 1.5fés 1e10f123.456F mind típusfloat. záró példa

  • A valódi literál, amely D vagy d utótaggal van ellátva, double típusú.

    Példa: A literálok 1d, 1.5dés 1e10d123.456D mind típusdouble. záró példa

  • Az M vagy m utótaggal ellátott valódi literál a decimal típusú.

    Példa: A literálok 1m, 1.5més 1e10m123.456M mind típusdecimal. záró példa Ezt a literálist a rendszer a pontos érték megadásával konvertálja értékké decimal , és szükség esetén a legközelebbi ábrázolható értékre kerekít a banker kerekítésével (8.3.8. §). A literálban látható skálák megmaradnak, kivéve, ha az érték kerekítve van. Megjegyzés: Ezért a literál 2.900m úgy lesz elemezve, hogy a jeletdecimal, az együtthatót 0és a 2900 skálázást 3alkotja. végjegyzet

Ha a megadott literál mérete túl nagy ahhoz, hogy a megadott típusban szerepeljen, fordítási időhiba lép fel.

Megjegyzés: Egy Real_Literal soha nem hoz létre lebegőpontos végtelent. A nem nulla Real_Literal azonban nullára kerekíthető. végjegyzet

Egy float vagy double típusú valódi literál értékét az IEC 60559 "kerekítés legközelebbihez" módja határozza meg, ahol a döntetlen helyzeteket a "páros" irányába törjük (azaz az utolsó jelentős bit nullára van állítva), és minden számjegy jelentősnek számít.

Megjegyzés: Valós literálban a tizedespont után mindig szükségesek a tizedesjegyek. Például a 1.3F egy valódi literál, de a 1.F nem. végjegyzet

Példa:

1.234_567      // double
.3e5f          // float
2_345E-2_0     // double
15D            // double
19.73M         // decimal
1.F            // parsed as a member access of F due to non-digit after .
1_.2F          // invalid; no trailing _ allowed in integer part
1._234         // parsed as a member access of _234 due to non-digit after .
1.234_         // invalid; no trailing _ allowed in fraction
.3e_5F         // invalid; no leading _ allowed in exponent
.3e5_F         // invalid; no trailing _ allowed in exponent

záró példa

6.4.5.5 Karakterkonstansok

A karakterkonstans egyetlen karaktert jelöl, és idézőjelekben szereplő karakterből áll, ahogyan a .'a'

Character_Literal
    : '\'' Character '\''
    ;

fragment Character
    : Single_Character
    | Simple_Escape_Sequence
    | Hexadecimal_Escape_Sequence
    | Unicode_Escape_Sequence
    ;

fragment Single_Character
    // anything but ', \, and New_Line_Character
    : ~['\\\u000D\u000A\u0085\u2028\u2029]
    ;

fragment Simple_Escape_Sequence
    : '\\\'' | '\\"' | '\\\\' | '\\0' | '\\a' | '\\b' |
      '\\f' | '\\n' | '\\r' | '\\t' | '\\v'
    ;

fragment Hexadecimal_Escape_Sequence
    : '\\x' Hex_Digit Hex_Digit? Hex_Digit? Hex_Digit?
    ;

Megjegyzés: Olyan karakter, ami egy "backslash" karaktert (\) követ a karakterláncban, a következő karakterek egyikének kell lennie: ', ", \, 0, a, b, f, n, r, t, u, U, x, v. Ellenkező esetben fordítási időhiba lép fel. végjegyzet

Megjegyzés: A \xHexadecimal_Escape_Sequence használata hibalehetőséget jelenthet, és nehezen olvasható, mivel a hexadecimális számjegyek száma változó a következő \x. Például a kódban:

string good = "\x9Good text";
string bad = "\x9Bad text";

elsőre úgy tűnhet, hogy a kezdő karakter ugyanaz (U+0009 egy tabulátor karakter) mindkét sztringben. Valójában a második karakterlánc a U+9BAD kezdődik, mivel a "Bad" szó mindhárom betűje érvényes hexadecimális számjegy. Stílusbeli szempontból ajánlott elkerülni a \x használatát, és ehelyett vagy konkrét escape szekvenciákat (\t ebben a példában), vagy a fix hosszúságú \u escape szekvenciát alkalmazni.

végjegyzet

A hexadecimális feloldósorozat egyetlen Unicode UTF-16 kódegységet jelöl, amelynek értékét a "\x" után a hexadecimális szám alkotja.

Ha a karakterkonstans által képviselt érték nagyobb U+FFFF, fordítási időben hiba lép fel.

Egy karakterkonstans Unicode menekülési szekvenciájának (§6.4.2) az U+0000 és U+FFFF közötti tartományba kell esnie.

Az egyszerű feloldójelek unicode karaktert jelölnek az alábbi táblázatban leírtak szerint.

Menekülési sorozat Karakternév Unicode-kódpont
\' Egy idézőjel U+0027
\" Dupla idézőjel U+0022
\\ Fordított perjel U+005C
\0 Null U+0000
\a Riasztás U+0007
\b Backspace U+0008
\f Űrlapcsatorna U+000C
\n Új sor U+000A
\r Kocsi visszatérítés U+000D
\t Vízszintes lap U+0009
\v Függőleges lap U+000B

A Character_Literal típusa a következőchar: .

6.4.5.6 Sztringkonstansok

A C# a sztringkonstansok két formáját támogatja: normál sztringkonstansokat és szó szerinti sztringkonstansokat. A szokásos karakterlánc literál nulla vagy több karakterből áll, amelyek dupla idézőjelek közé vannak foglalva, és magában foglalhatja az egyszerű escape szekvenciákat (például a \t a tabulátorkarakter esetében), valamint a hexadecimális és a Unicode escape szekvenciákat is.

A szó szerinti sztring literál egy @ karakterből áll, amelyet egy dupla idézőjel, egy nulla vagy több karakter és egy záró dupla idézőjel karakter követ.

Példa: Egy egyszerű példa.@"hello" záró példa

Szó szerinti formában, a határolójelek közötti karaktereket a rendszer változtatás nélkül értelmezi, az egyetlen kivétel egy Quote_Escape_Sequence, amely egy dupla idézőjelet jelöl. Az egyszerű feloldósorozatok, valamint a hexadecimális és Unicode feloldósorozatok nem kerülnek feldolgozásra a szó szerinti karaktersorozatokban. A szó szerinti sztringkonstans több sorra is kiterjedhet.

String_Literal
    : Regular_String_Literal
    | Verbatim_String_Literal
    ;

fragment Regular_String_Literal
    : '"' Regular_String_Literal_Character* '"'
    ;

fragment Regular_String_Literal_Character
    : Single_Regular_String_Literal_Character
    | Simple_Escape_Sequence
    | Hexadecimal_Escape_Sequence
    | Unicode_Escape_Sequence
    ;

fragment Single_Regular_String_Literal_Character
    // anything but ", \, and New_Line_Character
    : ~["\\\u000D\u000A\u0085\u2028\u2029]
    ;

fragment Verbatim_String_Literal
    : '@"' Verbatim_String_Literal_Character* '"'
    ;

fragment Verbatim_String_Literal_Character
    : Single_Verbatim_String_Literal_Character
    | Quote_Escape_Sequence
    ;

fragment Single_Verbatim_String_Literal_Character
    : ~["]     // anything but quotation mark (U+0022)
    ;

fragment Quote_Escape_Sequence
    : '""'
    ;

Példa: A példa

string a = "Happy birthday, Joel"; // Happy birthday, Joel
string b = @"Happy birthday, Joel"; // Happy birthday, Joel
string c = "hello \t world"; // hello world
string d = @"hello \t world"; // hello \t world
string e = "Joe said \"Hello\" to me"; // Joe said "Hello" to me
string f = @"Joe said ""Hello"" to me"; // Joe said "Hello" to me
string g = "\\\\server\\share\\file.txt"; // \\server\share\file.txt
string h = @"\\server\share\file.txt"; // \\server\share\file.txt
string i = "one\r\ntwo\r\nthree";
string j = @"one
two
three";

számos karakterlánc literált jelenít meg. Az utolsó sztringkonstans j egy többsoros, szó szerinti sztringkonstans. Az idézőjelek közötti karakterek, beleértve a fehér szóközt, például az új vonalkaraktereket, szó szerint megmaradnak, és minden páros idézőjelet egy ilyen karakter vált fel.

záró példa

Megjegyzés: A szószerinti karakterláncok bármilyen sortörése az eredmény része. Ha a vonaltörések létrehozásához használt pontos karakterek szemantikailag relevánsak egy alkalmazás számára, minden olyan eszköz, amely a forráskód sortöréseit különböző formátumokra fordítja (például a "\n" és a "\r\n" között) megváltoztatja az alkalmazás viselkedését. Ilyen helyzetekben a fejlesztőknek óvatosnak kell lenniük. végjegyzet

Megjegyzés: Mivel a hexadecimális feloldósorozatok változó számú hexa számjegyet tartalmazhatnak, a sztringkonstans "\x123" egyetlen, hexa értékkel 123rendelkező karaktert tartalmaz. Ha olyan karakterláncot szeretne létrehozni, amely tartalmazza a hexadecimális értékű 12 karaktert, amit a 3 követ, írhat "\x00123" vagy "\x12" + "3" helyette. végjegyzet

A String_Literal típusa string.

Minden sztringkonstans nem feltétlenül eredményez új sztringpéldányt. Ha két vagy több sztringkonstans, amely a sztringegyenlőség operátorának (12.12.8. §) szerint egyenértékű, ugyanabban a szerelvényben jelenik meg, ezek a sztringkonstansok ugyanarra a sztringpéldányra vonatkoznak.

Például: Például a kimenet által előállított

class Test
{
    static void Main()
    {
        object a = "hello";
        object b = "hello";
        System.Console.WriteLine(a == b);
    }
}

azért van, True mert a két literál ugyanarra a karakterlánc példányra hivatkozik.

záró példa

6.4.5.7 A null literál

null_literal
    : NULL
    ;

Megjegyzés: A null_literal egy elemző szabály, mivel nem vezet be új azonosítótípust. végjegyzet

A null_literal egy null értéket jelölnek. Nem rendelkezik típussal, de bármely hivatkozástípusra vagy null értékű értéktípusra konvertálható null literális átalakítással (10.2.7. §).

6.4.6 Operátorok és írásjelek

Többféle operátor és írásjel is létezik. Az operátorok a kifejezésekben egy vagy több operandust érintő műveletek leírására szolgálnak.

Példa: A kifejezés a + b az + operátorral adja hozzá a két operandust a és ba . záró példa

Az írásjelek csoportosításra és elkülönítésre szolgálnak.

operator_or_punctuator
    : '{'  | '}'  | '['  | ']'  | '('   | ')'  | '.'  | ','  | ':'  | ';'
    | '+'  | '-'  | ASTERISK    | SLASH | '%'  | '&'  | '|'  | '^'  | '!' | '~'
    | '='  | '<'  | '>'  | '?'  | '??'  | '::' | '++' | '--' | '&&' | '||'
    | '->' | '==' | '!=' | '<=' | '>='  | '+=' | '-=' | '*=' | '/=' | '%='
    | '&=' | '|=' | '^=' | '<<' | '<<=' | '=>' | '??='
    ;

right_shift
    : '>'  '>'
    ;

right_shift_assignment
    : '>' '>='
    ;

Megjegyzés: right_shift és right_shift_assignment elemző szabályok, mivel nem vezetnek be új token típust, hanem két token sorozatát jelölik. A operator_or_punctuator szabály csak leíró célokra létezik, és a nyelvhelyesség más részén nem használatos. végjegyzet

A right_shift két > és > tokenből áll. Hasonlóképpen, right_shift_assignment a két tokenekből > és >=. A szintaktikai nyelvhelyesség többi produkcióitól eltérően ezen produkciók két tokenje között semmilyen karakter (még a szóköz sem) nem engedélyezett. Ezeket a termeléseket kifejezetten a type_parameter_lists megfelelő kezelése érdekében kezelik (15.2.3. §).

Megjegyzés: A generikusok C# >>-hoz való hozzáadása előtt, >>= és >> mindkettő egyetlen token volt. Azonban az általános szintaxis a < és > karaktereket a típusparaméterek és típusargumentumok elválasztására használja. Gyakran kívánatos olyan beágyazott összetett típusok használata, mint például List<Dictionary<string, int>>. Ahelyett, hogy a programozónak szóközzel kellett volna elválasztania a >-t és >-t, megváltoztatták a két operator_or_punctuator definícióját. végjegyzet

6.5 Előfeldolgozási irányelvek

6.5.1 Általános

Az előfeldolgozási irányelvek lehetővé teszik a fordítási egységek szakaszainak feltételes kihagyását, a hiba- és figyelmeztetési feltételek jelentését, a forráskód különböző régióinak kijelölését és a null értékű környezet beállítását.

Megjegyzés: Az "előfeldolgozási irányelvek" kifejezés csak a C és C++ programozási nyelvekkel való konzisztenciára szolgál. A C#-ban nincs külön előfeldolgozási lépés; az előfeldolgozási irányelveket a lexikális elemzési fázis részeként dolgozzák fel. végjegyzet

PP_Directive
    : PP_Start PP_Kind PP_New_Line
    ;

fragment PP_Kind
    : PP_Declaration
    | PP_Conditional
    | PP_Line
    | PP_Diagnostic
    | PP_Region
    | PP_Pragma
    | PP_Nullable
    ;

// Only recognised at the beginning of a line
fragment PP_Start
    // See note below.
    : { getCharPositionInLine() == 0 }? PP_Whitespace? '#' PP_Whitespace?
    ;

fragment PP_Whitespace
    : ( [\p{Zs}]  // any character with Unicode class Zs
      | '\u0009'  // horizontal tab
      | '\u000B'  // vertical tab
      | '\u000C'  // form feed
      )+
    ;

fragment PP_New_Line
    : PP_Whitespace? Single_Line_Comment? New_Line
    ;

Megjegyzés:

  • Az előfeldolgozási nyelvhelyesség egyetlen lexikális jogkivonatot PP_Directive határoz meg, amelyet az összes előfeldolgozási irányelvhez használnak. Az egyes előfeldolgozási irányelvek szemantikája ebben a nyelvi specifikációban van meghatározva, de nem az implementálásuk módjában.
  • A PP_Start töredék csak egy sor elején ismerhető fel, a getCharPositionInLine() == 0 fenti ANTLR lexikális predikátum egy olyan módszert javasol, amelyben ez megvalósítható, és csak informatív, a megvalósítás más stratégiát használhat.

végjegyzet

A következő előfeldolgozási irányelvek érhetők el:

  • #define és #undef, amelyek a feltételes fordítási szimbólumok definiálására és nem definiálására szolgálnak (6.5.4. §).
  • #if, #elif, #elseés #endif, amelyek a forráskód feltételes szakaszainak kihagyására szolgálnak (6.5.5.5. §).
  • #line, amely a hibák és figyelmeztetések során kibocsátott vonalszámok szabályozására szolgál (6.5.8. §).
  • #error, amely hibákat jelez (§6.5.6.).
  • #region és #endregion, amelyek a forráskód szakaszainak explicit megjelölésére szolgálnak (6.5.7. §).
  • #nullable, amely a null értékű környezet megadására szolgál (6.5.9. §).
  • #pragma, amely a fordító számára választható környezeti információk megadására szolgál (6.5.10. §).

Az előfeldolgozási irányelv mindig külön forráskódsort foglal el, és mindig egy karakterrel és egy # előfeldolgozási irányelv nevével kezdődik. Szóköz is előfordulhat a # karakter előtt, valamint a # karakter és az irányelv neve között.

Egy #define, #undef, #if, #elif, #else, #endif, #line, vagy #endregion direktívát tartalmazó #nullable forrásvonal egysoros megjegyzéssel végződhet. A tagolt megjegyzések (a /* */ megjegyzések stílusa) nem engedélyezettek az előfeldolgozási irányelveket tartalmazó forrásvonalakon.

Az előfeldolgozási irányelvek nem részei a C#szintaktikai nyelvtanának. Az előfeldolgozási irányelvek azonban felhasználhatók a tokenek sorozatainak beillesztésére vagy kizárására, és így befolyásolhatják a C# program jelentését.

Példa: Fordításkor a program

#define A
#undef B
class C
{
#if A
    void F() {}
#else
    void G() {}
#endif
#if B
    void H() {}
#else
    void I() {}
#endif
}

pontosan ugyanazt az elem-sorozatot eredményezi, mint a program

class C
{
    void F() {}
    void I() {}
}

Így, míg lexikálisan a két program meglehetősen eltérő, szintaktikailag azonosak.

záró példa

6.5.2 Feltételes fordítási szimbólumok

A #if, #elif, #else és #endif irányelvek által biztosított feltételes fordítási funkciókat az előfeldolgozási kifejezések (§6.5.3) és a feltételes fordítási szimbólumok vezérlik.

fragment PP_Conditional_Symbol
    // Must not be equal to tokens TRUE or FALSE. See note below.
    : Basic_Identifier
    ;

Figyelje meg, hogy az implementáció hogyan kényszeríti ki az engedélyezett Basic_Identifier értékekre vonatkozó korlátozást, az implementálási probléma. végjegyzet

Két feltételes fordítási szimbólum akkor tekinthető azonosnak, ha az alábbi átalakítások alkalmazása után azonosak, sorrendben:

  • Minden Unicode_Escape_Sequence a megfelelő Unicode-karakterévé alakul át.
  • Minden Formatting_Characters el lesz távolítva.

A feltételes fordítási szimbólumnak két lehetséges állapota van: definiált vagy nem definiált. A fordítási egység lexikális feldolgozásának elején a feltételes fordítási szimbólum nincs meghatározva, kivéve, ha azt külső mechanizmus (például parancssori fordítóbeállítás) explicit módon definiálta. Az #define irányelv feldolgozásakor az irányelvben elnevezett feltételes fordítási szimbólum az adott összeállítási egységben lesz definiálva. A szimbólum mindaddig definiálva marad, amíg #undef az adott szimbólumra vonatkozó irányelv feldolgozásra nem kerül, vagy amíg el nem éri a fordítási egység végét. Ennek az a következménye, hogy #define#undef az egyik fordítási egységben lévő irányelveknek nincs hatása az ugyanabban a programban lévő más fordítási egységekre.

Ha egy előfeldolgozási kifejezésben (6.5.3. §) hivatkoznak rá, a megadott feltételes fordítási szimbólum logikai értékkel truerendelkezik, a nem definiált feltételes fordítási szimbólum pedig logikai értékkel false. Nincs szükség arra, hogy a feltételes fordítási szimbólumok explicit módon deklarálva legyenek, mielőtt előfeldolgozási kifejezésekben hivatkoznának rájuk. Ehelyett a be nem jelentett szimbólumok egyszerűen nem definiáltak, és így rendelkeznek az értékkel false.

A feltételes fordítási szimbólumok névtere eltér a C#-program összes többi elnevezett entitásától. A feltételes fordítási szimbólumokra csak irányelvekben #define és #undef előfeldolgozási kifejezésekben lehet hivatkozni.

6.5.3 Előfeldolgozási kifejezések

Előfeldolgozó kifejezések előfordulhatnak a #if és #elif irányelvekben. Az operátorok ! (csak a logikai eltagolás előtagja), ==, !=, &&és || az előfeldolgozási kifejezésekben engedélyezettek, és zárójelek használhatók csoportosításhoz.

fragment PP_Expression
    : PP_Whitespace? PP_Or_Expression PP_Whitespace?
    ;

fragment PP_Or_Expression
    : PP_And_Expression (PP_Whitespace? '||' PP_Whitespace? PP_And_Expression)*
    ;

fragment PP_And_Expression
    : PP_Equality_Expression (PP_Whitespace? '&&' PP_Whitespace?
      PP_Equality_Expression)*
    ;

fragment PP_Equality_Expression
    : PP_Unary_Expression (PP_Whitespace? ('==' | '!=') PP_Whitespace?
      PP_Unary_Expression)*
    ;

fragment PP_Unary_Expression
    : PP_Primary_Expression
    | '!' PP_Whitespace? PP_Unary_Expression
    ;

fragment PP_Primary_Expression
    : TRUE
    | FALSE
    | PP_Conditional_Symbol
    | '(' PP_Whitespace? PP_Expression PP_Whitespace? ')'
    ;

Ha egy előfeldolgozási kifejezésben hivatkoznak rá, a megadott feltételes fordítási szimbólum logikai értékkel truerendelkezik, a nem definiált feltételes fordítási szimbólum pedig logikai értékkel false.

Az előfeldolgozási kifejezések kiértékelése mindig logikai értéket ad. Az előfeldolgozási kifejezések kiértékelési szabályai megegyeznek az állandó kifejezések (§12.23) szabályaival, azzal a kivétellel, hogy az egyetlen felhasználó által definiált entitások, amelyekre hivatkozni lehet, feltételes fordítási szimbólumok.

6.5.4 Definíciós irányelvek

A definíciós irányelvek a feltételes fordítási szimbólumok meghatározására vagy nem definiálására szolgálnak.

fragment PP_Declaration
    : 'define' PP_Whitespace PP_Conditional_Symbol
    | 'undef' PP_Whitespace PP_Conditional_Symbol
    ;

Az #define irányelv feldolgozása eredményezi a megadott feltételes szimbólum definiálását, az irányelv utáni kódsortól kezdve. Hasonlóképpen, az #undef irányelv feldolgozása miatt a megadott feltételes fordítási szimbólum definiálatlanná válik, kezdve az irányelvet követő forrásvonallal.

A bármely #define és #undef irányelvnek a fordítási egység első tokenje előtt kell szerepelnie a fordítási egységben (6.4. §), különben fordítási idejű hiba lép fel. Bélérzet szerint, a #define és #undef irányelveknek meg kell előzniük a "valódi kódot" a fordítási egységben.

Példa: A példa:

#define Enterprise
#if Professional || Enterprise
#define Advanced
#endif
namespace Megacorp.Data
{
#if Advanced
    class PivotTable {...}
#endif
}

azért érvényes, mert az #define irányelvek megelőzik az első tokent (a namespace kulcsszót) a fordítási egységben.

záró példa

Példa: Az alábbi példa fordítási idejű hibát eredményez, mert egy #define utasítás egy valós kódrészt követ.

#define A
namespace N
{
#define B
#if B
    class Class1 {}
#endif
}

záró példa

A #define meghatározhat egy már definiált feltételes fordítási szimbólumot anélkül, hogy bármi közbeavatkozna #undef ahhoz a szimbólumhoz.

Példa: Az alábbi példa egy A feltételes fordítási szimbólumot határoz meg, majd újra definiálja.

#define A
#define A

Az olyan fordítók esetében, amelyek lehetővé teszik a feltételes fordítási szimbólumok fordítási lehetőségként való definiálását, az ilyen újradefiniálás másik módja a szimbólum fordítási lehetőségként és a forrásban való definiálása.

záró példa

A #undef "definiálás megszüntetése" egy nem definiált feltételes fordítási szimbólum esetén.

Példa: Az alábbi példa egy feltételes fordítási szimbólumot A határoz meg, majd kétszer visszavonja; bár a másodiknak #undef nincs hatása, továbbra is érvényes.

#define A
#undef A
#undef A

záró példa

6.5.5 Feltételes fordítási irányelvek

A feltételes fordítási irányelvek a fordítási egység részeinek feltételes belefoglalására vagy kizárására szolgálnak.

fragment PP_Conditional
    : PP_If_Section
    | PP_Elif_Section
    | PP_Else_Section
    | PP_Endif
    ;

fragment PP_If_Section
    : 'if' PP_Whitespace PP_Expression
    ;

fragment PP_Elif_Section
    : 'elif' PP_Whitespace PP_Expression
    ;

fragment PP_Else_Section
    : 'else'
    ;

fragment PP_Endif
    : 'endif'
    ;

A feltételes fordítási irányelveket olyan csoportokba kell írni, amelyek sorrendben egy #if irányelvből, egy vagy több #elif irányelvből, nulla vagy egy #else irányelvből és egy #endif irányelvből állnak. Az irányelvek között a forráskód feltételes szakaszai találhatók. Minden szakaszt közvetlenül az előző irányelv szabályoz. A feltételes szakaszok maguk is tartalmazhatnak beágyazott feltételes fordítási irányelveket, feltéve, hogy ezek az irányelvek teljes csoportokat alkotnak.

A rendszer legfeljebb az egyik tartalmazott feltételes szakaszt választja ki a normál lexikális feldolgozáshoz:

  • A PP_Expression-ek és a #if meg #elif irányelvek kiértékelése sorrendben történik, amíg az egyik értékelés true eredményt ad. Ha egy kifejezés hozamot eredményez true, a megfelelő direktívát követő feltételes szakasz lesz kiválasztva.
  • Ha az összes PP_Expression értéket ad false, és ha jelen van egy #else irányelv, akkor a #else irányelvet követő feltételes szakasz kerül kiválasztásra.
  • Ellenkező esetben nincs feltételes szakasz kijelölve.

Ha van ilyen, a kiválasztott feltételes szakasz normál input_section-ként kerül feldolgozásra: a szakaszban található forráskódnak meg kell felelnie a lexikális nyelvtannak; tokenek jönnek létre a szakasz forráskódjából, és a szakasz előfeldolgozási irányelvei rendelkeznek az előírt hatásokkal.

A rendszer kihagyja a fennmaradó feltételes szakaszokat, és az előfeldolgozási irányelvek kivételével nem jön létre jogkivonat a forráskódból. Ezért az előfeldolgozási irányelvek kivételével kihagyott forráskód lexikálisan helytelen lehet. A kihagyott előfeldolgozási irányelveknek lexikálisan helyesnek kell lenniük, de más módon nem dolgozhatók fel. A kihagyott feltételes szakaszokon belül a beágyazott (beágyazott #if...#endif szerkezetekben található) feltételes szakaszok is kimaradnak.

Megjegyzés: A fenti nyelvtan nem veszi figyelembe azt a lehetőséget, hogy az előfeldolgozási utasítások közötti feltételes szakaszok lexikális hibákat tartalmazhatnak. Ezért a nyelvhelyesség nem ANTLR-kész, mivel csak lexikálisan helyes bemenetet támogat. végjegyzet

Példa: Az alábbi példa bemutatja, hogyan beágyazhatók a feltételes fordítási irányelvek:

#define Debug // Debugging on
#undef Trace // Tracing off
class PurchaseTransaction
{
    void Commit()
    {
#if Debug
        CheckConsistency();
    #if Trace
        WriteToLog(this.ToString());
    #endif
#endif
        CommitHelper();
    }
    ...
}

Az előfeldolgozási irányelvek kivételével a kihagyott forráskód nem vonatkozik lexikális elemzésre. Például a következő érvényes, a #else szakasz nem befejezett megjegyzése ellenére:

#define Debug // Debugging on
class PurchaseTransaction
{
    void Commit()
    {
#if Debug
        CheckConsistency();
#else
        /* Do something else
#endif
    }
    ...
}

Vegye figyelembe azonban, hogy az előfeldolgozási irányelveknek lexikálisan helyesnek kell lenniük még a forráskód kihagyott szakaszaiban is.

Az előfeldolgozási irányelvek nem lesznek feldolgozva, ha többsoros bemeneti elemekben jelennek meg. Például a program:

class Hello
{
    static void Main()
    {
        System.Console.WriteLine(@"hello,
#if Debug
        world
#else
        Nebraska
#endif
        ");
    }
}

eredmények a kimenetben:

hello,
#if Debug
        world
#else
        Nebraska
#endif

Sajátos esetekben a feldolgozott előfeldolgozási irányelvek halmaza a pp_expression értékelésétől függhet. Példa:

#if X
    /*
#else
    /* */ class Q { }
#endif

mindig ugyanazt a jogkivonat-adatfolyamot hozza létre (classQ{}), függetlenül attól, hogy a X definiálva van-e. Ha X meg van adva, az egyetlen feldolgozott irányelvek a #if és a #endif a többsoros megjegyzés miatt. Ha X nincs meghatározva, akkor három irányelv (#if, #else, #endif) része az irányelvnek.

záró példa

6.5.6 Diagnosztikai irányelvek

A diagnosztikai irányelvek kifejezetten olyan hibaüzenetek és figyelmeztető üzenetek létrehozására szolgálnak, amelyek ugyanúgy jelennek meg, mint más fordítási időpontokkal kapcsolatos hibák és figyelmeztetések.

fragment PP_Diagnostic
    : 'error' PP_Message?
    | 'warning' PP_Message?
    ;

fragment PP_Message
    : PP_Whitespace Input_Character*
    ;

Példa: A példa

#if Debug && Retail
    #error A build can't be both debug and retail
#endif
class Test {...}

Fordítási időben hibaüzenetet ("Egy build nem lehet egyszerre hibakeresési és kiadási") kapunk, ha mind a Debug, mind a Retail feltételes fordítási szimbólumok definiálva vannak. Vegye figyelembe, hogy egy PP_Message tetszőleges szöveget tartalmazhat, pontosabban nem kell jól formázott jogkivonatokat tartalmaznia, ahogyan azt a szó can'tegyetlen idézőjele is mutatja.

záró példa

6.5.7 Régiókra vonatkozó irányelvek

A régió irányelvei kifejezetten a forráskód régióinak megjelölésére szolgálnak.

fragment PP_Region
    : PP_Start_Region
    | PP_End_Region
    ;

fragment PP_Start_Region
    : 'region' PP_Message?
    ;

fragment PP_End_Region
    : 'endregion' PP_Message?
    ;

Nincs szemantikai jelentés egy régióhoz csatolva; a régiókat a programozó vagy a forráskód egy szakaszának megjelölésére szolgáló automatizált eszközök használják. Minden #endregion irányelvnek egy #region irányelvnek kell megfelelnie. Az #region vagy #endregion irányelvben megadott üzenetnek ugyanúgy nincs szemantikai jelentése; csupán a régió azonosítására szolgál. Az egyezés #region és #endregion az irányelvek eltérő PP_Messagelehetnek.

Egy régió lexikális feldolgozása:

#region
...
#endregion

pontosan megfelel az űrlap feltételes fordítási irányelvének lexikális feldolgozásának:

#if true
...
#endif

Megjegyzés: Ez azt jelenti, hogy egy régió tartalmazhat egy vagy több #if/.../#endif, vagy tartalmazhat egy feltételes szakaszt a #if/.../#endif;-on belül, de a régió nem fedheti át a #if/.../#endif-nak csak egy részét, vagy a kezdés és a befejezés különböző feltételes szakaszokban végződhet. végjegyzet

6.5.8 Vonalirányok

A sorirányelvek használhatók a fordító által jelentett sorszámok és fordítási egységek neveinek módosítására a kimenetben, mint például a figyelmeztetések és hibák esetén. Ezeket az értékeket a hívóinformációs attribútumok is használják (22.5.6. §).

Megjegyzés: A sorirányokat leggyakrabban olyan metaprogramozási eszközökben használják, amelyek más szövegbevitelből C#-forráskódot hoznak létre. végjegyzet

fragment PP_Line
    : 'line' PP_Whitespace PP_Line_Indicator
    ;

fragment PP_Line_Indicator
    : Decimal_Digit+ PP_Whitespace PP_Compilation_Unit_Name
    | Decimal_Digit+
    | DEFAULT
    | 'hidden'
    ;

fragment PP_Compilation_Unit_Name
    : '"' PP_Compilation_Unit_Name_Character* '"'
    ;

fragment PP_Compilation_Unit_Name_Character
    // Any Input_Character except "
    : ~('\u000D' | '\u000A'   | '\u0085' | '\u2028' | '\u2029' | '"')
    ;

Ha nincsenek #line irányelvek, a fordító valódi sorszámokat és fordítási egységek nevét jelenti a kimenetében. Olyan irányelv feldolgozásakor, amely nem PP_Line_Indicator tartalmaz, a fordító az irányelv utáni sor a megadott sorszámmal (és ha meg van adva a fordítási egység nevével) kezeli.

A maximális megengedett Decimal_Digit+ érték a implementáció által definiált.

Egy #line default irányelv visszavonja az összes korábbi #line irányelv hatását. A fordító a következő sorok valós sorinformációkat ad, pontosan úgy, mintha nem dolgoztak volna fel #line direktívákat.

Az #line hidden irányelv nincs hatással a hibajelzésekben szereplő fordítási egységekre és a programsor számokra, sem arra, amit a CallerLineNumberAttribute használatával (22.5.6.2. §) állítanak elő. A forrásszintű hibakeresési eszközöket úgy kívánja befolyásolni, hogy hibakereséskor az #line hidden irányelv és az azt követő #line irányelv közötti összes sor (azaz nem #line hidden) ne rendelkezzen sorszámadatokkal, és a kódon keresztüli lépegetés során teljes egészében ki legyen hagyva.

Megjegyzés: Bár a PP_Compilation_Unit_Name tartalmazhatnak olyan szöveget, amely menekülési sorozatnak tűnik, az ilyen szöveg nem menekülési sorozat; ebben az összefüggésben a "\" karakter egyszerűen egy szokásos fordított perjel karaktert jelöl. végjegyzet

6.5.9 Érvénytelen irányelv

A null értékű irányelv szabályozza a null értékű környezetet az alábbiak szerint.

fragment PP_Nullable
    : 'nullable' PP_Whitespace PP_Nullable_Action
      (PP_Whitespace PP_Nullable_Target)?
    ;
fragment PP_Nullable_Action
    : 'disable'
    | 'enable'
    | 'restore'
    ;
fragment PP_Nullable_Target
    : 'warnings'
    | 'annotations'
    ;

A null értékű irányelv beállítja a további kódsorok számára elérhető jelzőket, amíg egy másik null értékű irányelv felül nem bírálja azt, vagy amíg el nem éri a fordítási _unit végét. A null értékű környezet két jelölőt tartalmaz: széljegyzeteket és figyelmeztetéseket. A null értékű irányelv minden formájának hatása a következő:

  • #nullable disable: Letiltja a null értékű széljegyzeteket és a null értékű figyelmeztetések jelzőit.
  • #nullable enable: Engedélyezi a null értékű széljegyzeteket és a null értékű figyelmeztetések jelzőit is.
  • #nullable restore: Visszaállítja a széljegyzeteket és a figyelmeztetési jelzőket a külső mechanizmus által megadott állapotra, ha vannak ilyenek.
  • #nullable disable annotations: Letiltja a null értékű széljegyzetek jelzőt. A "nullable warnings" jelző értéke változatlan marad.
  • #nullable enable annotations: Engedélyezi a nullálható annotációk kapcsolóját. A null értékű figyelmeztetések jelzője nincs hatással.
  • #nullable restore annotations: Visszaállítja a null értékű széljegyzetek jelzőt a külső mechanizmus által megadott állapotra, ha vannak ilyenek. A nullable figyelmeztetések jelzője nincs érintve.
  • #nullable disable warnings: Letiltja a nullable figyelmeztetések jelzőjét. A null értékű annotációk jelzője nincs hatással.
  • #nullable enable warnings: Engedélyezi a null értékű figyelmeztetések jelzőt. A null értékű annotációk jelölője nincs érintve.
  • #nullable restore warnings: Visszaállítja a null értékű figyelmeztetések jelzőt a külső mechanizmus által megadott állapotra, ha van ilyen. A null értékű annotációk jelölése változatlan marad.

A kifejezések null értékű állapotát mindig nyomon követi a rendszer. A széljegyzetjelző állapota és a null értékű széljegyzetek jelenléte vagy hiánya határozza meg a változódeklaráció ?kezdeti null állapotát. A figyelmeztetések csak akkor jelennek meg, ha a figyelmeztetések jelzője engedélyezve van.

Példa: A példa

#nullable disable
string x = null;
string y = "";
#nullable enable
Console.WriteLine(x.Length); // Warning
Console.WriteLine(y.Length);

fordítási idő figyelmeztetést állít elő ("ahogy x van null"). A null értékű állapot x mindenhol nyomon követhető. Figyelmeztetést ad ki, ha a figyelmeztetések jelzője engedélyezve van.

záró példa

6.5.10 Pragma-irányelvek

Az #pragma előfeldolgozási irányelv a fordítóprogram számára környezetfüggő információk megadására szolgál.

Megjegyzés: Egy fordító például olyan irányelveket adhat meg #pragma , amelyek

  • Adott figyelmeztető üzenetek engedélyezése vagy letiltása a következő kód összeállításakor.
  • Adja meg, hogy mely optimalizálásokat kell alkalmazni a következő kódra.
  • Adja meg a hibakereső által használandó információkat.

végjegyzet

fragment PP_Pragma
    : 'pragma' PP_Pragma_Text?
    ;

fragment PP_Pragma_Text
    : PP_Whitespace Input_Character*
    ;

Az PP_Pragma_TextInput_Characterkaraktereit a fordító egy implementáció által meghatározott módon értelmezi. Az irányelvben #pragma megadott információk nem módosíthatják a program szemantikáját. Az #pragma irányelv csak az ezen nyelvi specifikáció hatókörén kívül eső fordítói viselkedést módosíthatja. Ha egy fordító nem tudja értelmezni a Input_Characterkaraktereket, a fordító figyelmeztetést adhat; azonban nem eredményezhet fordítási hibát.

Megjegyzés: PP_Pragma_Text tetszőleges szöveget tartalmazhat, pontosabban nem kell jól formázott jogkivonatokat tartalmaznia. végjegyzet