1# LE Grammar for LE Grammars 2# 3# Copyright (c) 2007 by Ian Piumarta 4# All rights reserved. 5# 6# Permission is hereby granted, free of charge, to any person obtaining a 7# copy of this software and associated documentation files (the 'Software'), 8# to deal in the Software without restriction, including without limitation 9# the rights to use, copy, modify, merge, publish, distribute, and/or sell 10# copies of the Software, and to permit persons to whom the Software is 11# furnished to do so, provided that the above copyright notice(s) and this 12# permission notice appear in all copies of the Software. Acknowledgement 13# of the use of this Software in supporting documentation would be 14# appreciated but is not required. 15# 16# THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. 17# 18# Last edited: 2012-04-29 15:51:15 by piumarta on emilia 19 20%{ 21# include "tree.h" 22# include "version.h" 23 24# include <stdio.h> 25# include <stdlib.h> 26# include <unistd.h> 27# include <string.h> 28# include <libgen.h> 29# include <assert.h> 30 31 typedef struct Header Header; 32 33 struct Header { 34 char *text; 35 Header *next; 36 }; 37 38 FILE *input= 0; 39 40 int verboseFlag= 0; 41 42 static int lineNumber= 0; 43 static char *fileName= 0; 44 static char *trailer= 0; 45 static Header *headers= 0; 46 47 void makeHeader(char *text); 48 void makeTrailer(char *text); 49 50 void yyerror(char *message); 51 52# define YY_INPUT(buf, result, max) \ 53 { \ 54 int c= getc(input); \ 55 if ('\n' == c || '\r' == c) ++lineNumber; \ 56 result= (EOF == c) ? 0 : (*(buf)= c, 1); \ 57 } 58 59# define YY_LOCAL(T) static T 60# define YY_RULE(T) static T 61%} 62 63# Hierarchical syntax 64 65grammar= - ( declaration | definition )+ trailer? end-of-file 66 67declaration= '%{' < ( !'%}' . )* > RPERCENT { makeHeader(yytext); } #{YYACCEPT} 68 69trailer= '%%' < .* > { makeTrailer(yytext); } #{YYACCEPT} 70 71definition= identifier { if (push(beginRule(findRule(yytext)))->rule.expression) 72 fprintf(stderr, "rule '%s' redefined\n", yytext); } 73 EQUAL expression { Node *e= pop(); Rule_setExpression(pop(), e); } 74 SEMICOLON? #{YYACCEPT} 75 76expression= sequence (BAR sequence { Node *f= pop(); push(Alternate_append(pop(), f)); } 77 )* 78 79sequence= prefix (prefix { Node *f= pop(); push(Sequence_append(pop(), f)); } 80 )* 81 82prefix= AND action { push(makePredicate(yytext)); } 83| AND suffix { push(makePeekFor(pop())); } 84| NOT suffix { push(makePeekNot(pop())); } 85| suffix 86 87suffix= primary (QUESTION { push(makeQuery(pop())); } 88 | STAR { push(makeStar (pop())); } 89 | PLUS { push(makePlus (pop())); } 90 )? 91 92primary= identifier { push(makeVariable(yytext)); } 93 COLON identifier !EQUAL { Node *name= makeName(findRule(yytext)); name->name.variable= pop(); push(name); } 94| identifier !EQUAL { push(makeName(findRule(yytext))); } 95| OPEN expression CLOSE 96| literal { push(makeString(yytext)); } 97| class { push(makeClass(yytext)); } 98| DOT { push(makeDot()); } 99| action { push(makeAction(yytext)); } 100| BEGIN { push(makePredicate("YY_BEGIN")); } 101| END { push(makePredicate("YY_END")); } 102 103# Lexical syntax 104 105identifier= < [-a-zA-Z_][-a-zA-Z_0-9]* > - 106 107literal= ['] < ( !['] char )* > ['] - 108| ["] < ( !["] char )* > ["] - 109 110class= '[' < ( !']' range )* > ']' - 111 112range= char '-' char | char 113 114char= '\\' [-abefnrtv'"\[\]\\] 115| '\\' [0-3][0-7][0-7] 116| '\\' [0-7][0-7]? 117| !'\\' . 118 119action= '{' < braces* > '}' - 120 121braces= '{' braces* '}' 122| !'}' . 123 124EQUAL= '=' - 125COLON= ':' - 126SEMICOLON= ';' - 127BAR= '|' - 128AND= '&' - 129NOT= '!' - 130QUESTION= '?' - 131STAR= '*' - 132PLUS= '+' - 133OPEN= '(' - 134CLOSE= ')' - 135DOT= '.' - 136BEGIN= '<' - 137END= '>' - 138RPERCENT= '%}' - 139 140-= (space | comment)* 141space= ' ' | '\t' | end-of-line 142comment= '#' (!end-of-line .)* end-of-line 143end-of-line= '\r\n' | '\n' | '\r' 144end-of-file= !. 145 146%% 147 148void yyerror(char *message) 149{ 150 fprintf(stderr, "%s:%d: %s", fileName, lineNumber, message); 151 if (yyctx->text[0]) fprintf(stderr, " near token '%s'", yyctx->text); 152 if (yyctx->pos < yyctx->limit || !feof(input)) 153 { 154 yyctx->buf[yyctx->limit]= '\0'; 155 fprintf(stderr, " before text \""); 156 while (yyctx->pos < yyctx->limit) 157 { 158 if ('\n' == yyctx->buf[yyctx->pos] || '\r' == yyctx->buf[yyctx->pos]) break; 159 fputc(yyctx->buf[yyctx->pos++], stderr); 160 } 161 if (yyctx->pos == yyctx->limit) 162 { 163 int c; 164 while (EOF != (c= fgetc(input)) && '\n' != c && '\r' != c) 165 fputc(c, stderr); 166 } 167 fputc('\"', stderr); 168 } 169 fprintf(stderr, "\n"); 170 exit(1); 171} 172 173void makeHeader(char *text) 174{ 175 Header *header= (Header *)malloc(sizeof(Header)); 176 header->text= strdup(text); 177 header->next= headers; 178 headers= header; 179} 180 181void makeTrailer(char *text) 182{ 183 trailer= strdup(text); 184} 185 186static void version(char *name) 187{ 188 printf("%s version %d.%d.%d\n", name, PEG_MAJOR, PEG_MINOR, PEG_LEVEL); 189} 190 191static void usage(char *name) 192{ 193 version(name); 194 fprintf(stderr, "usage: %s [<option>...] [<file>...]\n", name); 195 fprintf(stderr, "where <option> can be\n"); 196 fprintf(stderr, " -h print this help information\n"); 197 fprintf(stderr, " -o <ofile> write output to <ofile>\n"); 198 fprintf(stderr, " -v be verbose\n"); 199 fprintf(stderr, " -V print version number and exit\n"); 200 fprintf(stderr, "if no <file> is given, input is read from stdin\n"); 201 fprintf(stderr, "if no <ofile> is given, output is written to stdout\n"); 202 exit(1); 203} 204 205int main(int argc, char **argv) 206{ 207 Node *n; 208 int c; 209 210 output= stdout; 211 input= stdin; 212 lineNumber= 1; 213 fileName= "<stdin>"; 214 215 while (-1 != (c= getopt(argc, argv, "Vho:v"))) 216 { 217 switch (c) 218 { 219 case 'V': 220 version(basename(argv[0])); 221 exit(0); 222 223 case 'h': 224 usage(basename(argv[0])); 225 break; 226 227 case 'o': 228 if (!(output= fopen(optarg, "w"))) 229 { 230 perror(optarg); 231 exit(1); 232 } 233 break; 234 235 case 'v': 236 verboseFlag= 1; 237 break; 238 239 default: 240 fprintf(stderr, "for usage try: %s -h\n", argv[0]); 241 exit(1); 242 } 243 } 244 argc -= optind; 245 argv += optind; 246 247 if (argc) 248 { 249 for (; argc; --argc, ++argv) 250 { 251 if (!strcmp(*argv, "-")) 252 { 253 input= stdin; 254 fileName= "<stdin>"; 255 } 256 else 257 { 258 if (!(input= fopen(*argv, "r"))) 259 { 260 perror(*argv); 261 exit(1); 262 } 263 fileName= *argv; 264 } 265 lineNumber= 1; 266 if (!yyparse()) 267 yyerror("syntax error"); 268 if (input != stdin) 269 fclose(input); 270 } 271 } 272 else 273 if (!yyparse()) 274 yyerror("syntax error"); 275 276 if (verboseFlag) 277 for (n= rules; n; n= n->any.next) 278 Rule_print(n); 279 280 Rule_compile_c_header(); 281 282 for (; headers; headers= headers->next) 283 fprintf(output, "%s\n", headers->text); 284 285 if (rules) 286 Rule_compile_c(rules); 287 288 if (trailer) 289 fprintf(output, "%s\n", trailer); 290 291 return 0; 292} 293