I don't recognize this as any Yacc that my hands have touched.
Looking at the reserved words,
there is one, ENTRY, that I've never heard of (although FORTRAN had an
ENTRY statement),
and there is STRUCT but no UNION. Also, he uses val= instead of
$$=. There don't seem to be
any nontrivial assignment ops (neither += or =+).
Al was at Bell Labs in 1973, and this is dated 5 years later.
The use of quotes for single character literals was in early Yaccs,
but it led to some strange-looking
lexical analyzer code, and I quickly gave it up.
I'm guessing either Al wrote it from scratch or based it on some other
similar program. LR parsing
made quite a stir in the 70's.
Can't help you though as far as how to generate a parser from this
input...
Steve
----- Original Message -----
From: "Lars Brinkhoff" <lars(a)nocrew.org>
To:<tuhs@tuhs.org>
Cc:
Sent:Sun, 28 Oct 2018 21:34:49 +0000
Subject:[TUHS] Archaic yacc C grammar
Hello,
This is Alan Snyder's C grammar. It's supposedly for yacc, but it's
probably using some really ancient version. Maybe from when Alan did
a
stint at Bell labs and converted yacc from B to C.
Does anyone recognize this type of yacc input? I don't have the
corresponding yacc version, and the one in V6 isn't happy about this
file. What would it take to update the grammar for V6 yacc? Add in
some %term, replace with %%?
# C GRAMMAR #
# 28 May 1978 #
# Alan Snyder #
# 26 acceptable conflicts:
2 S/R conflicts for (parsing) ambiguity between
declarators and function_declarators
1 S/R conflict for the C ELSE ambiguity
4 R/R conflicts for the (parsing) problem with regard
to integer constants as initial_values
12 R/R conflicts for the (parsing) problem with regard
to identifiers in function calls
1 R/R conflict for the (parsing) problem with regard
to identifiers in goto statements
4 R/R conflicts and 1 S/R conflict for TYPEDEFs
1 S/R conflict for ambiguous cast types
(int ()) = (int x()) not (int (x))
Approximate description:
18 S/R ( shift 37 reduce 141
50 S/R ( shift 37 reduce 71
81 S/R ( shift 37 reduce 71
113 R/R ( reduce 141 reduce 140
113 R/R ( reduce 159 reduce 140
113 R/R * reduce 159 reduce 141
113 S/R : shift 199 reduce 141
183 R/R , reduce 203 reduce 24
183 R/R } reduce 203 reduce 24
204 R/R ( reduce 159 reduce 140
206 R/R ( reduce 148 reduce 139
207 R/R ( reduce 147 reduce 139
208 R/R ( reduce 145 reduce 139
209 R/R ( reduce 144 reduce 139
210 R/R ( reduce 146 reduce 139
211 R/R ( reduce 149 reduce 139
212 R/R ( reduce 150 reduce 139
215 R/R ( reduce 159 reduce 140
215 R/R ; reduce 159 reduce 138
225 R/R ( reduce 151 reduce 139
228 R/R ( reduce 159 reduce 140
284 R/R , reduce 203 reduce 25
284 R/R } reduce 203 reduce 25
291 S/R ) shift 339 reduce 165
343 R/R ( reduce 153 reduce 139
360 S/R ELSE shift 369 reduce 94
#
# terminal symbols #
';' '}' '{' ']' '[' ')'
'(' ':'
',' '.' '?' '~' '!' '&'
'|' '^'
'%' '/' '*' '-' '+' '='
'<' '>'
'++' '--' '==' '!=' '<='
'>=' '<<' '>>'
'->' '=op' '&&' '||' 'c'
INT CHAR FLOAT DOUBLE STRUCT AUTO STATIC
EXTERN RETURN GOTO IF ELSE SWITCH
BREAK CONTINUE WHILE DO FOR DEFAULT CASE
ENTRY REGISTER SIZEOF LONG SHORT UNSIGNED TYPEDEF 'l'
'm' 'n' 'o' 'p' 'q' 'r'
's'
identifier integer floatcon string
# precedence information #
< ','
'=' '=op'
'?' ':'
< '||'
< '&&'
< '|'
< '^'
< '&'
< '==' '!='
< '<' '>' '<=' '>='
< '<<' '>>'
< '+' '-'
< '*' '/' '%'
'!' '~'
'++' '--' SIZEOF
< '[' '('
'.' '->'
# external definitions #
program:
program external_definition
|
external_definition:
declaration
| function_definition
function_definition:
function_specification function_body {afdef(#1,#2);}
function_specification:
decl_specifiers function_declarator {val=afdcl(1);}
| function_declarator {val=afdcl(0);}
function_body:
formal_declarations compound_statement {val=#2;}
formal_declarations:
formal_decl_list {afpdcl();}
| {afpdcl();}
compound_statement:
begin declaration_list statement_list end {val=#3;}
| begin statement_list end {val=#2;}
init_declarator_list:
init_declarator
| init_declarator_list ',' init_declarator
init_declarator:
$declarator initializer {aidecl();}
| declarator {aidecl();}
| function_declarator {adeclr(maktyp());}
initializer:
initial_value
| '{' initial_value_expression_list '}'
| '{' initial_value_expression_list ',' '}'
initial_value_expression_list:
initial_value_expression
| initial_value_expression_list ',' initial_value_expression
initial_value:
integer {inz(i_int,#1);}
| '-' integer {inz(i_int,-#2);}
| floatcon {inz(i_float,#1);}
| '-' floatcon {inz(i_negfloat,#2);}
| identifier {inz(i_idn,#1);}
| '&' identifier {inz(i_idn,#2);}
| string {inz(i_string,#1);}
initial_value_expression:
constant {inz(i_int,#1);}
| initial_value
# declarations #
declaration_list:
declaration
| declaration_list declaration
declaration:
decl_specifiers init_declarator_list ';'
| literal_type_specifier ';'
decl_specifiers:
type_specifier {attrib(-1,#1);}
| sc_specifier type_specifier {attrib(#1,#2);}
| type_specifier sc_specifier {attrib(#2,#1);}
type_specifier:
type_identifier
| literal_type_specifier
literal_type_specifier:
INT {val=TINT;}
| CHAR {val=TCHAR;}
| FLOAT {val=TFLOAT;}
| DOUBLE {val=TDOUBLE;}
| LONG {val=TINT;}
| LONG INT {val=TINT;}
| SHORT {val=TINT;}
| SHORT INT {val=TINT;}
| LONG FLOAT {val=TDOUBLE;}
| UNSIGNED {val=TINT;}
| UNSIGNED INT {val=TINT;}
| struct '{' type_decl_list '}' {val=astruct(NULL,#3);}
| struct $identifier '{' type_decl_list '}' {val=astruct(#2,#4);}
| struct identifier {val=aostruct(#2);}
sc_specifier:
AUTO {val=c_auto;}
| STATIC {val=c_static;}
| EXTERN {val=c_extern;}
| REGISTER {val=c_auto;}
| TYPEDEF {val=c_typedef;}
declarator_list:
declarator
| declarator_list ',' declarator
declarator:
dclr {val=adeclr(maktyp());}
| identifier ':' constant {val=adeclr(afield(#1,#3));}
| ':' constant {val=adeclr(afield(-1,#2));}
$declarator:
dclr {aiinz(adeclr(maktyp()));}
dclr:
'*' dclr {val=adclr(#2,MPTR);}
| dclr '(' ')' {val=adclr(#1,MFUNC);}
| dclr '[' ']' {val=adclr(#1,MARRAY,1);}
| dclr '[' constant ']' {val=adclr(#1,MARRAY,#3);}
| identifier {val=adclr(0,0);}
| '(' dclr ')' {val=#2;}
function_declarator:
'*' function_declarator {val=adclr(#2,MPTR);}
| function_declarator '(' ')' {val=adclr(#1,MFUNC);}
| function_declarator '[' ']' {val=adclr(#1,MARRAY,1);}
| function_declarator '[' constant ']' {val=adclr(#1,MARRAY,#3);}
| identifier '(' ')' {val=adclr(adclr(0,0),MFUNC);
parml=0;}
| identifier '(' parameter_list ')' {val=adclr(adclr(0,0),MFUNC);
parml=#3;}
| '(' function_declarator ')' {val=#2;}
parameter_list:
identifier {val=push(#1);}
| parameter_list ',' identifier {push(#3);}
formal_decl_list:
formal_declaration
| formal_decl_list formal_declaration
formal_declaration:
type_declaration
| REGISTER type_declaration
type_decl_list:
type_declaration
| type_decl_list type_declaration
type_declaration:
$type_specifier declarator_list ';' {in_type_def=0;
val=#2;}
$type_specifier:
type_specifier {in_type_def=1;
attrib(-1,#1);}
# statements #
statement_list:
statement
| statement_list statement {val=astmtl(#1,#2);}
statement:
expression ';' {val=aexprstmt(#1);}
| compound_statement
| IF '(' expression ')' statement {val=aif(#3,#5,0);}
| IF '(' expression ')' statement ELSE statement
{val=aif(#3,#5,#7);}
| while '(' expression ')' statement {val=awhile(#3,#5);}
| for '(' .expression ';' .expression ';' .expression
')' statement
{val=afor(#3,#5,#7,#9);}
| do statement WHILE '(' expression ')' ';'
{val=ado(#2,#5);}
| switch '(' expression ')' statement {val=aswitch(#3,#5);}
| CASE constant ':' statement {val=acase(#2,#4);}
| DEFAULT ':' statement {val=adefault(#3);}
| BREAK ';' {val=abreak();}
| CONTINUE ';' {val=acontinue();}
| RETURN ';' {val=areturn(0);}
| RETURN expression ';' {val=areturn(#2);}
| GOTO lexpression ';' {val=agoto(#2);}
| identifier ':' statement {val=alabel(#1,#3);}
| ENTRY identifier ':' statement {val=aentry(#2,#4);}
| ';' {val=anull();}
# expressions #
.expression:
expression
| {val=0;}
expression_list:
expression = '='
| expression_list ',' expression {val=aelist(#1,#3);}
expression:
expression '*' expression {val=node(n_times,#1,#3);}
| expression '/' expression {val=node(n_div,#1,#3);}
| expression '%' expression {val=node(n_mod,#1,#3);}
| expression '+' expression {val=node(n_plus,#1,#3);}
| expression '-' expression {val=node(n_minus,#1,#3);}
| expression '<<' expression {val=node(n_ls,#1,#3);}
| expression '>>' expression {val=node(n_rs,#1,#3);}
| expression '<' expression {val=node(n_lt,#1,#3);}
| expression '>' expression {val=node(n_gt,#1,#3);}
| expression '<=' expression {val=node(n_le,#1,#3);}
| expression '>=' expression {val=node(n_ge,#1,#3);}
| expression '==' expression {val=node(n_eq,#1,#3);}
| expression '!=' expression {val=node(n_ne,#1,#3);}
| expression '&' expression {val=node(n_band,#1,#3);}
| expression '^' expression {val=node(n_bxor,#1,#3);}
| expression '|' expression {val=node(n_bior,#1,#3);}
| expression '&&' expression {val=node(n_tv_and,#1,#3);}
| expression '||' expression {val=node(n_tv_or,#1,#3);}
| expression '?' expression ':' expression
{val=node(n_qmark,#1,node(n_colon,#3,#5));}
| expression '=' expression {val=node(n_assign,#1,#3);}
| expression '=op' expression {val=node(n_ars+#2,#1,#3);}
| expression ',' expression {val=node(n_comma,#1,#3);}
| term
# the following productions are ordered very carefully so that the
desired thing is done in the case of a R/R conflict #
lexpression:
expression
| identifier {val=aidn(alidn(#1));}
fterm:
term
| identifier {val=aidn(afidn(#1));}
type_identifier:
identifier {val=atidn(#1);}
term:
term '++' {val=node(n_inca,#1);}
| term '--' {val=node(n_deca,#1);}
| '*' term {val=node(n_star,#2);}
| '&' term {val=node(n_addr,#2);}
| '-' term {val=node(n_uminus,#2);}
| '!' term {val=node(n_tvnot,#2);}
| '~' term {val=node(n_bnot,#2);}
| '++' term {val=node(n_incb,#2);}
| '--' term {val=node(n_decb,#2);}
| SIZEOF term {val=node(n_sizeof,#2);}
| SIZEOF '(' cast_type ')' = SIZEOF
{val=node(n_int,1);} # hack #
| '(' cast_type ')' term = '++'
{val=#4;} # hack #
| term '[' expression ']' {val=asubscript(#1,#3);}
| fterm '(' expression_list ')' {val=acall(#1,#3);}
| fterm '(' ')' {val=acall(#1,0);}
| term '.' identifier {val=adot(#1,#3);}
| term '->' identifier {val=aptr(#1,#3);}
| identifier {val=aidn(aeidn(#1));}
| integer {val=node(n_int,#1);}
| floatcon {val=node(n_float,#1);}
| string {val=node(n_string,#1);}
| '(' expression ')' {val=#2;}
cast_type: literal_type_specifier null_decl
null_decl: # empty #
| '(' ')'
| '(' null_decl ')' '(' ')'
| '*' null_decl
| null_decl '[' ']'
| null_decl '[' constant ']'
| '(' null_decl ')'
while: WHILE {apshw();}
do: DO {apshd();}
for: FOR {apshf();}
switch: SWITCH {apshs();}
struct: STRUCT {strlev++;}
$identifier: identifier {val=astridn(#1);}
begin: '{' {abegin();}
end: '}' {aend();}
constant:
constant '*' constant {val=#1*#3;}
| constant '/' constant {val=#1/#3;}
| constant '%' constant {val=#1%#3;}
| constant '+' constant {val=#1+#3;}
| constant '-' constant {val=#1-#3;}
| constant '<<' constant {val=#1<<#3;}
| constant '>>' constant {val=#1>>#3;}
| constant '<' constant {val=#1<#3;}
| constant '>' constant {val=#1>#3;}
| constant '<=' constant {val=#1<=#3;}
| constant '>=' constant {val=#1>=#3;}
| constant '==' constant {val=#1==#3;}
| constant '!=' constant {val=#1!=#3;}
| constant '&' constant {val=#1}
| constant '^' constant {val=#1^#3;}
| constant '|' constant {val=#1|#3;}
| constant '&&' constant {val=#1&}
| constant '||' constant {val=#1||#3;}
| constant '?' constant ':' constant
{val=(#1?#3:#5);}
| c_term
c_term:
'-' c_term {val= -#2;}
| '!' c_term {val= !#2;}
| '~' c_term {val= ~#2;}
| integer
| '(' constant ')' {val=#2;}