Share via


Struttura lessicale

Documenti

Un documento M è una sequenza ordinata di caratteri Unicode. Il linguaggio M consente di inserire diverse classi di caratteri Unicode in diverse parti di un documento M. Per informazioni sulle classi di caratteri Unicode, vedere Standard Unicode, versione 3.0, sezione 4.5.

Un documento può essere costituito da una sola espressione o da gruppi di definizioni organizzati in sezioni. Le sezioni vengono descritte in dettaglio nel capitolo 10. A livello concettuale, la lettura dell'espressione di un documento si articola nei passaggi seguenti:

  1. Il documento viene decodificato in base allo schema di codifica dei caratteri in una sequenza di caratteri Unicode.

  2. Viene eseguita l'analisi lessicale, in modo che il flusso di caratteri Unicode venga convertito in un flusso di token. L'analisi lessicale viene affrontata nelle sottosezioni rimanenti di questa sezione.

  3. Viene eseguita l'analisi sintattica, in modo che il flusso di token venga convertito in un formato che possa essere valutato. Questo processo viene affrontato nelle sezioni successive.

Convenzioni grammaticali

Le grammatiche lessicali e sintattiche vengono presentate usando produzioni grammaticali. Ogni produzione grammaticale definisce un simbolo non terminale e le possibili espansioni del simbolo, in sequenze di simboli terminali o non terminali. Nelle produzioni grammaticali, i simboli non-terminal+ vengono visualizzati in corsivo e i simboli terminal in un tipo di carattere a larghezza fissa.

La prima riga di una produzione grammaticale corrisponde al nome del simbolo non terminale definito, seguito da due punti. Ogni successiva riga rientrata contiene una possibile espansione del simbolo non terminale, specificata come sequenza di simboli terminali o non terminali. Ad esempio, la produzione:

if-expression:
      ifif-conditionthentrue-expressionelsefalse-expression

definisce che una if-expression deve essere composta dal token if, seguito da una if-condition, seguita dal token then, seguito da una true-expression, seguita dal token else, seguito da una false-expression.

Se esiste più di un'espansione possibile per un simbolo non terminale, le alternative vengono elencate in righe separate. Ad esempio, la produzione:

variable-list:
      Variabile
      variable-list
,variable

definisce che una variable-list deve essere composta da una variable o da una variable-list seguita da una variable. In altre parole, la definizione è ricorsiva e specifica che un elenco di variabili è costituito da una o più variabili, separate da virgole.

Per indicare un simbolo facoltativo, viene usato un suffisso con indice "opt". La produzione:

field-specification:
      optionalopt field-name=field-type

è una sintassi abbreviata per:

field-specification:
      field-name
=field-type
      optionalfield-name=field-type

e definisce che una field-specification può iniziare con il simbolo del terminale optional seguito da un field-name, dal simbolo del terminale = e da un field-type.

Le alternative, in genere, sono elencate in righe separate ma, nel caso in cui esistano molte alternative, la frase "uno/a tra" può precedere un elenco di espansioni in una singola riga. Si tratta semplicemente di una sintassi abbreviata per elencare ognuna delle alternative in una riga distinta. Ad esempio, la produzione:

decimal-digit: uno tra
      0 1 2 3 4 5 6 7 8 9

è una sintassi abbreviata per:

decimal-digit:
      0
      1
      2
      3
      4
      5
      6
      7
      8
      9

Analisi lessicale

La produzione lexical-unit definisce la grammatica lessicale per un documento M. Ogni documento M valido è conforme a questa grammatica.

lexical-unit:
      lexical-elementsopt
lexical-elements:
      lexical-element
      lexical-element
      lexical-elements
lexical-element:
      whitespace
      token comment

A livello lessicale, un documento M è costituito da un flusso di elementi whitespace, comment e token. Ciascuna di queste produzioni viene trattata nelle sezioni seguenti. Nella grammatica sintattica solo gli elementi token sono significativi.

Spazio vuoto

In un documento M, per separare commenti e token viene usato uno spazio vuoto, composto dal carattere di spazio (appartenente alla classe Unicode Zs), da un carattere di tabulazione orizzontale e uno verticale, da un carattere di avanzamento carta e da sequenze di caratteri di nuova riga. Le sequenze di caratteri di nuova riga includono: ritorno a capo, avanzamento riga, ritorno a capo seguito da avanzamento riga, riga successiva e separatore di paragrafo.

whitespace:
      Qualsiasi carattere con classe Unicode Zs
      Carattere di tabulazione orizzontale (U+0009)
      Carattere di tabulazione verticale (U+000B)
      Carattere di avanzamento carta (U+000C)
      Carattere di ritorno a capo (U+000D) seguito da un carattere di avanzamento riga (U+000A)
      new-line-character
new-line-character:
      Carattere di ritorno a capo (U+000D)
      Carattere di avanzamento riga (U+000A)
      Carattere di nuova riga (U+0085)
      Carattere separatore di riga (U+2028)
      Carattere separatore di paragrafo (U+2029)

Per compatibilità con gli strumenti di modifica del codice sorgente che aggiungono marcatori di fine file e per consentire la visualizzazione di un documento come sequenza di righe con terminazioni appropriate, a un documento M vengono applicate (in ordine) le trasformazioni seguenti:

  • Se l'ultimo carattere del documento è un carattere Control-Z (U+001A), viene eliminato.

  • Alla fine del documento viene aggiunto un carattere di ritorno a capo (U+000D) se il documento non è vuoto e se l'ultimo carattere del documento non è un ritorno a capo (U+000D), un avanzamento riga (U+000A), un separatore di riga (U+2028) o un separatore di paragrafo (U+2029).

Commenti

Sono supportati due tipi di commenti: commenti su riga singola e commenti delimitati. I commenti su riga singola iniziano con i caratteri // e si estendono fino alla fine della riga di codice sorgente. I commenti delimitati iniziano con i caratteri /* e terminano con i caratteri */.

I commenti delimitati possono estendersi su più righe.

comment:
      single-line-comment
      delimited-comment
single-line-comment:

      //single-line-comment-charactersopt
single-line-comment-characters:
      single-line-comment-character single-line-comment-charactersopt
single-line-comment-character:

      Qualsiasi carattere Unicode ad eccezione di new-line-character
delimited-comment:

      /*delimited-comment-textopt asterisks/
delimited-comment-text:
      delimited-comment-section delimited-comment-textopt
delimited-comment-section:

      /
      asterisksopt not-slash-or-asterisk
asterisks:

      *asterisksopt
not-slash-or-asterisk:

      Qualsiasi carattere Unicode ad eccezione di * o /

I commenti non vengono annidati. Le sequenze di caratteri /* e */ non hanno un significato speciale in un commento su riga singola, così come le sequenze di caratteri // e /* non hanno un significato speciale in un commento delimitato.

I commenti non vengono elaborati all'interno di valori letterali di testo. L'esempio:

/* Hello, world 
*/ 
    "Hello, world"

include un commento delimitato.

L'esempio:

// Hello, world 
// 
"Hello, world" // This is an example of a text literal

mostra vari commenti su riga singola.

OAuth

Un token può essere rappresentato un identificatore, una parola chiave, un valore letterale, un operatore o un segno di punteggiatura. Per separare i token vengono usati spazi vuoti e commenti, che tuttavia non sono token.

token:
      identificatore
      keyword
      literal
      operator-or-punctuator

Sequenze di caratteri di escape

I valori di testo M possono contenere caratteri Unicode arbitrari. I valori letterali di testo, tuttavia, sono limitati ai caratteri grafici e, per i caratteri non grafici, è necessario quindi usare sequenze di escape. Ad esempio, per includere un carattere di ritorno a capo, di avanzamento riga o di tabulazione in un valore letterale di testo, è possibile usare, rispettivamente, le sequenze di escape #(cr), #(lf) e #(tab). Per incorporare i caratteri di inizio di sequenza di escape #( in un valore letterale di testo, è necessario eseguire l'escape del carattere # stesso:

#(#)(

Le sequenze di escape possono contenere anche valori di punti di codice Unicode Short (quattro cifre esadecimali) o Long (otto cifre esadecimali). Le tre sequenze di escape seguenti sono quindi equivalenti:

#(000D)     // short Unicode hexadecimal value 
#(0000000D) // long Unicode hexadecimal value 
#(cr)       // compact escape shorthand for carriage return

In una singola sequenza di escape possono essere inclusi più codici di escape, separati da virgole; le due sequenze seguenti sono quindi equivalenti:

#(cr,lf) 
#(cr)#(lf)

Di seguito viene descritto il meccanismo standard di escape dei caratteri in un documento M.

character-escape-sequence:
      #(escape-sequence-list)
escape-sequence-list:
      single-escape-sequence
      single-escape-sequence
,escape-sequence-list
single-escape-sequence:
      long-unicode-escape-sequence
      short-unicode-escape-sequence
      control-character-escape-sequence
      escape-escape
long-unicode-escape-sequence:
      hex-digit hex-digit hex-digit hex-digit hex-digit hex-digit hex-digit hex-digit
short-unicode-escape-sequence:
      hex-digit hex-digit hex-digit hex-digit
control-character-escape-sequence:
      control-character
control-character:

      cr
      lf
      tab
escape-escape:
      #

Letterali

Un valore letterale è una rappresentazione del codice sorgente di un valore.

literal:
      logical-literal
      number-literal
      text-literal
      null-literal
      verbatim-literal

Valori letterali Null

Per scrivere il valore null viene usato il valore letterale Null. Il valore null rappresenta un valore assente.

null-literal:
      null

Valori letterali logici

Per scrivere i valori true e false viene usato un valore letterale logico, che produce un valore logico.

logical-literal:
      true
      false

Valori letterali numerici

Per scrivere un valore numerico viene usato un valore letterale numerico, che produce un valore numerico.

number-literal:
      decimal-number-literal
      hexadecimal-number-literal
decimal-number-literal:
      decimal-digits
.decimal-digits exponent-partopt
      .decimal-digits exponent-partopt
      decimal-digits exponent-partopt
decimal-digits:
      decimal-digit decimal-digitsopt
decimal-digit:
uno tra
      0 1 2 3 4 5 6 7 8 9
exponent-part:
      esignopt decimal-digits
      Esignopt decimal-digits
sign:
uno tra
      + -
hexadecimal-number-literal:
      0xhex-digits
      0Xhex-digits
hex-digits:
      hex-digit hex-digitsopt
hex-digit:
one of
      0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f

È possibile specificare un numero in formato esadecimale anteponendo a hex-digits i caratteri 0x. Ad esempio:

0xff // 255

Se in un valore letterale numerico è incluso un separatore decimale, deve essere seguito almeno da una cifra. Ad esempio, 1.3 è un valore letterale numerico, mentre 1. e 1.e3 non lo sono.

Valori letterali di testo

Un valore letterale di testo consente di scrivere una sequenza di caratteri Unicode e produce un valore di testo.

text-literal:
      "text-literal-charactersopt"
text-literal-characters:
      text-literal-character text-literal-charactersopt
text-literal-character:
      single-text-character
      character-escape-sequence
      double-quote-escape-sequence
single-text-character:

      Qualsiasi carattere ad eccezione di " (U+0022) o # (U+0023), seguito da ( (U+0028)
double-quote-escape-sequence:
      "" (U+0022, U+0022)

Per includere le virgolette in un valore di testo, il segno delle virgolette deve essere ripetuto, come illustrato di seguito:

"The ""quoted"" text" // The "quoted" text

La produzione character-escape-sequence può essere usata per scrivere caratteri in valori di testo senza doverli codificare direttamente come caratteri Unicode nel documento. Per inserire un ritorno a capo e un avanzamento di riga, ad esempio, è necessario digitare:

"Hello world#(cr,lf)"

Valori letterali verbatim

Un valore letterale verbatim viene usato per archiviare una sequenza di caratteri Unicode immessi da un utente come codice, ma che non possono essere analizzati correttamente come codice. In fase di esecuzione, viene generato un valore di errore.

verbatim-literal:
      #!"text-literal-charactersopt"

Identifiers

Con il termine identificatore si fa riferimento a un valore. Gli identificatori possono essere regolari o delimitati.

identifier:
      regular-identifier
      quoted-identifier
regular-identifier:
      available-identifier
      available-identifier dot-character regular-identifier
available-identifier:

      Un elemento keyword-or-identifierdiverso da keyword
keyword-or-identifier:
      identifier-start-character identifier-part-charactersopt
identifier-start-character:
      letter-character
      underscore-character
identifier-part-characters:
      identifier-part-character identifier-part-charactersopt
identifier-part-character:
      letter-character
      decimal-digit-character
      underscore-character
      connecting-character
      combining-character
      formatting-character
dot-character:

      . (U+002E)
underscore-character:
      _ (U+005F)
letter-character:
      Carattere Unicode di classe Lu, Ll, Lt, Lm, Lo o Nl
combining-character:
      Carattere Unicode di classe Mn o Mc
decimal-digit-character:
      Carattere Unicode di classe Nd
connecting-character:
      Carattere Unicode di classe Pc
formatting-character:
      Carattere Unicode di classe Cf

Un quoted-identifier consente di usare come identificatore qualsiasi sequenza di zero o più caratteri Unicode, tra cui parole chiave, spazi vuoti, commenti, operatori e segni di punteggiatura.

quoted-identifier:
      #"text-literal-charactersopt"

Tenere presente che le sequenze di escape e le virgolette doppie per l'escape delle virgolette possono essere usate in un quoted-identifier, così come in un text-literal.

Nell'esempio seguente viene usata la delimitazione dell'identificatore per i nomi contenenti un carattere spazio:

[ 
    #"1998 Sales" = 1000, 
    #"1999 Sales" = 1100, 
    #"Total Sales" = #"1998 Sales" + #"1999 Sales"
]

Nell'esempio seguente viene usata la delimitazione dell'identificatore per includere l'operatore + in un identificatore:

[ 
    #"A + B" = A + B, 
    A = 1, 
    B = 2 
]

Identificatori generalizzati

Nel linguaggio M esistono due posizioni in cui non vengono introdotte ambiguità dagli identificatori che contengono spazi vuoti o sono costituiti da parole chiave o da valori letterali numerici. Queste posizioni sono costituite dai nomi dei campi di record in un record valore letterale e in un operatore di accesso ai campi ([ ]). Il linguaggio M consente quindi di inserire questi identificatori senza dover usare identificatori delimitati.

[ 
    Data = [ Base Line = 100, Rate = 1.8 ], 
    Progression = Data[Base Line] * Data[Rate]
]

Gli identificatori usati per nominare e accedere ai campi prendono il nome di identificatori generalizzati e vengono definiti come illustrato di seguito:

generalized-identifier:
      generalized-identifier-part
      generalized-identifier
separati solo da spazi vuoti (U+0020)
generalized-identifier-part
generalized-identifier-part:
      generalized-identifier-segment
      decimal-digit-character generalized-identifier-segment
generalized-identifier-segment:
      keyword-or-identifier
      keyword-or-identifier dot-character keyword-or-identifier

Parole chiave

Una parola chiave è una sequenza riservata di caratteri di tipo identificatore che non è possibile usare come identificatore, tranne quando si usa il meccanismo identifier-quoting o è consentito un identificatore generalizzato.

keyword: una tra
       and as each else error false if in is let meta not null or otherwise
       section shared then true try type #binary #date #datetime
       #datetimezone #duration #infinity #nan #sections #shared #table #time

Operatori e segni di punteggiatura

Esistono diversi tipi di operatori e segni di punteggiatura. Gli operatori vengono usati nelle espressioni per descrivere le operazioni che includono uno o più operandi. L'espressione a + b, ad esempio, usa l'operatore + per aggiungere i due operandi a e b. I segni di punteggiatura consentono invece di raggruppare e separare.

operator-or-punctuator: uno tra
      , ; = < <= > >= <> + - * / & ( ) [ ] { } @ ! ? ?? => .. ...