rexpr.c
上传用户:itx_2006
上传日期:2007-01-06
资源大小:493k
文件大小:10k
源码类别:

编译器/解释器

开发平台:

Others

  1. /*
  2.  * This file contains code for
  3.  *
  4.  *      int rexpr(char *expr, char *s);
  5.  *
  6.  * which answers
  7.  *
  8.  *      1 if 's' is in the language described by the regular expression 'expr'
  9.  *      0 if it is not
  10.  *     -1 if the regular expression is invalid
  11.  *
  12.  * Language membership is determined by constructing a non-deterministic
  13.  * finite automata (NFA) from the regular expression.  A depth-
  14.  * first-search is performed on the NFA (graph) to check for a match of 's'.
  15.  * Each non-epsilon arc consumes one character from 's'.  Backtracking is
  16.  * performed to check all possible paths through the NFA.
  17.  *
  18.  * Regular expressions follow the meta-language:
  19.  *
  20.  * <regExpr>        ::= <andExpr> ( '|' <andExpr> )*
  21.  *
  22.  * <andExpr>        ::= <expr> ( <expr> )*
  23.  *
  24.  * <expr>           ::= {'~'} '[' <atomList> ']' <repeatSymbol>
  25.  *                      | '(' <regExpr> ')' <repeatSymbol>
  26.  *                      | '{' <regExpr> '}' <repeatSymbol>
  27.  *                      | <atom> <repeatSymbol>
  28.  *
  29.  * <repeatSymbol>   ::= { '*' | '+' }
  30.  *
  31.  * <atomList>       ::= <atom> ( <atom> )*
  32.  *                      | { <atomList> } <atom> '-' <atom> { <atomList> }
  33.  *
  34.  * <atom>           ::= Token[Atom]
  35.  *
  36.  * Notes:
  37.  * ~ means complement the set in [..]. i.e. all characters not listed
  38.  * * means match 0 or more times (can be on expression or atom)
  39.  * + means match 1 or more times (can be on expression or atom)
  40.  * {} optional
  41.  * () grouping
  42.  * [] set of atoms
  43.  * x-y all characters from x to y (found only in [..])
  44.  * xx the character with value xx
  45.  *
  46.  * Examples:
  47.  * [a-z]+
  48.  * match 1 or more lower-case letters (e.g. variable)
  49.  *
  50.  * 0x[0-9A-Fa-f]+
  51.  * match a hex number with 0x on front (e.g. 0xA1FF)
  52.  *
  53.  * [0-9]+.[0-9]+{e[0-9]+}
  54.  * match a floating point number (e.g. 3.14e21)
  55.  *
  56.  * Code example:
  57.  * if ( rexpr("[a-zA-Z][a-zA-Z0-9]+", str) ) then str is keyword
  58.  *
  59.  * Terence Parr
  60.  * Purdue University
  61.  * April 1991
  62.  */
  63. #include <stdio.h>
  64. #include <ctype.h>
  65. #ifdef __STDC__
  66. #include <stdlib.h>
  67. #else
  68. #include <malloc.h>
  69. #endif
  70. #include "rexpr.h"
  71. #ifdef __STDC__
  72. static int regExpr( GraphPtr g );
  73. static int andExpr( GraphPtr g );
  74. static int expr( GraphPtr g );
  75. static int repeatSymbol( GraphPtr g );
  76. static int atomList( char *p, int complement );
  77. static int next( void );
  78. static ArcPtr newGraphArc( void );
  79. static NodePtr newNode( void );
  80. static int ArcBetweenGraphNode( NodePtr i, NodePtr j, int label );
  81. static Graph BuildNFA_atom( int label );
  82. static Graph BuildNFA_AB( Graph A, Graph B );
  83. static Graph BuildNFA_AorB( Graph A, Graph B );
  84. static Graph BuildNFA_set( char *s );
  85. static Graph BuildNFA_Astar( Graph A );
  86. static Graph BuildNFA_Aplus( Graph A );
  87. static Graph BuildNFA_Aoptional( Graph A );
  88. #else
  89. static int regExpr();
  90. static int andExpr();
  91. static int expr();
  92. static int repeatSymbol();
  93. static int atomList();
  94. static int next();
  95. static ArcPtr newGraphArc();
  96. static NodePtr newNode();
  97. static int ArcBetweenGraphNode();
  98. static Graph BuildNFA_atom();
  99. static Graph BuildNFA_AB();
  100. static Graph BuildNFA_AorB();
  101. static Graph BuildNFA_set();
  102. static Graph BuildNFA_Astar();
  103. static Graph BuildNFA_Aplus();
  104. static Graph BuildNFA_Aoptional();
  105. #endif
  106. static char *_c;
  107. static int token, tokchar;
  108. static NodePtr accept;
  109. static NodePtr freelist = NULL;
  110. /*
  111.  * return 1 if s in language described by expr
  112.  *        0 if s is not
  113.  *       -1 if expr is an invalid regular expression
  114.  */
  115. rexpr(expr, s)
  116. char *expr, *s;
  117. {
  118. NodePtr p,q;
  119. Graph nfa;
  120. int result;
  121. fprintf(stderr, "rexpr(%s,%s);n", expr,s);
  122. freelist = NULL;
  123. _c = expr;
  124. next();
  125. if ( regExpr(&nfa) == -1 ) return -1;
  126. accept = nfa.right;
  127. result = match(nfa.left, s);
  128. /* free all your memory */
  129. p = q = freelist;
  130. while ( p!=NULL ) { q = p->track; free(p); p = q; }
  131. return result;
  132. }
  133. /*
  134.  * do a depth-first-search on the NFA looking for a path from start to
  135.  * accept state labelled with the characters of 's'.
  136.  */
  137. match(automaton, s)
  138. NodePtr automaton;
  139. char *s;
  140. {
  141. ArcPtr p;
  142. if ( automaton == accept && *s == '' ) return 1; /* match */
  143. for (p=automaton->arcs; p!=NULL; p=p->next) /* try all arcs */
  144. {
  145. if ( p->label == Epsilon )
  146. {
  147. if ( match(p->target, s) ) return 1;
  148. }
  149. else if ( p->label == *s )
  150. if ( match(p->target, s+1) ) return 1;
  151. }
  152. return 0;
  153. }
  154. /*
  155.  * <regExpr>        ::= <andExpr> ( '|' {<andExpr>} )*
  156.  *
  157.  * Return -1 if syntax error
  158.  * Return  0 if none found
  159.  * Return  1 if a regExrp was found
  160.  */
  161. static
  162. regExpr(g)
  163. GraphPtr g;
  164. {
  165. Graph g1, g2;
  166. if ( andExpr(&g1) == -1 )
  167. {
  168. return -1;
  169. }
  170. while ( token == '|' )
  171. {
  172. int a;
  173. next();
  174. a = andExpr(&g2);
  175. if ( a == -1 ) return -1; /* syntax error below */
  176. else if ( !a ) return 1; /* empty alternative */
  177. g1 = BuildNFA_AorB(g1, g2);
  178. }
  179. if ( token!='' ) return -1;
  180. *g = g1;
  181. return 1;
  182. }
  183. /*
  184.  * <andExpr>        ::= <expr> ( <expr> )*
  185.  */
  186. static
  187. andExpr(g)
  188. GraphPtr g;
  189. {
  190. Graph g1, g2;
  191. if ( expr(&g1) == -1 )
  192. {
  193. return -1;
  194. }
  195. while ( token==Atom || token=='{' || token=='(' || token=='~' || token=='[' )
  196. {
  197. if (expr(&g2) == -1) return -1;
  198. g1 = BuildNFA_AB(g1, g2);
  199. }
  200. *g = g1;
  201. return 1;
  202. }
  203. /*
  204.  * <expr>           ::=    {'~'} '[' <atomList> ']' <repeatSymbol>
  205.  *                      | '(' <regExpr> ')' <repeatSymbol>
  206.  *                      | '{' <regExpr> '}' <repeatSymbol>
  207.  *                      | <atom> <repeatSymbol>
  208.  */
  209. static
  210. expr(g)
  211. GraphPtr g;
  212. {
  213. int complement = 0;
  214. char s[257];    /* alloc space for string of char in [] */
  215. if ( token == '~' || token == '[' )
  216. {
  217. if ( token == '~' ) {complement = 1; next();}
  218. if ( token != '[' ) return -1;
  219. next();
  220. if ( atomList( s, complement ) == -1 ) return -1;
  221. *g = BuildNFA_set( s );
  222. if ( token != ']' ) return -1;
  223. next();
  224. repeatSymbol( g );
  225. return 1;
  226. }
  227. if ( token == '(' )
  228. {
  229. next();
  230. if ( regExpr( g ) == -1 ) return -1;
  231. if ( token != ')' ) return -1;
  232. next();
  233. repeatSymbol( g );
  234. return 1;
  235. }
  236. if ( token == '{' )
  237. {
  238. next();
  239. if ( regExpr( g ) == -1 ) return -1;
  240. if ( token != '}' ) return -1;
  241. next();
  242. /* S p e c i a l  C a s e   O p t i o n a l  {  } */
  243. if ( token != '*' && token != '+' )
  244. {
  245. *g = BuildNFA_Aoptional( *g );
  246. }
  247. repeatSymbol( g );
  248. return 1;
  249. }
  250. if ( token == Atom )
  251. {
  252. *g = BuildNFA_atom( tokchar );
  253. next();
  254. repeatSymbol( g );
  255. return 1;
  256. }
  257. return -1;
  258. }
  259. /*
  260.  * <repeatSymbol>   ::= { '*' | '+' }
  261.  */
  262. static
  263. repeatSymbol(g)
  264. GraphPtr g;
  265. {
  266. switch ( token )
  267. {
  268. case '*' : *g = BuildNFA_Astar( *g ); next(); break;
  269. case '+' : *g = BuildNFA_Aplus( *g ); next(); break;
  270. }
  271. return 1;
  272. }
  273. /*
  274.  * <atomList>       ::= <atom> { <atom> }*
  275.  *                      { <atomList> } <atom> '-' <atom> { <atomList> }
  276.  *
  277.  * a-b is same as ab
  278.  * q-a is same as q
  279.  */
  280. static
  281. atomList(p, complement)
  282. char *p;
  283. int complement;
  284. {
  285. static unsigned char set[256]; /* no duplicates */
  286. int first, last, i;
  287. char *s = p;
  288. if ( token != Atom ) return -1;
  289. for (i=0; i<256; i++) set[i] = 0;
  290. while ( token == Atom )
  291. {
  292. if ( !set[tokchar] ) *s++ = tokchar;
  293. set[tokchar] = 1;     /* Add atom to set */
  294. next();
  295. if ( token == '-' )          /* have we found '-' */
  296. {
  297. first = *(s-1);             /* Get last char */
  298. next();
  299. if ( token != Atom ) return -1;
  300. else
  301. {
  302. last = tokchar;
  303. }
  304. for (i = first+1; i <= last; i++)
  305. {
  306. if ( !set[tokchar] ) *s++ = i;
  307. set[i] = 1;     /* Add atom to set */
  308. }
  309. next();
  310. }
  311. }
  312. *s = '';
  313. if ( complement )
  314. {
  315. for (i=0; i<256; i++) set[i] = !set[i];
  316. for (i=1,s=p; i<256; i++) if ( set[i] ) *s++ = i;
  317. *s = '';
  318. }
  319. return 1;
  320. }
  321. /* a somewhat stupid lexical analyzer */
  322. static
  323. next()
  324. {
  325. while ( *_c==' ' || *_c=='t' || *_c=='n' ) _c++;
  326. if ( *_c=='\' )
  327. {
  328. _c++;
  329. if ( isdigit(*_c) )
  330. {
  331. int n=0;
  332. while ( isdigit(*_c) )
  333. {
  334. n = n*10 + (*_c++ - '0');
  335. }
  336. if ( n>255 ) n=255;
  337. tokchar = n;
  338. }
  339. else
  340. {
  341. switch (*_c)
  342. {
  343. case 'n' : tokchar = 'n'; break;
  344. case 't' : tokchar = 't'; break;
  345. case 'r' : tokchar = 'r'; break;
  346. default  : tokchar = *_c;
  347. }
  348. _c++;
  349. }
  350. token = Atom;
  351. }
  352. else if ( isgraph(*_c) && *_c!='[' && *_c!='(' && *_c!='{' &&
  353.   *_c!='-' && *_c!='}' && *_c!=')' && *_c!=']' &&
  354.   *_c!='+' && *_c!='*' && *_c!='~' && *_c!='|' )
  355. {
  356. token = Atom;
  357. tokchar = *_c++;
  358. }
  359. else
  360. {
  361. token = tokchar = *_c++;
  362. }
  363. }
  364. /* N F A  B u i l d i n g  R o u t i n e s */
  365. static
  366. ArcPtr
  367. newGraphArc()
  368. {
  369. ArcPtr p;
  370. p = (ArcPtr) calloc(1, sizeof(Arc));
  371. if ( p==NULL ) {fprintf(stderr,"rexpr: out of memoryn"); exit(-1);}
  372. if ( freelist != NULL ) p->track = (ArcPtr) freelist;
  373. freelist = (NodePtr) p;
  374. return p;
  375. }
  376. static
  377. NodePtr
  378. newNode()
  379. {
  380. NodePtr p;
  381. p = (NodePtr) calloc(1, sizeof(Node));
  382. if ( p==NULL ) {fprintf(stderr,"rexpr: out of memoryn"); exit(-1);}
  383. if ( freelist != NULL ) p->track = freelist;
  384. freelist = p;
  385. return p;
  386. }
  387. static
  388. ArcBetweenGraphNodes(i, j, label)
  389. NodePtr i, j;
  390. int label;
  391. {
  392. ArcPtr a;
  393. a = newGraphArc();
  394. if ( i->arcs == NULL ) i->arctail = i->arcs = a;
  395. else {(i->arctail)->next = a; i->arctail = a;}
  396. a->label = label;
  397. a->target = j;
  398. }
  399. static Graph
  400. BuildNFA_atom(label)
  401. int label;
  402. {
  403. Graph g;
  404. g.left = newNode();
  405. g.right = newNode();
  406. ArcBetweenGraphNodes(g.left, g.right, label);
  407. return( g );
  408. }
  409. static Graph
  410. BuildNFA_AB(A, B)
  411. Graph A, B;
  412. {
  413. Graph g;
  414. ArcBetweenGraphNodes(A.right, B.left, Epsilon);
  415. g.left = A.left;
  416. g.right = B.right;
  417. return( g );
  418. }
  419. static Graph
  420. BuildNFA_AorB(A, B)
  421. Graph A, B;
  422. {
  423. Graph g;
  424. g.left = newNode();
  425. ArcBetweenGraphNodes(g.left, A.left, Epsilon);
  426. ArcBetweenGraphNodes(g.left, B.left, Epsilon);
  427. g.right = newNode();
  428. ArcBetweenGraphNodes(A.right, g.right, Epsilon);
  429. ArcBetweenGraphNodes(B.right, g.right, Epsilon);
  430. return( g );
  431. }
  432. static Graph
  433. BuildNFA_set( s )
  434. char *s;
  435. {
  436. Graph g;
  437. if ( s == NULL ) return g;
  438. g.left = newNode();
  439. g.right = newNode();
  440. while ( *s != '' )
  441. {
  442. ArcBetweenGraphNodes(g.left, g.right, *s++);
  443. }
  444. return g;
  445. }
  446. static Graph
  447. BuildNFA_Astar( A )
  448. Graph A;
  449. {
  450. Graph g;
  451. g.left = newNode();
  452. g.right = newNode();
  453. ArcBetweenGraphNodes(g.left, A.left, Epsilon);
  454. ArcBetweenGraphNodes(g.left, g.right, Epsilon);
  455. ArcBetweenGraphNodes(A.right, g.right, Epsilon);
  456. ArcBetweenGraphNodes(A.right, A.left, Epsilon);
  457. return( g );
  458. }
  459. static Graph
  460. BuildNFA_Aplus( A )
  461. Graph A;
  462. {
  463. ArcBetweenGraphNodes(A.right, A.left, Epsilon);
  464. return( A );
  465. }
  466. static Graph
  467. BuildNFA_Aoptional( A )
  468. Graph A;
  469. {
  470. Graph g;
  471. g.left = newNode();
  472. g.right = newNode();
  473. ArcBetweenGraphNodes(g.left, A.left, Epsilon);
  474. ArcBetweenGraphNodes(g.left, g.right, Epsilon);
  475. ArcBetweenGraphNodes(A.right, g.right, Epsilon);
  476. return( g );
  477. }