Come hai sottolineato, gli esseri umani comunicano tra loro attraverso una lingua "naturale" come inglese, francese, tedesco. Sono chiamati naturali perché li acquisiamo naturalmente piuttosto che inventarli intenzionalmente (l'esperanto è un'eccezione).
Un linguaggio formale è uno inventato per uno scopo o altro. Un linguaggio di programmazione come C, ad esempio, è un linguaggio formale inventato ai fini della programmazione dei computer.
Tutte le lingue possono essere descritte usando una grammatica. Una gerarchia di grammatiche è stata descritta da Noam Chomsky nel 1956. È composta dai seguenti livelli:
Grammatiche di tipo 0 (grammatiche senza restrizioni). Sono i più generici e equivalgono a una macchina di Turing. In quanto tale, il problema di decidere se una determinata stringa fa parte di una grammatica senza restrizioni è indecidibile.
Grammatiche di tipo 1 (grammatiche sensibili al contesto). Quasi tutte le lingue naturali come l'inglese sono sensibili al contesto. Un esempio di sensibilità al contesto in inglese sono le due frasi: "Il tempo vola come una freccia". e "La frutta vola come una banana". In generale, per i computer è difficile comprendere i linguaggi sensibili al contesto.
Grammatiche di tipo 2 (senza contesto). I linguaggi senza contesto sono la base teorica della sintassi della maggior parte dei linguaggi di programmazione.
Grammatiche di tipo 3 (grammatiche regolari). La famiglia delle lingue regolari può essere ottenuta da espressioni regolari. I linguaggi regolari sono comunemente usati per definire modelli di ricerca e la struttura lessicale dei linguaggi di programmazione.
Le grammatiche di tipo 2 (senza contesto) e di tipo 3 (regolari) sono spesso eseguite dai computer perché i loro parser possono essere implementati in modo efficiente.
BNF (Backus Normal Form o Backus – Naur Form) è una tecnica di notazione per grammatiche senza contesto, spesso utilizzata per descrivere la sintassi dei linguaggi utilizzati nell'informatica.
Ad esempio un identificatore potrebbe essere descritto come:
<identifier> ::= <letter> { <letter> | <digit> }
il che significa che deve iniziare con una lettera e può contenere lettere o cifre aggiuntive.
In precedenza, una lettera è definita una "a" | 'b' | 'c' ecc. e la cifra viene definita da '0' a '9' usando lo stesso tipo di notazione.
L'istruzione "for" potrebbe essere definita come:
<for_statement> ::=
'for' '(' <expression> ';' <expression> ';' <expression> ')' <statement>
Analizzatori e parser lessicali (i primi stadi di un compilatore o interprete) sono quindi costruiti per accettare la grammatica specifica descritta dal BNF per un particolare linguaggio. Gli analizzatori lessicali vengono in genere utilizzati per separare i vari token di una lingua (come una parola chiave, un identificatore o un numero) e il parser viene utilizzato per capire come funzionano i token insieme, ad esempio come viene costruita un'istruzione "for" .