Capitolul IV
Structura lexicală Java

4.1 Setul de caractere
4.2 Unități lexicale

4.3 Comentarii

4.1 Setul de caractere

Limbajului Java lucrează în mod nativ folosind setul de caractere Unicode. Acesta este un standard internațional care înlocuiește vechiul set de caractere ASCII. Motivul acestei înlocuiri a fost necesitatea de a reprezenta mai mult de 256 de caractere. Setul de caractere Unicode, fiind reprezentat pe 16 biți are posibilități mult mai mari.

Vechiul standard ASCII este însă un subset al setului Unicode, ceea ce înseamnă că vom regăsi caracterele ASCII cu exact aceleași coduri ca și mai înainte în noul standard.

Java folosește setul Unicode în timpul rulării aplicațiilor ca și în timpul compilării acestora. Folosirea Unicode în timpul execuției nu înseamnă nimic altceva decât faptul că o variabilă Java de tip caracter este reprezentată pe 16 biți iar un șir de caractere va ocupa fizic în memorie de doua ori mai mulți octeți decât numărul caracterelor care formează șirul.

În ceea ce privește folosirea Unicode în timpul compilării, compilatorul Java acceptă la intrare fișiere sursă care pot conține orice caractere Unicode. Se poate lucra și cu fișiere ASCII obișnuite în care putem introduce caractere Unicode folosind secvențe escape. Fișierele sursă sunt fișiere care conțin declarații și instrucțiuni Java. Aceste fișiere trec prin trei pași distincți la citirea lor de către compilator:

  1. Șirul de caractere Unicode sau ASCII, memorat în fișierul sursă, este transformat într-un șir de caractere Unicode. Caracterele Unicode pot fi introduse și ca secvențe escape folosind doar caractere ASCII.
  2. Șirul de caractere Unicode este transformat într-un șir de caractere în care sunt evidențiate separat caracterele de intrare față de caracterele de sfârșit de linie.
  3. Șirul de caractere de intrare și de sfârșit de linie este transformat într-un șir de cuvinte ale limbajului Java.

În primul pas al citirii fișierului sursă, sunt generate secvențe escape. Secvențele escape sunt secvențe de caractere ASCII care încep cu caracterul backslash \. Pentru secvențele escape Unicode, al doilea caracter din secvență trebuie să fie u sau U. Orice alt caracter care urmează după backslash va fi considerat ca fiind caracter nativ Unicode și lăsat nealterat. Dacă al doilea caracter din secvența escape este u, următoarele patru caractere ASCII sunt tratate ca și cifre hexazecimale (în baza 16) care formează împreună doi octeți de memorie care reprezintă un caracter Unicode.

Se pot folosi la intrare și fișiere ASCII normale, pentru că ASCII este un subset al Unicode. De exemplu, putem scrie:

int f\u0660 = 3;

Numele variabilei are două caractere și al doilea caracter este o cifră arabic-indic.

Exemple de secvențe Unicode:

\uaa08 \U0045 \uu6abe

În al doilea pas al citirii fișierului sursă, sunt recunoscute ca și caractere de sfârșit de linie caracterele ASCII CR și ASCII LF. În același timp, secvența de caractere ASCII CR-ASCII LF este tratată ca un singur sfârșit de linie și nu două. În acest mod, Java suportă în comun standardele de terminare a liniilor folosite de diferite sisteme de operare: MacOS, Unix și DOS.

Este important să separăm caracterele de sfârșit de linie de restul caracterelor de intrare pentru a ști unde se termină comentariile de o singură linie (care încep cu secvența //) precum și pentru a raporta odată cu erorile de compilare și linia din fișierul sursă în care au apărut acestea.

În pasul al treilea al citirii fișierului sursă, sunt izolate elementele de intrare ale limbajului Java, și anume: spații, comentarii și unități lexicale.

Spațiile pot fi caracterele ASCII SP (spațiu), FF (avans de pagină) sau HT (tab orizontal) precum și orice caracter terminator de linie. Comentariile le vom discuta în paragraful 4.3. ^

4.2 Unități lexicale

Unitățile lexicale sunt elementele de bază cu care se construiește semantica programelor Java. În șirul de cuvinte de intrare, unitățile lexicale sunt separate între ele prin comentarii și spații. Unitățile lexicale în limbajul Java pot fi:

  • Cuvinte cheie
  • Identificatori
  • Literali
  • Separatori
  • Operatori ^

4.2.1 Cuvinte cheie

Cuvintele cheie sunt secvențe de caractere ASCII rezervate de limbaj pentru uzul propriu. Cu ajutorul lor, Java își definește unitățile sintactice de bază. Nici un program nu poate să utilizeze aceste secvențe altfel decât în modul în care sunt definite de limbaj. Singura excepție este aceea că nu există nici o restricționare a apariției cuvintelor cheie în șiruri de caractere sau comentarii.

Cuvintele cheie ale limbajului Java sunt:

abstract
boolean
break
byte
case
cast
catch
char
class
const
continue
default
do
double
else
extends
final
finally
float
for
future
generic
goto
if
implements
import
inner
instanceof
intinterface
long
native
new
null
operator
outer
package
private
protected
public
rest
return
short
static
super
switch
synchronized
this
throw
throws
transient
try
var
void
volatile
while
byvalue

Dintre acestea, cele îngroșate sunt efectiv folosite, iar restul sunt rezervate pentru viitoare extensii ale limbajului. ^

4.2.2 Identificatori

Identificatorii Java sunt secvențe nelimitate de litere și cifre Unicode, începând cu o literă. Identificatorii nu au voie să fie identici cu cuvintele rezervate.

Cifrele Unicode sunt definite în următoarele intervale:

Reprezentare Unicode

Caracter ASCII

Explicație

\u0030-\u0039

0-9

cifre ISO-LATIN-1

\u0660-\u0669

 

cifre Arabic-Indic

\u06f0-\u06f9

 

cifre Eastern Arabic-Indic

\u0966-\u096f

 

cifre Devanagari

\u09e6-\u09ef

 

cifre Bengali

\u0a66-\ u0a6f

 

cifre Gurmukhi

\u0ae6-\u0aef

 

cifre Gujarati

\u0b66-\u0b6f

 

cifre Oriya

\u0be7-\u0bef

 

cifre Tamil

\u0c66-\u0c6f

 

cifre Telugu

\u0ce6-\u0cef

 

cifre Kannada

\u0d66-\u0d6f

 

cifre Malayalam

\u0e50-\u0e59

 

cifre Thai

\u0ed0-\u0ed9

 

cifre Lao

\u1040-\u1049

 

cifre Tibetan

Tabelul 4.1 Cifrele Unicode.

Un caracter Unicode este o literă dacă este în următoarele intervale și nu este cifră:

Reprezentare Unicode

Caracter ASCII

Explicație

\u0024

$

semnul dolar (din motive istorice)

\u0041-\u005a

A-Z

litere majuscule Latin

\u005f

_

underscore (din motive istorice)

\u0061-\u007a

a-z

litere minuscule Latin

\u00c0-\u00d6

 

diferite litere Latin cu diacritice

\u00d8-\u00f6

 

diferite litere Latin cu diacritice

\u00f8-\u00ff

 

diferite litere Latin cu diacritice

\u0100-\u1fff

 

alte alfabete și simboluri non-CJK

\u3040-\u318f

 

Hiragana, Katakana, Bopomofo, și Hangul

\u3300-\u337f

 

cuvinte pătratice CJK

\u3400-\u3d2d

 

simboluri Hangul coreene

\u4e00-\u9fff

 

Han (Chinez, Japonez, Corean)

\uf900-\ufaff

 

compatibilitate Han

Tabelul 4.2 Literele Unicode. ^

4.2.3 Literali

Un literal este modalitatea de bază de exprimare în fișierul sursă a valorilor pe care le pot lua tipurile primitive și tipul șir de caractere. Cu ajutorul literalilor putem introduce valori constante în variabilele de tip primitiv sau în variabilele de tip șir de caractere.

În limbajul Java există următoarele tipuri de literali:

  • literali întregi
  • literali flotanți
  • literali booleeni
  • literali caracter
  • literali șir de caractere ^

4.2.3.1 Literali întregi

Literalii întregi pot fi reprezentați în baza 10, 16 sau 8. Toate caracterele care se folosesc pentru scrierea literalilor întregi fac parte din subsetul ASCII al setului Unicode.

Literalii întregi pot fi întregi normali sau lungi. Literalii lungi se recunosc prin faptul că se termină cu sufixul l sau L. Un literal întreg este reprezentat pe 32 de biți iar unul lung pe 64 de biți.

Un literal întreg în baza 10 începe cu o cifră de la 1 la 9 și se continuă cu un șir de cifre de la 0 la 9. Un literal întreg în baza 10 nu poate să înceapă cu cifra 0, pentru că acesta este semnul folosit pentru a semnaliza literalii scriși în baza 8.

Exemple de literali întregi în baza 10:

12356L234871234567890l

Exemplul al doilea și al patrulea sunt literali întregi lungi.

Pentru a exprima un literal întreg în baza 16 trebuie să definim cifrele de la 10 la 15. Convenția va fi următoarea:

10 - a, A13 - d, D
11 - b, B14 - e, E
12 - c, C15 - f, F

În plus, pentru că un literal întreg în baza 16 poate începe cu o literă, vom adăuga prefixul 0x sau 0X. Dacă nu am adăuga acest sufix, compilatorul ar considera că este vorba despre un identificator.

Exemple de literali întregi în baza 16:

0xa340X1230x2c45L0xde123abccdL

Ultimele două exemple sunt literali întregi lungi.

În fine, pentru a reprezenta un literal întreg în baza 8, îl vom preceda cu cifra 0. Restul cifrelor pot fi oricare între 0 și 7. Cifrele 8 și 9 nu sunt admise în literalii întregi în baza 8.

Exemple de literali întregi în baza 8:

0234500123001234567712345677L

Valoarea maximă a unui literal întreg normal este de 2147483647 (231-1), scrisă în baza 10. În baza 16, cel mai mare literal pozitiv se scrie ca 0x7fffffff iar în baza 8 ca 017777777777. Toate trei scrierile reprezintă de fapt aceeași valoare, doar că aceasta este exprimată în baze diferite.

Cea mai mică valoare a unui literal întreg normal este -2147483648 (-231), respectiv 0x80000000 și 020000000000. Valorile 0xffffffff și 037777777777 reprezintă amândouă valoarea -1.

Specificarea în sursă a unui literal întreg normal care depășește aceste limite reprezintă o eroare de compilare. Cu alte cuvinte, dacă folosim în sursă numărul: 21474836470 de exemplu, fără să punem sufixul de număr lung după el, compilatorul va genera o eroare la analiza sursei.

Valoarea maximă a unui literal întreg lung este, în baza 10, 9223372036854775807L (263-1). În octal, asta înseamnă 0777777777777777777777L iar în baza 16 0x7fffffffffffffffL. În mod asemănător, valoarea minimă a unui literal întreg lung este -9223372036854775808L (-263-1), în octal această valoare este 0400000000000000000000L iar în baza 16 este 0x8000000000000000L.

La fel ca și la literalii întregi normali, depășirea acestor limite este o eroare de compilare. ^

4.2.3.2 Literali flotanți

Literalii flotanți reprezintă numere reale. Ei sunt formați dintr-o parte întreagă, o parte fracționară, un exponent și un sufix de tip. Exponentul, dacă există, este introdus de litera e sau E urmată opțional de un semn al exponentului.

Este obligatoriu să existe măcar o cifră fie în partea întreagă fie în partea zecimală și punctul zecimal sau litera e pentru exponent.

Sufixul care indică tipul flotantului poate fi f sau F în cazul în care avem o valoare flotantă normală și d sau D dacă avem o valoare flotantă dublă. Dacă nu este specificat nici un sufix, valoarea este implicit dublă.

Valoarea maximă a unui literal flotant normal este 3.40282347e+38f iar valoarea cea mai mică reprezentabilă este 1.40239846e-45f, ambele reprezentate pe 32 de biți.

Valoarea maximă reprezentabilă a unui literal flotant dublu este de 1.79769313486231570e+308 iar valoarea cea mai mică reprezentabilă este 4.94065645841246544e-324, ambele reprezentate pe 64 de biți.

La fel ca și la literalii întregi, este o eroare să avem exprimat în sursă un literal mai mare decât valoarea maximă reprezentabilă sau mai mic decât cea mai mică valoare reprezentabilă.

Exemple de literali flotanți:

1.0e45f-3.456f0..01e-3

Primele două exemple reprezintă literali flotanți normali, iar celelalte literali flotanți dubli. ^

4.2.3.3 Literali booleeni

Literalii booleeni nu pot fi decât true sau false, primul reprezentând valoarea booleană de adevăr iar celălalt valoarea booleană de fals. True și false nu sunt cuvinte rezervate ale limbajului Java, dar nu veți putea folosi aceste cuvinte ca identificatori. ^

4.2.3.4 Literali caracter

Un literal de tip caracter este utilizat pentru a exprima caracterele codului Unicode. Reprezentarea se face fie folosind o literă, fie o secvență escape. Secvențele escape ne permit reprezentarea caracterelor care nu au reprezentare grafică și reprezentarea unor caractere speciale precum backslash și însăși caracterul apostrof.

Caracterele care au reprezentare grafică pot fi reprezentate între apostrofe, ca în exemplele:

'a' 'Ș' ','

Pentru restul caracterelor Unicode trebuie să folosim secvențe escape. Dintre acestea, câteva sunt predefinite în Java, și anume:

Secvență escape

Caracterul reprezentat

'\b'

caracterul backspace BS \u0008

'\t'

caracterul tab orizontal HT \u0009

'\n'

caracterul linefeed LF \u000a

'\f'

caracterul formfeed FF \u000c

'\r'

caracterul carriage return CR \u000d

'\"'

caracterul ghilimele \u0022

'\''

caracterul apostrof \u0027

'\\'

caracterul backslash \u005c

Tabelul 4.3 Secvențe escape predefinite în Java.

În formă generală, o secvență escape se scrie sub una din formele:

'\o' '\oo''\too'

unde o este o cifră octală iar t este o cifră octală între 0 și 3.

Nu este corect să folosiți ca valori pentru literale caracter secvența '\u000d' (caracterul ASCII CR), sau altele care reprezintă caractere speciale, pentru că acestea fiind secvențe escape Unicode sunt transformate foarte devreme în timpul procesării sursei în caractere CR și sunt interpretate ca terminatori de linie.

Exemple de secvențe escape:

'\n''\u23a''\34'

dacă după caracterul backslash urmează altceva decât: b, t, n, f, r, ", ', \, 0, 1, 2, 3, 4, 5, 6, 7 se va semnala o eroare de compilare.

În acest moment secvențele escape Unicode au fost deja înlocuite cu caractere Unicode native. Dacă u apare după \, se semnalează o eroare de compilare. ^

4.2.3.5 Literali șir de caractere

Un literal șir de caractere este format din zero sau mai multe caractere între ghilimele. Caracterele care formează șirul de caractere pot fi caractere grafice sau secvențe escape ca cele definite la literalii caracter.

Dacă un literal șir de caractere conține în interior un caracter terminator de linie va fi semnalată o eroare de compilare. Cu alte cuvinte, nu putem avea în sursă ceva de forma:

"Acesta este
greșit!”

chiar dacă aparent exprimarea ar reprezenta un șir format din caracterele A, c, e, s, t, a, spațiu, e, s, t, e, linie nouă, g, r, e, ș, i, t, !. Dacă dorim să introducem astfel de caractere terminatoare de linie într-un șir va trebui să folosim secvențe escape ca în:

“Acesta este\ngreșit”

Dacă șirul de caractere este prea lung, putem să-l spargem în bucăți mai mici pe care să le concatenăm cu operatorul +.

Fiecare șir de caractere este în fapt o instanță a clasei de obiecte String declarată standard în pachetul java.lang.

Exemple de șiruri de caractere:

"""\"""Șir de caractere""unu" + "doi"

Primul șir de caractere din exemplu nu conține nici un caracter și se numește șirul vid. Ultimul exemplu este format din două șiruri distincte concatenate. ^

4.2.4 Separatori

Un separator este un caracter care indică sfârșitul unei unități lexicale și începutul alteia. Separatorii sunt necesari atunci când unități lexicale diferite sunt scrise fără spații între ele. Acestea se pot totuși separa dacă unele dintre ele conțin caractere separatori. În Java separatorii sunt următorii:

( ) { } [ ] ; , .

Exemple de separare:

a[i]sin(56)

În primul exemplu nu avem o singură unitate lexicală ci patru: a, [, i, ]. Separatorii [ și ] ne dau această informație. În al doilea exemplu, unitățile lexicale sunt tot 4 sin, (, 56, ).

Atenție, separatorii participă în același timp și la construcția sintaxei limbajului. Ei nu sunt identici cu spațiile deși, ca și acestea, separă unități lexicale diferite. ^

4.2.5 Operatori

Operatorii reprezintă simboluri grafice pentru operațiile elementare definite de limbajul Java. Despre operatori vom discuta mai mult atunci când vom prezenta expresiile. Deocamdată, iată lista tuturor operatorilor limbajului Java:

=><!~?:
==<=>=!=&&||++--
+-*/&|^%<<>> >>>
+=-=*=/=&=|=^=%=<<=>>=>>>=

Să mai precizăm deocamdată că toți operatorii joacă și rol de separatori. Cu alte cuvinte, din secvența de caractere:

vasile+gheorghe

putem extrage trei unități lexicale, vasile, + și gheorghe. ^

4.3 Comentarii

Un comentariu este o secvență de caractere existentă în fișierul sursă dar care servește doar pentru explicarea sau documentarea sursei și nu afectează în nici un fel semantica programelor.

În Java există trei feluri de comentarii:

  • Comentarii pe mai multe linii, închise între /* și */. Toate caracterele dintre cele două secvențe sunt ignorate.
  • Comentarii pe mai multe linii care țin de documentație, închise între /** și */. Textul dintre cele două secvențe este automat mutat în documentația aplicației de către generatorul automat de documentație.
  • Comentarii pe o singură linie care încep cu //. Toate caracterele care urmează acestei secvențe până la primul caracter sfârșit de linie sunt ignorate.

În Java, nu putem să scriem comentarii în interiorul altor comentarii. La fel, nu putem introduce comentarii în interiorul literalilor caracter sau șir de caractere. Secvențele /* și */ pot să apară pe o linie după secvența // dar își pierd semnificația. La fel se întâmplă cu secvența // în comentarii care încep cu /* sau /**.

Ca urmare, următoarea secvență de caractere formează un singur comentariu:

/* acest comentariu /* // /* se termină abia aici: */ ^
[cuprins]
(C) IntegraSoft 1996-1998