Yacc (Yet Another Compiler-Compiler) egy számítógépes program a Unix operációs rendszerhez, amelyet Stephen C. Johnson fejlesztett ki. Ez egy előretekintő balról jobbra elemző (LALR) parser generátor, amely egy LALR elemzőt (a fordítónak azt a részét, amely megpróbálja megérteni a forráskódot) generál egy formális nyelvtan alapján, amely a Backus-Naur formához (BNF) hasonló jelöléssel íródott. A BSD és az AT&T Unix szabványos segédprogramként szállítja az Yacc-t. A GNU-alapú Linux disztribúciók tartalmazzák a Bison-t, egy előre kompatibilis Yacc helyettesítő programot.
Az 1970-es évek elején Stephen C. Johnson, a Bell Labs/AT&T informatikusa fejlesztette ki az Yacc-ot, mert kizáró vagy operátort (XOR) akart beilleszteni egy B nyelvű fordítóba (amelyet McIlroy TMG fordító-fordítójának felhasználásával fejlesztett ki), de ez nehéz feladatnak bizonyult. Ennek eredményeként a Bell Labs-nél dolgozó kollégája, Al Aho irányította Donald Knuth LR-elemzéssel kapcsolatos munkájához, amely az Yacc alapjául szolgált. Az Yacc a TMG fordító-fordítóra volt hatással, és a TMG fordító-fordítóra utalva (Még egy fordító-fordító) kapta a nevét.
Az Yacc eredetileg B programozási nyelven íródott, de hamarosan Alan Snyder átírta C nyelven. A Unix 3-as verziójának részeként jelent meg, és az Yacc teljes leírása 1975-ben jelent meg.
Johnson az Yacc-t használta a Portable C Compiler megalkotásához. Bjarne Stroustrup szintén megpróbálta az Yacc-t használni a C++ formális specifikációjának megalkotásához, de „a C szintaxisa legyőzte”. Bár Stroustrup nem találta alkalmasnak a nyelv formális specifikációjára, mégis az Yacc segítségével implementálta a Cfrontot, a C++ első implementációját.
Egy 2008-as interjúban Johnson azt mondta, hogy „az Yacc hozzájárulása a Unix és a C elterjedéséhez az, amire a legbüszkébb vagyok”.
Az Yacc bemenete egy nyelvtan, amelynek szabályaihoz C kódrészleteket (úgynevezett „akciókat”) csatolnak. A kimenete egy C nyelvű shift-reduce elemző, amely végrehajtja az egyes szabályokhoz tartozó C kódrészleteket, amint a szabály felismerésre kerül. A tipikus műveletek közé tartozik az elemzési fák felépítése. Egy Johnson-példát használva, ha a node(label, left, right) hívás egy bináris elemzési fa-csomópontot épít a megadott címkével (label) és gyermekekkel, akkor a szabály
expr : expr '+' expr { $$ = node('+', $1, $3); }
felismeri az összegző kifejezéseket, és csomópontokat hoz létre számukra. A speciális azonosítók $$, $1 és $3 az elemző vermének elemeire utalnak.
Az Yacc csak egy elemzőt (phrase analyzer) állít elő, amely egyedül is használható szkenner nélküli elemzés esetén, azonban a teljes szintaktikai elemzéshez általában egy külső lexikai elemzőre van szükség, amely először egy tokenizálási szakaszt végez (szóelemzés), amelyet aztán a tényleges elemzési szakasz követ. Erre a célra széles körben elérhetőek lexikai elemző generátorok, mint például a Lex vagy a Flex. Az IEEE POSIX P1003.2 szabvány meghatározza a Lex és az Yacc funkcióit és követelményeit.
Az AT&T Yacc néhány verziója nyílt forráskódúvá vált. A forráskód például a Plan 9 standard disztribúcióival együtt elérhető.
Ezek a példaprogramok együtt egy egyszerű, asztali számológépet hoznak létre, amely összeadási, kivonási, szorzási és osztási műveleteket hajt végre. Ez a számolóprogram azt is lehetővé teszi, hogy értékeket rendeljen a változókhoz (mindegyik kisbetűvel van jelölve), majd a változókat számításokban használja. A példa lex és yacc programokat tartalmazó fájlok a következők:
A következő leírások feltételezik, hogy a calc.lex és calc.yacc example példaprogramok az aktuális könyvtárban találhatók.
A számológép példa programjának elkészítéséhez a következő lépéseket kell sorrendben végrehajtani:
1. Az yacc nyelvtani fájl feldolgozása a -d opcionális kapcsolóval (amely arra utasítja az yacc parancsot, hogy hozzon létre egy fájlt, amely meghatározza a C nyelv forráskódja mellett használt tokeneket):
yacc -d calc.yacc2. Az ls paranccsal ellenőrizhető, hogy a következő fájlok létrejöttek-e:
3. A lex specifikációs fájl feldolgozása:
lex calc.lex4. Az ls parancs ellenőrzi, hogy a következő fájl létrejött-e:
5. Fordítsa le és linkelje a két C nyelvű forrásfájlt:
cc y.tab.c lex.yy.c6. Az ls paranccsal ellenőrizze, hogy a következő fájlok létrejöttek-e:
$ a.out$ mv a.out calculate$ calculatem=4 <enter>m+5 <enter>9%{
#include <stdio.h>
int regs[26];
int base;
%}
%start list
%token DIGIT LETTER
%left '|'
%left '&'
%left '+' '-'
%left '*' '/' '%'
%left UMINUS /* elsőbbséget biztosít az unáris mínuszhoz */
%% /* szabályok szakasz eleje */
list: /*empty */
|
list stat '\n'
|
list error '\n'
{
yyerrok;
}
;
stat: expr
{
printf("%d\n",$1);
}
|
LETTER '=' expr
{
regs[$1] = $3;
}
;
expr: '(' expr ')'
{
$$ = $2;
}
|
expr '*' expr
{
$$ = $1 * $3;
}
|
expr '/' expr
{
$$ = $1 / $3;
}
|
expr '%' expr
{
$$ = $1 % $3;
}
|
expr '+' expr
{
$$ = $1 + $3;
}
|
expr '-' expr
{
$$ = $1 - $3;
}
|
expr '&' expr
{
$$ = $1 & $3;
}
|
expr '|' expr
{
$$ = $1 | $3;
}
|
'-' expr %prec UMINUS
{
$$ = -$2;
}
|
LETTER
{
$$ = regs[$1];
}
|
number
;
number: DIGIT
{
$$ = $1;
base = ($1==0) ? 8 : 10;
} |
number DIGIT
{
$$ = base * $1 + $2;
}
;
%%
main()
{
return(yyparse());
}
yyerror(s)
char *s;
{
fprintf(stderr, "%s\n",s);
}
yywrap()
{
return(1);
}
%{
#include <stdio.h>
#include "y.tab.h"
int c;
extern int yylval;
%}
%%
" " ;
[a-z] {
c = yytext[0];
yylval = c - 'a';
return(LETTER);
}
[0-9] {
c = yytext[0];
yylval = c - '0';
return(DIGIT);
}
[^a-z0-9\b] {
c = yytext[0];
return(c);
}
Annak ellenére, hogy a példák a C nyelv szintaxisára hasonlítanak, azok nem C-programok, hanem az yacc és a lex forrásprogramjai.
Az itt ismertetett példaprogram megfelelő környezetben (UNIX/Linux) lefordítható és működőképes.
Az Yacc és a hasonló programok (nagyrészt újraimplementációk) nagyon népszerűek voltak. Maga az Yacc a legtöbb Unix rendszerben alapértelmezett elemzőgenerátorként volt elérhető, bár azóta olyan újabb, nagyrészt kompatibilis programok váltották fel, mint a Berkeley Yacc, a GNU Bison, az MKS Yacc és az Abraxas PCYACC. Az eredeti AT&T Yacc frissített változata a Sun OpenSolaris projekt részeként szerepel. Mindegyik kisebb javításokat és további funkciókat kínál az eredeti Yacc-hoz képest, de a koncepció és az alapvető szintaxis ugyanaz maradt.
Az Yacc egyike volt a Charles River Data Systems UNOS operációs rendszeréhez Bell Laboratories licenc alapján elérhető UNIX eszközöknek.
Az Yacc segítségével elsőként megvalósított nyelvek között szerepel az AWK, a C++, az eqn és a Pic. Az Yacc-t Unixon is használták a Portable C Compiler, valamint olyan programozási nyelvek elemzőinek implementálására, mint a FORTRAN 77, Ratfor, APL, bc, m4 stb.
Az Yacc-t más nyelvekre is átírták, többek között OCaml, Ratfor, ML, Ada, Pascal, Java, PHP, Python, Ruby, Go, Common Lisp és Erlang nyelvekre.
After the TMG version of B was working, Thompson rewrote B in itself(a bootstrapping step).…When Johnson returned to Bell Labs in 1973, he was disconcerted to find that the language whose seeds he had brought to Canada had evolved back home; even his own yacc program had been rewritten in C, by Alan Snyder.
{{cite conference}}: Check |first= value (súgó)
yacc Unix Manualyacc(1) – Linux kézikönyv