├── .gitignore ├── ChangeLog ├── LICENSE.txt ├── Makefile ├── README.md ├── README.txt ├── build-mac.sh ├── build-win.cmd ├── examples ├── Makefile ├── accept.c ├── accept.peg ├── accept.ref ├── basic.leg ├── basic.ref ├── bench.bas ├── calc.leg ├── calc.ref ├── dc.c ├── dc.peg ├── dc.ref ├── dcv.c ├── dcv.peg ├── dcv.ref ├── erract.leg ├── erract.ref ├── fibonacci.bas ├── left.c ├── left.peg ├── localleg.leg ├── localleg.ref ├── localpeg.c ├── localpeg.ref ├── rule.c ├── rule.peg ├── rule.ref ├── test.bas ├── test.c ├── test.peg ├── test.ref ├── username.leg ├── wc.leg └── wc.ref ├── leg-mode.el ├── leg.vcxproj ├── leg.vcxproj.filters ├── peg.gyp ├── peg.sln ├── peg.vcxproj ├── peg.vcxproj.filters ├── peg.xcodeproj └── project.pbxproj ├── src ├── compile.c ├── leg.c ├── leg.leg ├── peg.1 ├── peg.c ├── peg.peg ├── peg.peg-c ├── tree.c ├── tree.h └── version.h └── win ├── getopt.c ├── getopt.h ├── libgen.h └── unistd.h /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | leg 3 | peg 4 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2023-11-19 Ian Piumarta 2 | 3 | * src/version.h (PEG_LEVEL): Version is 0.1.20. 4 | 5 | * src/tree.c (makeInline): Inline nodes remember their parent rule. 6 | Replace "$$" in inline actions with "__". 7 | * src/tree.h (struct Inline): Inline nodes remember their parent rule. 8 | 9 | * src/leg.leg (main): Filenames on WIN32 have \ changed to /, keeping 10 | #line directives happy. 11 | (main): Don't print #line directives for headers if nolineFlag is set. 12 | 13 | * src/compile.c (allocateVariables): Separated from defineVariables. 14 | (Node_compile_c_ko): Allocates and sets local variables during parse. 15 | (Rule_compile_c2): Generate yyEnter and yyLeave if rule has variables. 16 | (preamble): Macros yyEnter and yyLeave manage local variable space on 17 | stack during parsing. 18 | 19 | * Makefile (testleg): Quickly tests local changes. 20 | 21 | 2023-03-06 Ian Piumarta 22 | 23 | * src/version.h (PEG_LEVEL): Version 0.1.19. 24 | * src/compile.c: Allow re-entrant parsing. 25 | Macro YYPARSEFROM_R names the function yyparsefrom_r(). 26 | yyDone takes second argument, the yythunkpos at which actions start. 27 | yyparsefrom_r saves and restores thunkpos and val state during recursive parse. 28 | yyparsefrom resets thunkpos, val before recursive parse. 29 | 30 | 2016-07-22 Ian Piumarta 31 | 32 | * src/version.h (PEG_LEVEL): Version 0.1.18. 33 | * src/tree.h: Rule_compile_c takes nolines argument for option -P. 34 | * src/compile.c, src/peg.c, src/leg.leg (main): Add option -P. 35 | Generate #line directives for all actions. 36 | * src/peg.1: Document option -P. 37 | 38 | 2016-07-14 Ian Piumarta 39 | 40 | * src/version.h: 0.1.17 41 | 42 | * src/leg.leg: Remember line numbers for headers and trailer. 43 | Emit #line directives in the generated file. 44 | 45 | 2016-06-25 piumarta 46 | 47 | * src/version.h: 0.1.16 48 | 49 | * src/tree.[ch], src/compile.c, src/leg.leg: Add @-actions. 50 | 51 | * src/peg.1: Explain @-actions. 52 | 53 | * src/peg/peg-c, src/leg.c: Regenerate C source. 54 | 55 | 2013-12-18 piumarta 56 | 57 | * src/version.h: 0.1.15 58 | 59 | * src/compile.c: YY_FREE takes context and pointer as arguments. 60 | 61 | * YYRELEASE: Pass yyctx and pointer to YY_FREE. 62 | 63 | 2013-12-01 Ian Piumarta 64 | 65 | * src/version.h: 0.1.14 66 | 67 | * src/peg.1: Fix several typos and escape backslashes (thanks to 68 | Giulio Paci). 69 | 70 | * LICENSE.txt: Replace "the the" with "the". 71 | 72 | 2013-08-16 Ian Piumarta 73 | 74 | * src/compile.c: Predicate actions can refer to yytext (thanks to 75 | Gregory Pakosz). 76 | 77 | * src/leg.leg: Hexadecimal character escapes are supported by leg 78 | (thanks to Hugo Etchegoyen). 79 | 80 | 2013-07-20 Ian Piumarta 81 | 82 | * src/getopt.c: Use BSD-licensed getopt() in Windows 83 | build. 84 | 85 | * src/compile.c: Verbose mode handles Variable nodes. 86 | 87 | 2013-06-03 Ian Piumarta 88 | 89 | * src/leg.leg, src/compile.c: Add error actions via "~" operator. 90 | 91 | * src/compile.c: Support declaration of local variables at the top 92 | level of semantic actions. Dynamically grow data structures to 93 | remove artificial limits on rule recursion (thanks to Alex 94 | Klinkhamer). Many small changes to better support C++. 95 | 96 | * src/peg.1: Update manual page to describe new features. 97 | 98 | Add build files for Win32 and MacOS thanks to Fyodor Sheremetyev). 99 | 100 | 2012-04-29 Ian Piumarta 101 | 102 | * compile.c: Move global state into a structure to facilitate 103 | reentrant and thread-safe parsers (thanks to Dmitry Lipovoi). 104 | 105 | 2012-03-29 Ian Piumarta 106 | 107 | * leg.leg: Allow nested, matched braces within actions. 108 | 109 | 2011-11-25 Ian Piumarta 110 | 111 | * compile.c: Fix matching of 8-bit chars to allow utf-8 sequences 112 | in matching expressions (thanks to Gregory Pakosz). 113 | 114 | 2011-11-24 Ian Piumarta 115 | 116 | * compile.c: Allow octal escapes in character classes. 117 | 118 | 2011-11-24 Ian Piumarta 119 | 120 | * Makefile: Remove dwarf sym dirs when cleaning. 121 | 122 | * compile.c: Fix size calculation when resizing text 123 | buffers. 124 | 125 | * leg.leg, peg.peg: Backslash can be escaped. 126 | 127 | 2009-08-26 Ian Piumarta 128 | 129 | * leg.leg: Fix match of a single single quote character. 130 | 131 | * examples/basic.leg: Rename getline -> nextline to avoid C 132 | namespace conflict. 133 | 134 | 2007-09-13 Ian Piumarta 135 | 136 | * leg.leg: Allow matched braces inside leg actions. Handle empty 137 | rules. Handle empty grammars. 138 | 139 | 2007-08-31 Ian Piumarta 140 | 141 | * compile.c: Grow buffers while (not if) they are too 142 | small. Remove dependencies on grammar files. Add more basic 143 | examples. 144 | 145 | 2007-05-15 Ian Piumarta 146 | 147 | First public release. 148 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007-2013, Ian Piumarta 2 | All rights reserved. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the 'Software'), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, and/or sell copies of the 8 | Software, and to permit persons to whom the Software is furnished to do so, 9 | provided that the above copyright notice(s) and this permission notice appear 10 | in all copies or substantial portions of the Software. Inclusion of the 11 | above copyright notice(s) and this permission notice in supporting 12 | documentation would be appreciated but is not required. 13 | 14 | THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -g -Wall $(OFLAGS) $(XFLAGS) -Isrc 2 | OFLAGS = -O3 -DNDEBUG 3 | #OFLAGS = -pg 4 | 5 | OBJS = tree.o compile.o 6 | 7 | all : peg leg 8 | 9 | peg : peg.o $(OBJS) 10 | $(CC) $(CFLAGS) -o $@-new peg.o $(OBJS) 11 | mv $@-new $@ 12 | 13 | leg : leg.o $(OBJS) 14 | $(CC) $(CFLAGS) -o $@-new leg.o $(OBJS) 15 | mv $@-new $@ 16 | 17 | testleg : .FORCE 18 | ./leg -o $@.c src/leg.leg 19 | $(CC) $(CFLAGS) -Wno-unused -Wno-array-bounds -o $@ leg.c src/compile.c src/tree.c 20 | ./$@ -o $@.c.c src/leg.leg 21 | diff $@.c $@.c.c 22 | 23 | ROOT = 24 | PREFIX = /usr/local 25 | BINDIR = $(ROOT)$(PREFIX)/bin 26 | MANDIR = $(ROOT)$(PREFIX)/man/man1 27 | 28 | install : $(BINDIR) $(BINDIR)/peg $(BINDIR)/leg $(MANDIR) $(MANDIR)/peg.1 29 | 30 | $(BINDIR) : 31 | mkdir -p $(BINDIR) 32 | 33 | $(BINDIR)/% : % 34 | cp -p $< $@ 35 | strip $@ 36 | 37 | $(MANDIR) : 38 | mkdir -p $(MANDIR) 39 | 40 | $(MANDIR)/% : src/% 41 | cp -p $< $@ 42 | 43 | uninstall : .FORCE 44 | rm -f $(BINDIR)/peg 45 | rm -f $(BINDIR)/leg 46 | rm -f $(MANDIR)/peg.1 47 | 48 | %.o : src/%.c 49 | $(CC) $(CFLAGS) -c -o $@ $< 50 | 51 | peg.o : src/peg.c src/peg.peg-c 52 | 53 | leg.o : src/leg.c 54 | 55 | check : check-peg check-leg 56 | 57 | check-peg : peg.peg-c .FORCE 58 | diff src/peg.peg-c peg.peg-c 59 | 60 | check-leg : leg.c .FORCE 61 | diff src/leg.c leg.c 62 | 63 | peg.peg-c : src/peg.peg peg 64 | ./peg -o $@ $< 65 | 66 | leg.c : src/leg.leg leg 67 | ./leg -o $@ $< 68 | 69 | new : newpeg newleg 70 | 71 | newpeg : peg.peg-c 72 | mv src/peg.peg-c src/peg.peg-c- 73 | mv peg.peg-c src/. 74 | 75 | newleg : leg.c 76 | mv src/leg.c src/leg.c- 77 | mv leg.c src/. 78 | 79 | test examples : peg leg .FORCE 80 | $(SHELL) -ec '(cd examples; $(MAKE))' 81 | 82 | clean : .FORCE 83 | rm -f src/*~ *~ *.o *.peg.[cd] *.leg.[cd] peg.peg-c leg.c 84 | $(SHELL) -ec '(cd examples; $(MAKE) $@)' 85 | 86 | spotless : clean .FORCE 87 | rm -f src/*- 88 | rm -rf build 89 | rm -f peg 90 | rm -f leg 91 | $(SHELL) -ec '(cd examples; $(MAKE) $@)' 92 | 93 | .FORCE : 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # peg/leg — recursive-descent parser generators for C 2 | 3 | `peg` and `leg` are tools for generating recursive-descent parsers: programs that perform pattern matching on 4 | text. They processes a Parsing Expression Grammar (PEG)[Ford 2004] to produce a program that recognises legal sentences of that grammar. 5 | 6 | `peg` processes PEGs written using the original syntax described by Ford. 7 | 8 | `leg` processes PEGs written using slightly different syntax and conventions that are intended to make it an attractive replacement for parsers built with `lex` and `yacc`. 9 | 10 | Unlike `lex` and `yacc`, `peg` and `leg` support unlimited backtracking, provide ordered choice as a means for disambiguation, and can combine scanning (lexical analysis) and parsing (syntactic analysis) into a single activity. 11 | 12 | `peg` is distributed under the MIT license. It will not infect your project with a contagious license disease if you 13 | decide to modify it for your own use. The parser generators that `peg` creates are unencumbered and you are free to use and/or 14 | distribute them any way you like. 15 | 16 | `peg`/`leg` is copyright (c) 2007 by Ian Piumarta. 17 | 18 | ## References 19 | 20 | * `peg`/`leg` manual page: [peg.1.html][1] 21 | 22 | * [Ford 2004] Bryan Ford, [*Parsing Expression Grammars: A Recognition-Based Syntactic Foundation*][2]. ACM SIGPLAN Symposium on Principles of Programming Languages (POPL), 2004. 23 | 24 | [1]: http://piumarta.com/software/peg/peg.1.html "peg/leg manual" 25 | [2]: http://bford.info/pub/lang/peg "Parsing Expression Grammars: A Recognition-Based Syntactic Foundation" 26 | 27 | ## Version history 28 | 29 | * **0.1.20** ([zip](../../archive/0.1.20.zip), [tar.gz](../../archive/0.1.20.tar.gz)) — 2019-11-19 30 | Experimental support for variables and semantic values in ‘inline actions’ executed during recognition (separate from the parser actions that are run after the input is fully recognised). 31 | Don't print `#line` directives for headers if `-P` was given and pathnames on WIN32 have `\` changed to `/` to keep `#line` directives happy (thanks to Ben Hines for the problem report). 32 | * **0.1.19** ([zip](../../archive/0.1.19.zip), [tar.gz](../../archive/0.1.19.tar.gz)) — 2019-03-06 33 | Experimental support for re-entrant parsing through `yyparsefrom_r()`. 34 | * **0.1.18** ([zip](../../archive/0.1.18.zip), [tar.gz](../../archive/0.1.18.tar.gz)) — 2016-07-22 35 | Add `-P` option to disable `#line` directives. 36 | Emit `#line` directives for all actions. 37 | * **0.1.17** ([zip](../../archive/0.1.17.zip), [tar.gz](../../archive/0.1.17.tar.gz)) — 2016-07-14 38 | Emit `#line` directives for header and trailer in the generated source file. 39 | * **0.1.16** ([zip](../../archive/0.1.16.zip), [tar.gz](../../archive/0.1.16.tar.gz)) — 2016-06-25 40 | Add `@{...}` actions that are performed during matching. 41 | * **0.1.15** ([zip](../../archive/0.1.15.zip), [tar.gz](../../archive/0.1.15.tar.gz)) — 2013-12-17 42 | Calls to `YY_FREE` fixed (thanks to Andrew Dunham). 43 | * **0.1.14** ([zip](../../archive/0.1.14.zip), [tar.gz](../../archive/0.1.14.tar.gz)) — 2013-12-01 44 | Documentation typos fixed (thanks to Giulio Paci). 45 | * **0.1.13** ([zip](../../archive/0.1.13.zip), [tar.gz](../../archive/0.1.13.tar.gz)) — 2013-08-16 46 | Predicate actions can refer to `yytext` (thanks to Grégory Pakosz). 47 | Hexadecimal character escapes are supported by `leg` (thanks to Hugo Etchegoyen). 48 | * **0.1.12** ([zip](../../archive/0.1.12.zip), [tar.gz](../../archive/0.1.12.tar.gz)) — 2013-07-20 49 | Use BSD-licensed `getopt()` in Windows build. 50 | Verbose mode handles Variable nodes. 51 | * **0.1.11** ([zip](../../archive/0.1.11.zip), [tar.gz](../../archive/0.1.11.tar.gz)) — 2013-06-03 52 | Add error actions via `"~"` operator. 53 | Support declaration of local variables at the top level of semantic actions. 54 | Dynamically grow data structures to remove artificial limits on rule recursion (thanks to Alex Klinkhamer). 55 | Many small changes to better support C++. 56 | Add build files for Win32 and MacOS (thanks to Fyodor Sheremetyev). 57 | Update manual page to describe new features. 58 | * **0.1.10** — missing in upstream 59 | * **0.1.9** ([zip](../../archive/0.1.9.zip), [tar.gz](../../archive/0.1.9.tar.gz)) — 2012-04-29 60 | Move global state into a structure to facilitate reentrant and thread-safe parsers (thanks to Dmitry Lipovoi). 61 | * **0.1.8** ([zip](../../archive/0.1.8.zip), [tar.gz](../../archive/0.1.8.tar.gz)) — 2012-03-29 62 | Allow nested, matched braces within actions. 63 | * **0.1.7** ([zip](../../archive/0.1.7.zip), [tar.gz](../../archive/0.1.7.tar.gz)) — 2011-11-25 64 | Fix matching of 8-bit chars to allow utf-8 sequences in matching expressions (thanks to Grégory Pakosz). 65 | * **0.1.6** ([zip](../../archive/0.1.6.zip), [tar.gz](../../archive/0.1.6.tar.gz)) — 2011-11-24 66 | Allow octal escapes in character classes. 67 | * **0.1.5** ([zip](../../archive/0.1.5.zip), [tar.gz](../../archive/0.1.5.tar.gz)) — 2011-11-24 68 | Remove dwarf sym dirs when cleaning. 69 | Fix size calculation when resizing text buffers. 70 | Backslash can be escaped. 71 | * **0.1.4** ([zip](../../archive/0.1.4.zip), [tar.gz](../../archive/0.1.4.tar.gz)) — 2009-08-26 72 | Fix match of a single single quote character. 73 | Rename `getline` -> `nextline` to avoid C namespace conflict. 74 | * **0.1.3** ([zip](../../archive/0.1.3.zip), [tar.gz](../../archive/0.1.3.tar.gz)) — 2007-09-13 75 | Allow matched braces inside `leg` actions. 76 | Handle empty rules. 77 | Handle empty grammars. 78 | * **0.1.2** ([zip](../../archive/0.1.2.zip), [tar.gz](../../archive/0.1.2.tar.gz)) — 2007-08-31 79 | Grow buffers while (not if) they are too small. 80 | Remove dependencies on grammar files. 81 | Add more basic examples. 82 | * **0.1.1** ([zip](../../archive/0.1.1.zip), [tar.gz](../../archive/0.1.1.tar.gz)) — 2007-05-15 83 | First public release. 84 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | Building on a Unix-like system 2 | ------------------------------ 3 | 4 | Type 'make' or 'make test'. 5 | 6 | The latter builds all the examples and runs them, comparing their 7 | output with the expected output. 8 | 9 | Type 'make install' to install the binaries and manual page under 10 | /usr/local. (Type 'make uninstall' to remove them.) You may have to 11 | do this using 'sudo' or while logged in as root. 12 | 13 | Edit 'Makefile' to change the way things are built and/or the places 14 | where things are installed. 15 | 16 | 17 | Building on MacOS X 18 | ------------------- 19 | 20 | Run the 'build-mac.sh' script from a terminal or by double-clicking on 21 | it in the Finder. 22 | 23 | You will need Xcode. The provided project is known to work with Xcode 24 | versions 3.2.6 and 4.3.2. 25 | 26 | Modify build-mac.sh and/or peg.xcodeproj to change the way things are 27 | built. 28 | 29 | 30 | Building on Windows 31 | ------------------- 32 | 33 | Run the 'build-win.cmd' script. 34 | 35 | You will need Visual Studio 2010 Express. 36 | 37 | Modify build-win.cmd, leg.vcxproj, leg.vcxproj.filters, peg.gyp, 38 | peg.sln, peg.vcxproj and/or peg.vcxproj.filters to change the way 39 | things are built. 40 | 41 | Local implementations of getopt() and basename() are provided in the 42 | 'win' directory. 43 | -------------------------------------------------------------------------------- /build-mac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | xcodebuild -project peg.xcodeproj -configuration Release 4 | 5 | cp build/Release/peg ./ 6 | cp build/Release/leg ./ 7 | -------------------------------------------------------------------------------- /build-win.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | call "%VS100COMNTOOLS%vsvars32.bat" 3 | msbuild peg.sln /p:Configuration=Release 4 | 5 | xcopy /Y /D Release\*.exe .\ 6 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | EXAMPLES = test rule accept wc dc dcv calc basic localpeg localleg erract 2 | 3 | CFLAGS = -g -O3 4 | 5 | DIFF = diff 6 | TEE = cat > 7 | 8 | all : $(EXAMPLES) 9 | 10 | test : .FORCE 11 | ../peg -o test.peg.c test.peg 12 | $(CC) $(CFLAGS) -o test test.c 13 | echo 'ab.ac.ad.ae.afg.afh.afg.afh.afi.afj.' | ./$@ | $(TEE) $@.out 14 | $(DIFF) $@.ref $@.out 15 | rm -f $@.out 16 | @echo 17 | 18 | rule : .FORCE 19 | ../peg -o rule.peg.c rule.peg 20 | $(CC) $(CFLAGS) -o rule rule.c 21 | echo 'abcbcdabcbcdabcbcdabcbcd' | ./$@ | $(TEE) $@.out 22 | $(DIFF) $@.ref $@.out 23 | rm -f $@.out 24 | @echo 25 | 26 | accept : .FORCE 27 | ../peg -o accept.peg.c accept.peg 28 | $(CC) $(CFLAGS) -o accept accept.c 29 | echo 'abcbcdabcbcdabcbcdabcbcd' | ./$@ | $(TEE) $@.out 30 | $(DIFF) $@.ref $@.out 31 | rm -f $@.out 32 | @echo 33 | 34 | wc : .FORCE 35 | ../leg -o wc.leg.c wc.leg 36 | $(CC) $(CFLAGS) -o wc wc.leg.c 37 | cat wc.leg | ./$@ | $(TEE) $@.out 38 | $(DIFF) $@.ref $@.out 39 | rm -f $@.out 40 | @echo 41 | 42 | dc : .FORCE 43 | ../peg -o dc.peg.c dc.peg 44 | $(CC) $(CFLAGS) -o dc dc.c 45 | echo ' 2 *3 *(3+ 4) ' | ./dc | $(TEE) $@.out 46 | $(DIFF) $@.ref $@.out 47 | rm -f $@.out 48 | @echo 49 | 50 | dcv : .FORCE 51 | ../peg -o dcv.peg.c dcv.peg 52 | $(CC) $(CFLAGS) -o dcv dcv.c 53 | echo 'a = 6; b = 7; a * b' | ./dcv | $(TEE) $@.out 54 | $(DIFF) $@.ref $@.out 55 | rm -f $@.out 56 | @echo 57 | 58 | calc : .FORCE 59 | ../leg -o calc.leg.c calc.leg 60 | $(CC) $(CFLAGS) -o calc calc.leg.c 61 | echo 'a = 6; b = 7; a * b' | ./calc | $(TEE) $@.out 62 | $(DIFF) $@.ref $@.out 63 | rm -f $@.out 64 | @echo 65 | 66 | basic : .FORCE 67 | ../leg -o basic.leg.c basic.leg 68 | $(CC) $(CFLAGS) -o basic basic.leg.c 69 | ( echo 'load "test"'; echo "run" ) | ./basic | $(TEE) $@.out 70 | $(DIFF) $@.ref $@.out 71 | rm -f $@.out 72 | @echo 73 | 74 | localpeg : .FORCE 75 | ../peg -o test.peg.c test.peg 76 | $(CC) $(CFLAGS) -o localpeg localpeg.c 77 | echo 'ab.ac.ad.ae.afg.afh.afg.afh.afi.afj.' | ./$@ | $(TEE) $@.out 78 | $(DIFF) $@.ref $@.out 79 | rm -f $@.out 80 | @echo 81 | 82 | localleg : .FORCE 83 | ../leg -o localleg.leg.c localleg.leg 84 | $(CC) $(CFLAGS) -o localleg localleg.leg.c 85 | ./$@ < localleg.leg | $(TEE) $@.out 86 | $(DIFF) $@.ref $@.out 87 | rm -f $@.out 88 | @echo 89 | 90 | erract : .FORCE 91 | ../leg -o erract.leg.c erract.leg 92 | $(CC) $(CFLAGS) -o erract erract.leg.c 93 | echo '6*9' | ./$@ | $(TEE) $@.out 94 | $(DIFF) $@.ref $@.out 95 | rm -f $@.out 96 | @echo 97 | 98 | clean : .FORCE 99 | rm -f *~ *.o *.[pl]eg.[cd] $(EXAMPLES) 100 | rm -rf *.dSYM 101 | 102 | spotless : clean 103 | 104 | .FORCE : 105 | -------------------------------------------------------------------------------- /examples/accept.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "accept.peg.c" 5 | 6 | int main() 7 | { 8 | while (yyparse()); 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /examples/accept.peg: -------------------------------------------------------------------------------- 1 | start <- abcd+ 2 | 3 | abcd <- 'a' { printf("A %d\n", yypos); } bc { printf("ABC %d\n", yypos); } &{YYACCEPT} 4 | / 'b' { printf("B %d\n", yypos); } cd { printf("BCD %d\n", yypos); } &{YYACCEPT} 5 | 6 | bc <- 'b' { printf("B %d\n", yypos); } 'c' { printf("C %d\n", yypos); } 7 | 8 | cd <- 'c' { printf("C %d\n", yypos); } 'd' { printf("D %d\n", yypos); } 9 | -------------------------------------------------------------------------------- /examples/accept.ref: -------------------------------------------------------------------------------- 1 | A 3 2 | B 3 3 | C 3 4 | ABC 3 5 | B 3 6 | C 3 7 | D 3 8 | BCD 3 9 | A 3 10 | B 3 11 | C 3 12 | ABC 3 13 | B 3 14 | C 3 15 | D 3 16 | BCD 3 17 | A 3 18 | B 3 19 | C 3 20 | ABC 3 21 | B 3 22 | C 3 23 | D 3 24 | BCD 3 25 | A 3 26 | B 3 27 | C 3 28 | ABC 3 29 | B 3 30 | C 3 31 | D 3 32 | BCD 3 33 | -------------------------------------------------------------------------------- /examples/basic.leg: -------------------------------------------------------------------------------- 1 | # A 'syntax-directed interpreter' (all execution is a side-effect of parsing). 2 | # Inspired by Dennis Allison's original Tiny BASIC grammar, circa 1975. 3 | # 4 | # Copyright (c) 2007 by Ian Piumarta 5 | # All rights reserved. 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a 8 | # copy of this software and associated documentation files (the 'Software'), 9 | # to deal in the Software without restriction, including without limitation 10 | # the rights to use, copy, modify, merge, publish, distribute, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, provided that the above copyright notice(s) and this 13 | # permission notice appear in all copies of the Software. Acknowledgement 14 | # of the use of this Software in supporting documentation would be 15 | # appreciated but is not required. 16 | # 17 | # THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. 18 | # 19 | # Last edited: 2012-04-29 15:14:06 by piumarta on emilia 20 | 21 | %{ 22 | # include 23 | 24 | typedef struct line line; 25 | 26 | struct line 27 | { 28 | int number; 29 | int length; 30 | char *text; 31 | }; 32 | 33 | line *lines= 0; 34 | int numLines= 0; 35 | int pc= -1, epc= -1; 36 | int batch= 0; 37 | 38 | int nextline(char *buf, int max); 39 | 40 | # define min(x, y) ((x) < (y) ? (x) : (y)) 41 | 42 | # define YY_INPUT(buf, result, max_size) \ 43 | { \ 44 | if ((pc >= 0) && (pc < numLines)) \ 45 | { \ 46 | line *linep= lines+pc++; \ 47 | result= min(max_size, linep->length); \ 48 | memcpy(buf, linep->text, result); \ 49 | } \ 50 | else \ 51 | result= nextline(buf, max_size); \ 52 | } 53 | 54 | union value { 55 | int number; 56 | char *string; 57 | int (*binop)(int lhs, int rhs); 58 | }; 59 | 60 | # define YYSTYPE union value 61 | 62 | int variables[26]; 63 | 64 | void accept(int number, char *line); 65 | 66 | void save(char *name); 67 | void load(char *name); 68 | void type(char *name); 69 | 70 | int lessThan(int lhs, int rhs) { return lhs < rhs; } 71 | int lessEqual(int lhs, int rhs) { return lhs <= rhs; } 72 | int notEqual(int lhs, int rhs) { return lhs != rhs; } 73 | int equalTo(int lhs, int rhs) { return lhs == rhs; } 74 | int greaterEqual(int lhs, int rhs) { return lhs >= rhs; } 75 | int greaterThan(int lhs, int rhs) { return lhs > rhs; } 76 | 77 | int input(void); 78 | 79 | int stack[1024], sp= 0; 80 | 81 | char *help; 82 | 83 | void error(char *fmt, ...); 84 | int findLine(int n, int create); 85 | %} 86 | 87 | line = - s:statement CR 88 | | - n:number < ( !CR . )* CR > { accept(n.number, yytext); } 89 | | - CR 90 | | - < ( !CR . )* CR > { epc= pc; error("syntax error"); } 91 | | - !. { exit(0); } 92 | 93 | statement = 'print'- expr-list 94 | | 'if'- e1:expression r:relop e2:expression { if (!r.binop(e1.number, e2.number)) yythunkpos= 0; } 95 | 'then'- statement 96 | | 'goto'- e:expression { epc= pc; if ((pc= findLine(e.number, 0)) < 0) error("no such line"); } 97 | | 'input'- var-list 98 | | 'let'- v:var EQUAL e:expression { variables[v.number]= e.number; } 99 | | 'gosub'- e:expression { epc= pc; if (sp < 1024) stack[sp++]= pc, pc= findLine(e.number, 0); else error("too many gosubs"); 100 | if (pc < 0) error("no such line"); } 101 | | 'return'- { epc= pc; if ((pc= sp ? stack[--sp] : -1) < 0) error("no gosub"); } 102 | | 'clear'- { while (numLines) accept(lines->number, "\n"); } 103 | | 'list'- { int i; for (i= 0; i < numLines; ++i) printf("%5d %s", lines[i].number, lines[i].text); } 104 | | 'run'- s:string { load(s.string); pc= 0; } 105 | | 'run'- { pc= 0; } 106 | | 'end'- { pc= -1; if (batch) exit(0); } 107 | | 'rem'- ( !CR . )* 108 | | ('bye'|'quit'|'exit')- { exit(0); } 109 | | 'save'- s:string { save(s.string); } 110 | | 'load'- s:string { load(s.string); } 111 | | 'type'- s:string { type(s.string); } 112 | | 'dir'- { system("ls *.bas"); } 113 | | 'help'- { fprintf(stderr, "%s", help); } 114 | 115 | expr-list = ( e:string { printf("%s", e.string); } 116 | | e:expression { printf("%d", e.number); } 117 | )? ( COMMA ( e:string { printf("%s", e.string); } 118 | | e:expression { printf("%d", e.number); } 119 | ) 120 | )* ( COMMA 121 | | !COMMA { printf("\n"); } 122 | ) 123 | 124 | var-list = v:var { variables[v.number]= input(); } 125 | ( COMMA v:var { variables[v.number]= input(); } 126 | )* 127 | 128 | expression = ( PLUS? l:term 129 | | MINUS l:term { l.number = -l.number } 130 | ) ( PLUS r:term { l.number += r.number } 131 | | MINUS r:term { l.number -= r.number } 132 | )* { $$.number = l.number } 133 | 134 | term = l:factor ( STAR r:factor { l.number *= r.number } 135 | | SLASH r:factor { l.number /= r.number } 136 | )* { $$.number = l.number } 137 | 138 | factor = v:var { $$.number = variables[v.number] } 139 | | n:number 140 | | OPEN expression CLOSE 141 | 142 | var = < [a-z] > - { $$.number = yytext[0] - 'a' } 143 | 144 | number = < digit+ > - { $$.number = atoi(yytext); } 145 | 146 | digit = [0-9] 147 | 148 | string = '"' < [^\"]* > '"' - { $$.string = yytext; } 149 | 150 | relop = '<=' - { $$.binop= lessEqual; } 151 | | '<>' - { $$.binop= notEqual; } 152 | | '<' - { $$.binop= lessThan; } 153 | | '>=' - { $$.binop= greaterEqual; } 154 | | '>' - { $$.binop= greaterThan; } 155 | | '=' - { $$.binop= equalTo; } 156 | 157 | EQUAL = '=' - CLOSE = ')' - OPEN = '(' - 158 | SLASH = '/' - STAR = '*' - MINUS = '-' - 159 | PLUS = '+' - COMMA = ',' - 160 | 161 | - = [ \t]* 162 | 163 | CR = '\n' | '\r' | '\r\n' 164 | 165 | %% 166 | 167 | #include 168 | #include 169 | 170 | char *help= 171 | "print | [, | ...] [,]\n" 172 | "if <|<=|<>|=|>=|> then \n" 173 | "input [, ...] let = \n" 174 | "goto gosub \n" 175 | "end return\n" 176 | "list clear\n" 177 | "run [\"filename\"] rem \n" 178 | "dir type \"filename\"\n" 179 | "save \"filename\" load \"filename\"\n" 180 | "bye|quit|exit help\n" 181 | ; 182 | 183 | void error(char *fmt, ...) 184 | { 185 | va_list ap; 186 | va_start(ap, fmt); 187 | if (epc > 0) 188 | fprintf(stderr, "\nline %d: %s", lines[epc-1].number, lines[epc-1].text); 189 | else 190 | fprintf(stderr, "\n"); 191 | vfprintf(stderr, fmt, ap); 192 | fprintf(stderr, "\n"); 193 | va_end(ap); 194 | epc= pc= -1; 195 | } 196 | 197 | #ifdef USE_READLINE 198 | # include 199 | # include 200 | #endif 201 | 202 | int nextline(char *buf, int max) 203 | { 204 | pc= -1; 205 | if (batch) exit(0); 206 | if (isatty(fileno(stdin))) 207 | { 208 | # ifdef USE_READLINE 209 | char *line= readline(">"); 210 | if (line) 211 | { 212 | int len= strlen(line); 213 | if (len >= max) len= max - 1; 214 | strncpy(buf, line, len); 215 | (buf)[len]= '\n'; 216 | add_history(line); 217 | free(line); 218 | return len + 1; 219 | } 220 | else 221 | { 222 | printf("\n"); 223 | return 0; 224 | } 225 | # endif 226 | putchar('>'); 227 | fflush(stdout); 228 | } 229 | return fgets(buf, max, stdin) ? strlen(buf) : 0; 230 | } 231 | 232 | int maxLines= 0; 233 | 234 | int findLine(int n, int create) 235 | { 236 | int lo= 0, hi= numLines - 1; 237 | while (lo <= hi) 238 | { 239 | int mid= (lo + hi) / 2, lno= lines[mid].number; 240 | if (lno > n) 241 | hi= mid - 1; 242 | else if (lno < n) 243 | lo= mid + 1; 244 | else 245 | return mid; 246 | } 247 | if (create) 248 | { 249 | if (numLines == maxLines) 250 | { 251 | maxLines *= 2; 252 | lines= realloc(lines, sizeof(line) * maxLines); 253 | } 254 | if (lo < numLines) 255 | memmove(lines + lo + 1, lines + lo, sizeof(line) * (numLines - lo)); 256 | ++numLines; 257 | lines[lo].number= n; 258 | lines[lo].text= 0; 259 | return lo; 260 | } 261 | return -1; 262 | } 263 | 264 | void accept(int n, char *s) 265 | { 266 | if (s[0] < 32) /* delete */ 267 | { 268 | int lno= findLine(n, 0); 269 | if (lno >= 0) 270 | { 271 | if (lno < numLines - 1) 272 | memmove(lines + lno, lines + lno + 1, sizeof(line) * (numLines - lno - 1)); 273 | --numLines; 274 | } 275 | } 276 | else /* insert */ 277 | { 278 | int lno= findLine(n, 1); 279 | if (lines[lno].text) free(lines[lno].text); 280 | lines[lno].length= strlen(s); 281 | lines[lno].text= strdup(s); 282 | } 283 | } 284 | 285 | char *extend(char *name) 286 | { 287 | static char path[1024]; 288 | int len= strlen(name); 289 | sprintf(path, "%s%s", name, (((len > 4) && !strcasecmp(".bas", name + len - 4)) ? "" : ".bas")); 290 | return path; 291 | } 292 | 293 | void save(char *name) 294 | { 295 | FILE *f= fopen(name= extend(name), "w"); 296 | if (!f) 297 | perror(name); 298 | else 299 | { 300 | int i; 301 | for (i= 0; i < numLines; ++i) 302 | fprintf(f, "%d %s", lines[i].number, lines[i].text); 303 | fclose(f); 304 | } 305 | } 306 | 307 | void load(char *name) 308 | { 309 | FILE *f= fopen(name= extend(name), "r"); 310 | if (!f) 311 | perror(name); 312 | else 313 | { 314 | int lineNumber; 315 | char lineText[1024]; 316 | while ((1 == fscanf(f, " %d ", &lineNumber)) && fgets(lineText, sizeof(lineText), f)) 317 | accept(lineNumber, lineText); 318 | fclose(f); 319 | } 320 | } 321 | 322 | void type(char *name) 323 | { 324 | FILE *f= fopen(name= extend(name), "r"); 325 | if (!f) 326 | perror(name); 327 | else 328 | { 329 | int c, d; 330 | while ((c= getc(f)) >= 0) 331 | putchar(d= c); 332 | fclose(f); 333 | if ('\n' != d && '\r' != d) putchar('\n'); 334 | } 335 | } 336 | 337 | int input(void) 338 | { 339 | char line[32]; 340 | fgets(line, sizeof(line), stdin); 341 | return atoi(line); 342 | } 343 | 344 | int main(int argc, char **argv) 345 | { 346 | lines= malloc(sizeof(line) * (maxLines= 32)); 347 | numLines= 0; 348 | 349 | if (argc > 1) 350 | { 351 | batch= 1; 352 | while (argc-- > 1) 353 | load(*++argv); 354 | pc= 0; 355 | } 356 | 357 | while (!feof(stdin)) 358 | yyparse(); 359 | 360 | return 0; 361 | } 362 | -------------------------------------------------------------------------------- /examples/basic.ref: -------------------------------------------------------------------------------- 1 | 1 2 | 2 4 3 | 3 6 9 4 | 4 8 12 16 5 | 5 10 15 20 25 6 | 6 12 18 24 30 36 7 | 7 14 21 28 35 42 49 8 | 8 16 24 32 40 48 56 64 9 | 9 18 27 36 45 54 63 72 81 10 | 10 20 30 40 50 60 70 80 90 100 11 | -------------------------------------------------------------------------------- /examples/bench.bas: -------------------------------------------------------------------------------- 1 | 100 let n=100000 2 | 120 let m=0 3 | 110 let s=0 4 | 130 let m=m+1 5 | 140 let s=s+m 6 | 150 if m 3 | int vars[26]; 4 | %} 5 | 6 | Stmt = - e:Expr EOL { printf("%d\n", e); } 7 | | ( !EOL . )* EOL { printf("error\n"); } 8 | 9 | Expr = i:ID ASSIGN s:Sum { $$= vars[i]= s; } 10 | | s:Sum { $$= s; } 11 | 12 | Sum = l:Product 13 | ( PLUS r:Product { l += r; } 14 | | MINUS r:Product { l -= r; } 15 | )* { $$= l; } 16 | 17 | Product = l:Value 18 | ( TIMES r:Value { l *= r; } 19 | | DIVIDE r:Value { l /= r; } 20 | )* { $$= l; } 21 | 22 | Value = i:NUMBER { $$= atoi(yytext); } 23 | | i:ID !ASSIGN { $$= vars[i]; } 24 | | OPEN i:Expr CLOSE { $$= i; } 25 | 26 | NUMBER = < [0-9]+ > - { $$= atoi(yytext); } 27 | ID = < [a-z] > - { $$= yytext[0] - 'a'; } 28 | ASSIGN = '=' - 29 | PLUS = '+' - 30 | MINUS = '-' - 31 | TIMES = '*' - 32 | DIVIDE = '/' - 33 | OPEN = '(' - 34 | CLOSE = ')' - 35 | 36 | - = [ \t]* 37 | EOL = '\n' | '\r\n' | '\r' | ';' 38 | 39 | %% 40 | 41 | int main() 42 | { 43 | while (yyparse()); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /examples/calc.ref: -------------------------------------------------------------------------------- 1 | 6 2 | 7 3 | 42 4 | -------------------------------------------------------------------------------- /examples/dc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int stack[1024]; 5 | int stackp= -1; 6 | 7 | int push(int n) { return stack[++stackp]= n; } 8 | int pop(void) { return stack[stackp--]; } 9 | 10 | #include "dc.peg.c" 11 | 12 | int main() 13 | { 14 | while (yyparse()); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /examples/dc.peg: -------------------------------------------------------------------------------- 1 | # Grammar 2 | 3 | Expr <- SPACE Sum EOL { printf("%d\n", pop()); } 4 | / (!EOL .)* EOL { printf("error\n"); } 5 | 6 | Sum <- Product ( PLUS Product { int r= pop(), l= pop(); push(l + r); } 7 | / MINUS Product { int r= pop(), l= pop(); push(l - r); } 8 | )* 9 | 10 | Product <- Value ( TIMES Value { int r= pop(), l= pop(); push(l * r); } 11 | / DIVIDE Value { int r= pop(), l= pop(); push(l / r); } 12 | )* 13 | 14 | Value <- NUMBER { push(atoi(yytext)); } 15 | / OPEN Sum CLOSE 16 | 17 | # Lexemes 18 | 19 | NUMBER <- < [0-9]+ > SPACE 20 | PLUS <- '+' SPACE 21 | MINUS <- '-' SPACE 22 | TIMES <- '*' SPACE 23 | DIVIDE <- '/' SPACE 24 | OPEN <- '(' SPACE 25 | CLOSE <- ')' SPACE 26 | SPACE <- [ \t]* 27 | EOL <- '\n' / '\r\n' / '\r' 28 | -------------------------------------------------------------------------------- /examples/dc.ref: -------------------------------------------------------------------------------- 1 | 42 2 | -------------------------------------------------------------------------------- /examples/dcv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int stack[1024]; 5 | int stackp= -1; 6 | int var= 0; 7 | int vars[26]; 8 | 9 | int push(int n) { return stack[++stackp]= n; } 10 | int pop(void) { return stack[stackp--]; } 11 | int top(void) { return stack[stackp]; } 12 | 13 | #include "dcv.peg.c" 14 | 15 | int main() 16 | { 17 | while (yyparse()); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /examples/dcv.peg: -------------------------------------------------------------------------------- 1 | # Grammar 2 | 3 | Stmt <- SPACE Expr EOL { printf("%d\n", pop()); } 4 | / (!EOL .)* EOL { printf("error\n"); } 5 | 6 | Expr <- ID { var= yytext[0] } ASSIGN Sum { vars[var - 'a']= top(); } 7 | / Sum 8 | 9 | Sum <- Product ( PLUS Product { int r= pop(), l= pop(); push(l + r); } 10 | / MINUS Product { int r= pop(), l= pop(); push(l - r); } 11 | )* 12 | 13 | Product <- Value ( TIMES Value { int r= pop(), l= pop(); push(l * r); } 14 | / DIVIDE Value { int r= pop(), l= pop(); push(l / r); } 15 | )* 16 | 17 | Value <- NUMBER { push(atoi(yytext)); } 18 | / < ID > !ASSIGN { push(vars[yytext[0] - 'a']); } 19 | / OPEN Expr CLOSE 20 | 21 | # Lexemes 22 | 23 | NUMBER <- < [0-9]+ > SPACE 24 | ID <- < [a-z] > SPACE 25 | ASSIGN <- '=' SPACE 26 | PLUS <- '+' SPACE 27 | MINUS <- '-' SPACE 28 | TIMES <- '*' SPACE 29 | DIVIDE <- '/' SPACE 30 | OPEN <- '(' SPACE 31 | CLOSE <- ')' SPACE 32 | 33 | SPACE <- [ \t]* 34 | EOL <- '\n' / '\r\n' / '\r' / ';' 35 | -------------------------------------------------------------------------------- /examples/dcv.ref: -------------------------------------------------------------------------------- 1 | 6 2 | 7 3 | 42 4 | -------------------------------------------------------------------------------- /examples/erract.leg: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | Expr = a:NUMBER PLUS ~{ printf("fail at PLUS\n") } b:NUMBER { printf("got addition\n"); } 6 | | ( a:NUMBER MINUS b:NUMBER { printf("got subtraction\n"); } ) ~{ printf("fail at subtraction\n") } 7 | | a:NUMBER TIMES b:NUMBER { printf("got multiplication\n"); } 8 | | a:NUMBER DIVIDE b:NUMBER { printf("got division\n"); } 9 | 10 | NUMBER = < [0-9]+ > - { $$= atoi(yytext); } 11 | PLUS = '+' - 12 | MINUS = '-' - 13 | TIMES = '*' - 14 | DIVIDE = '/' - 15 | 16 | - = (SPACE | EOL)* 17 | SPACE = [ \t] 18 | EOL = '\n' | '\r\n' | '\r' | ';' 19 | 20 | %% 21 | 22 | int main() 23 | { 24 | while (yyparse()); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /examples/erract.ref: -------------------------------------------------------------------------------- 1 | fail at PLUS 2 | fail at subtraction 3 | got multiplication 4 | fail at subtraction 5 | -------------------------------------------------------------------------------- /examples/fibonacci.bas: -------------------------------------------------------------------------------- 1 | 100 let n=32 2 | 110 gosub 200 3 | 120 print "fibonacci(",n,") = ", m 4 | 130 end 5 | 6 | 200 let c=n 7 | 210 let b=1 8 | 220 if c<2 then goto 400 9 | 230 let c=c-1 10 | 240 let a=1 11 | 300 let c=c-1 12 | 310 let d=a+b 13 | 320 let a=b 14 | 330 let b=d+1 15 | 340 if c<>0 then goto 300 16 | 400 let m=b 17 | 410 return 18 | -------------------------------------------------------------------------------- /examples/left.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define YY_INPUT(buf, result, max) \ 4 | { \ 5 | int c= getchar(); \ 6 | result= (EOF == c) ? 0 : (*(buf)= c, 1); \ 7 | if (EOF != c) printf("<%c>\n", c); \ 8 | } 9 | 10 | #include "left.peg.c" 11 | 12 | int main() 13 | { 14 | printf(yyparse() ? "success\n" : "failure\n"); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /examples/left.peg: -------------------------------------------------------------------------------- 1 | # Grammar 2 | 3 | S <- (S 'a' / 'a') !'a' 4 | -------------------------------------------------------------------------------- /examples/localleg.leg: -------------------------------------------------------------------------------- 1 | %{ 2 | #define YY_CTX_LOCAL 1 3 | #define YY_CTX_MEMBERS \ 4 | int count; 5 | %} 6 | 7 | Char = ('\n' | '\r\n' | '\r') { yy->count++ } 8 | | . 9 | 10 | %% 11 | 12 | #include 13 | #include 14 | 15 | int main() 16 | { 17 | yycontext yy; 18 | memset(&yy, 0, sizeof(yy)); 19 | while (yyparse(&yy)) 20 | ; 21 | printf("%d newlines\n", yy.count); 22 | yyrelease(&yy); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /examples/localleg.ref: -------------------------------------------------------------------------------- 1 | 24 newlines 2 | -------------------------------------------------------------------------------- /examples/localpeg.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define YY_CTX_LOCAL 4 | 5 | #include "test.peg.c" 6 | 7 | int main() 8 | { 9 | yycontext ctx; 10 | memset(&ctx, 0, sizeof(yycontext)); 11 | while (yyparse(&ctx)); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /examples/localpeg.ref: -------------------------------------------------------------------------------- 1 | a1 ab1 . 2 | a2 ac2 . 3 | a3 ad3 . 4 | a3 ae3 . 5 | a4 af4 afg4 . 6 | a4 af5 afh5 . 7 | a4 af4 afg4 . 8 | a4 af5 afh5 . 9 | af6 afi6 a6 . 10 | af6 af7 afj7 a6 . 11 | -------------------------------------------------------------------------------- /examples/rule.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "rule.peg.c" 5 | 6 | int main() 7 | { 8 | while (yyparse()); 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /examples/rule.peg: -------------------------------------------------------------------------------- 1 | start <- abcd+ 2 | 3 | abcd <- 'a' { printf("A %d\n", yypos); } bc { printf("ABC %d\n", yypos); } 4 | / 'b' { printf("B %d\n", yypos); } cd { printf("BCD %d\n", yypos); } 5 | 6 | bc <- 'b' { printf("B %d\n", yypos); } 'c' { printf("C %d\n", yypos); } 7 | 8 | cd <- 'c' { printf("C %d\n", yypos); } 'd' { printf("D %d\n", yypos); } 9 | -------------------------------------------------------------------------------- /examples/rule.ref: -------------------------------------------------------------------------------- 1 | A 24 2 | B 24 3 | C 24 4 | ABC 24 5 | B 24 6 | C 24 7 | D 24 8 | BCD 24 9 | A 24 10 | B 24 11 | C 24 12 | ABC 24 13 | B 24 14 | C 24 15 | D 24 16 | BCD 24 17 | A 24 18 | B 24 19 | C 24 20 | ABC 24 21 | B 24 22 | C 24 23 | D 24 24 | BCD 24 25 | A 24 26 | B 24 27 | C 24 28 | ABC 24 29 | B 24 30 | C 24 31 | D 24 32 | BCD 24 33 | -------------------------------------------------------------------------------- /examples/test.bas: -------------------------------------------------------------------------------- 1 | 10 let i=1 2 | 20 gosub 100 3 | 30 let i=i+1 4 | 40 if i<=10 then goto 20 5 | 50 end 6 | 7 | 100 let j=1 8 | 110 print " ", i*j, 9 | 120 let j=j+1 10 | 130 if j<=i then goto 110 11 | 140 print 12 | 150 return 13 | -------------------------------------------------------------------------------- /examples/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test.peg.c" 3 | 4 | int main() 5 | { 6 | while (yyparse()); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /examples/test.peg: -------------------------------------------------------------------------------- 1 | start <- body '.' { printf(".\n"); } 2 | 3 | body <- 'a' { printf("a1 "); } 'b' { printf("ab1 "); } 4 | 5 | / 'a' { printf("a2 "); } 'c' { printf("ac2 "); } 6 | 7 | / 'a' { printf("a3 "); } ( 'd' { printf("ad3 "); } / 'e' { printf("ae3 "); } ) 8 | 9 | / 'a' { printf("a4 "); } ( 'f' { printf("af4 "); } 'g' { printf("afg4 "); } 10 | / 'f' { printf("af5 "); } 'h' { printf("afh5 "); } ) 11 | 12 | / 'a' { printf("a6 "); } ( 'f' &{ printf("af6 ") } 'i' &{ printf("afi6 ") } 13 | / 'f' &{ printf("af7 ") } 'j' &{ printf("afj7 ") } ) 14 | -------------------------------------------------------------------------------- /examples/test.ref: -------------------------------------------------------------------------------- 1 | a1 ab1 . 2 | a2 ac2 . 3 | a3 ad3 . 4 | a3 ae3 . 5 | a4 af4 afg4 . 6 | a4 af5 afh5 . 7 | a4 af4 afg4 . 8 | a4 af5 afh5 . 9 | af6 afi6 a6 . 10 | af6 af7 afj7 a6 . 11 | -------------------------------------------------------------------------------- /examples/username.leg: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | start = "username" { printf("%s", getlogin()); } 6 | | < . > { putchar(yytext[0]); } 7 | 8 | %% 9 | 10 | int main() 11 | { 12 | while (yyparse()); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /examples/wc.leg: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | int lines= 0, words= 0, chars= 0; 4 | %} 5 | 6 | start = (line | word | char) 7 | 8 | line = < (( '\n' '\r'* ) | ( '\r' '\n'* )) > { lines++; chars += yyleng; } 9 | word = < [a-zA-Z]+ > { words++; chars += yyleng; printf("<%s>\n", yytext); } 10 | char = . { chars++; } 11 | 12 | %% 13 | 14 | int main() 15 | { 16 | while (yyparse()) 17 | ; 18 | printf("%d lines\n", lines); 19 | printf("%d chars\n", chars); 20 | printf("%d words\n", words); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/wc.ref: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 22 lines 54 | 425 chars 55 | 52 words 56 | -------------------------------------------------------------------------------- /leg-mode.el: -------------------------------------------------------------------------------- 1 | ;;; leg-mode.el -- minor mode for editing leg parsers 2 | ;;; 3 | ;;; THIS SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. 4 | ;;; 5 | ;;; Last edited: 2016-07-26 14:14:47 by piumarta on nas.local 6 | 7 | (defvar-local leg-mode-active? nil) 8 | (defvar-local leg-mode-timer nil) 9 | (defvar-local leg-mode-check? nil) 10 | 11 | (defun leg-mode-changed () 12 | (when leg-mode-timer (cancel-timer leg-mode-timer)) 13 | (setq leg-mode-timer (run-with-idle-timer 0.2 t 'leg-mode-check)) 14 | (add-hook 'post-command-hook 'leg-mode-enable-check nil t)) 15 | 16 | (defun leg-mode-enable-check () 17 | (setq leg-mode-check? t)) 18 | 19 | (defun leg-mode-check () 20 | (when (and leg-mode-check? (not (region-active-p))) 21 | (setq leg-mode-check? nil) 22 | (let (( active (save-excursion (setq active (or (search-backward "%}" nil t) -1)))) 23 | (inactive (save-excursion (setq inactive (or (search-backward "%%" nil t) -1)))) 24 | (active? (> active inactive))) 25 | (unless (eq active? leg-mode-active?) 26 | (funcall (if active? 'fundamental-mode 'c-mode)) 27 | (leg-mode-changed) 28 | (and font-lock-mode (not active?) (font-lock-fontify-buffer)) 29 | (setq leg-mode-active? active?))))) 30 | 31 | (defun leg-mode () 32 | "Minor mode for editing leg parsers." 33 | (interactive) 34 | (funcall 'c-mode) 35 | (unless (assq 'leg-mode-timer minor-mode-alist) 36 | (setq minor-mode-alist (cons '(leg-mode-timer " LEG") minor-mode-alist))) 37 | (leg-mode-changed)) 38 | 39 | (provide 'leg-mode) 40 | -------------------------------------------------------------------------------- /leg.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {5ECEC9E5-8F23-47B6-93E0-C3B328B3BE66} 15 | Win32Proj 16 | leg 17 | $(ProjectName) 18 | 19 | 20 | 21 | Application 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | $(ExecutablePath);$(MSBuildProjectDirectory)\.\bin\;$(MSBuildProjectDirectory)\.\bin\ 31 | $(Configuration)\obj\$(ProjectName)\ 32 | $(SolutionDir)$(Configuration)\ 33 | 34 | 35 | 36 | win;%(AdditionalIncludeDirectories) 37 | WIN32;_WINDOWS;DEBUG;%(PreprocessorDefinitions) 38 | 39 | 40 | true 41 | $(OutDir)$(ProjectName).exe 42 | Console 43 | 44 | 45 | win;%(AdditionalIncludeDirectories) 46 | WIN32;_WINDOWS;DEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions) 47 | 48 | 49 | 50 | 51 | win;%(AdditionalIncludeDirectories) 52 | WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) 53 | 54 | 55 | true 56 | $(OutDir)$(ProjectName).exe 57 | Console 58 | 59 | 60 | win;%(AdditionalIncludeDirectories) 61 | WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions) 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /leg.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {47FC5EC4-15EB-E92F-89D7-AFE51CF838A9} 6 | 7 | 8 | 9 | 10 | 11 | win 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /peg.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': [ 3 | { 4 | 'target_name': 'peg', 5 | 'type': 'executable', 6 | 'msvs_guid': '5ECEC9E5-8F23-47B6-93E0-C3B328B3BE65', 7 | 'sources': [ 8 | 'peg.c', 9 | 'tree.c', 10 | 'compile.c', 11 | ], 12 | 'conditions': [ 13 | ['OS=="win"', { 14 | 'include_dirs': [ 15 | 'win', 16 | ], 17 | 'sources': [ 18 | 'win/getopt.c', 19 | ], 20 | }], 21 | ], 22 | }, 23 | { 24 | 'target_name': 'leg', 25 | 'type': 'executable', 26 | 'msvs_guid': '5ECEC9E5-8F23-47B6-93E0-C3B328B3BE66', 27 | 'sources': [ 28 | 'leg.c', 29 | 'tree.c', 30 | 'compile.c', 31 | ], 32 | 'conditions': [ 33 | ['OS=="win"', { 34 | 'include_dirs': [ 35 | 'win', 36 | ], 37 | 'sources': [ 38 | 'win/getopt.c', 39 | ], 40 | }], 41 | ], 42 | }, 43 | ], 44 | 45 | 'target_defaults': { 46 | 'configurations': { 47 | 'Debug': { 48 | 'defines': [ 49 | 'DEBUG', 50 | ], 51 | }, 52 | 'Release': { 53 | 'defines': [ 54 | 'NDEBUG', 55 | ], 56 | }, 57 | }, 58 | }, 59 | 60 | # define default project settings 61 | 'conditions': [ 62 | ['OS=="win"', { 63 | 'target_defaults': { 64 | 'defines': [ 65 | 'WIN32', 66 | '_WINDOWS', 67 | ], 68 | 'msvs_settings': { 69 | 'VCLinkerTool': { 70 | 'GenerateDebugInformation': 'true', 71 | # SubSystem values: 72 | # 0 == not set 73 | # 1 == /SUBSYSTEM:CONSOLE 74 | # 2 == /SUBSYSTEM:WINDOWS 75 | 'SubSystem': '1', 76 | }, 77 | }, 78 | }, 79 | }], 80 | ], 81 | } 82 | -------------------------------------------------------------------------------- /peg.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 11.00 2 | # Visual Studio 2010 3 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "leg", "leg.vcxproj", "{5ECEC9E5-8F23-47B6-93E0-C3B328B3BE66}" 4 | EndProject 5 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peg", "peg.vcxproj", "{5ECEC9E5-8F23-47B6-93E0-C3B328B3BE65}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Win32 = Debug|Win32 10 | Release|Win32 = Release|Win32 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {5ECEC9E5-8F23-47B6-93E0-C3B328B3BE65}.Debug|Win32.ActiveCfg = Debug|Win32 14 | {5ECEC9E5-8F23-47B6-93E0-C3B328B3BE65}.Debug|Win32.Build.0 = Debug|Win32 15 | {5ECEC9E5-8F23-47B6-93E0-C3B328B3BE65}.Release|Win32.ActiveCfg = Release|Win32 16 | {5ECEC9E5-8F23-47B6-93E0-C3B328B3BE65}.Release|Win32.Build.0 = Release|Win32 17 | {5ECEC9E5-8F23-47B6-93E0-C3B328B3BE66}.Debug|Win32.ActiveCfg = Debug|Win32 18 | {5ECEC9E5-8F23-47B6-93E0-C3B328B3BE66}.Debug|Win32.Build.0 = Debug|Win32 19 | {5ECEC9E5-8F23-47B6-93E0-C3B328B3BE66}.Release|Win32.ActiveCfg = Release|Win32 20 | {5ECEC9E5-8F23-47B6-93E0-C3B328B3BE66}.Release|Win32.Build.0 = Release|Win32 21 | EndGlobalSection 22 | GlobalSection(SolutionProperties) = preSolution 23 | HideSolutionNode = FALSE 24 | EndGlobalSection 25 | GlobalSection(NestedProjects) = preSolution 26 | EndGlobalSection 27 | EndGlobal 28 | -------------------------------------------------------------------------------- /peg.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {5ECEC9E5-8F23-47B6-93E0-C3B328B3BE65} 15 | Win32Proj 16 | peg 17 | $(ProjectName) 18 | 19 | 20 | 21 | Application 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | $(ExecutablePath);$(MSBuildProjectDirectory)\.\bin\;$(MSBuildProjectDirectory)\.\bin\ 31 | $(Configuration)\obj\$(ProjectName)\ 32 | $(SolutionDir)$(Configuration)\ 33 | 34 | 35 | 36 | win;%(AdditionalIncludeDirectories) 37 | WIN32;_WINDOWS;DEBUG;%(PreprocessorDefinitions) 38 | 39 | 40 | true 41 | $(OutDir)$(ProjectName).exe 42 | Console 43 | 44 | 45 | win;%(AdditionalIncludeDirectories) 46 | WIN32;_WINDOWS;DEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions) 47 | 48 | 49 | 50 | 51 | win;%(AdditionalIncludeDirectories) 52 | WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) 53 | 54 | 55 | true 56 | $(OutDir)$(ProjectName).exe 57 | Console 58 | 59 | 60 | win;%(AdditionalIncludeDirectories) 61 | WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions) 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /peg.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {47FC5EC4-15EB-E92F-89D7-AFE51CF838A9} 6 | 7 | 8 | 9 | 10 | 11 | win 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /peg.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 45; 7 | objects = { 8 | 9 | /* Begin PBXAggregateTarget section */ 10 | EFBC7368F96EACB75989C21D /* All */ = { 11 | isa = PBXAggregateTarget; 12 | buildConfigurationList = 007E1122105A105C63F8A59F /* Build configuration list for PBXAggregateTarget "All" */; 13 | buildPhases = ( 14 | ); 15 | dependencies = ( 16 | B85F90055126E00C1334834C /* PBXTargetDependency */, 17 | 3DF530CEA77A591E4DFBFF2F /* PBXTargetDependency */, 18 | ); 19 | name = All; 20 | productName = All; 21 | }; 22 | /* End PBXAggregateTarget section */ 23 | 24 | /* Begin PBXBuildFile section */ 25 | 2D4E663DE432A398FC78635B /* compile.c in Sources */ = {isa = PBXBuildFile; fileRef = D4BAF07C3AF28E51DD58E853 /* compile.c */; }; 26 | 3FE25C706AB45972C102CBB4 /* tree.c in Sources */ = {isa = PBXBuildFile; fileRef = E503317C684EFEB3E7E03861 /* tree.c */; }; 27 | 4D30CEABCD51397A50F65058 /* compile.c in Sources */ = {isa = PBXBuildFile; fileRef = D4BAF07C3AF28E51DD58E853 /* compile.c */; }; 28 | 7921C7C2AD25A4A4C02470F5 /* peg.c in Sources */ = {isa = PBXBuildFile; fileRef = 27FA3C119507A9A914A66936 /* peg.c */; }; 29 | 8B61C6AE75A1750C17350E64 /* tree.c in Sources */ = {isa = PBXBuildFile; fileRef = E503317C684EFEB3E7E03861 /* tree.c */; }; 30 | D8C3FFD80B6642D8BB341B90 /* leg.c in Sources */ = {isa = PBXBuildFile; fileRef = 454F9F599E7B65F90C62CF9C /* leg.c */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXContainerItemProxy section */ 34 | 12CD2CA862C5C1693300D7EF /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = D23EA86C97C1C940E2591A06 /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = 84A1E5C1231D1E337ED0FC84; 39 | remoteInfo = leg; 40 | }; 41 | 22C9A5E8EF76D4B801BB24E5 /* PBXContainerItemProxy */ = { 42 | isa = PBXContainerItemProxy; 43 | containerPortal = D23EA86C97C1C940E2591A06 /* Project object */; 44 | proxyType = 1; 45 | remoteGlobalIDString = 050EA9DBA8F5C296C3E39B8A; 46 | remoteInfo = peg; 47 | }; 48 | /* End PBXContainerItemProxy section */ 49 | 50 | /* Begin PBXFileReference section */ 51 | 27FA3C119507A9A914A66936 /* peg.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = src/peg.c; sourceTree = ""; }; 52 | 4165F882B6F541E12DBD6A0D /* peg */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = peg; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | 454F9F599E7B65F90C62CF9C /* leg.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = src/leg.c; sourceTree = ""; }; 54 | 5C991B5472A7498A982B7350 /* peg.gyp */ = {isa = PBXFileReference; lastKnownFileType = text; path = peg.gyp; sourceTree = ""; }; 55 | C9B3F1D07DD720C50DE87DC5 /* leg */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = leg; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | D4BAF07C3AF28E51DD58E853 /* compile.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = src/compile.c; sourceTree = ""; }; 57 | E503317C684EFEB3E7E03861 /* tree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = src/tree.c; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | 3DF86BD64E76AD4F8D892CF6 /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | 97D5812F2529A3E39CE17CDE /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | /* End PBXFrameworksBuildPhase section */ 76 | 77 | /* Begin PBXGroup section */ 78 | 3854A05A8AE7E9B329F09174 /* Build */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 5C991B5472A7498A982B7350 /* peg.gyp */, 82 | ); 83 | name = Build; 84 | sourceTree = ""; 85 | }; 86 | AB7FD4EAF4FFE1A1CE63E31B = { 87 | isa = PBXGroup; 88 | children = ( 89 | E2D71C5771542F758C302162 /* Source */, 90 | AF64E60ED33C9E5DC5DB4C21 /* Products */, 91 | 3854A05A8AE7E9B329F09174 /* Build */, 92 | ); 93 | sourceTree = ""; 94 | }; 95 | AF64E60ED33C9E5DC5DB4C21 /* Products */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 4165F882B6F541E12DBD6A0D /* peg */, 99 | C9B3F1D07DD720C50DE87DC5 /* leg */, 100 | ); 101 | name = Products; 102 | sourceTree = ""; 103 | }; 104 | E2D71C5771542F758C302162 /* Source */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | D4BAF07C3AF28E51DD58E853 /* compile.c */, 108 | 454F9F599E7B65F90C62CF9C /* leg.c */, 109 | 27FA3C119507A9A914A66936 /* peg.c */, 110 | E503317C684EFEB3E7E03861 /* tree.c */, 111 | ); 112 | name = Source; 113 | sourceTree = ""; 114 | }; 115 | /* End PBXGroup section */ 116 | 117 | /* Begin PBXNativeTarget section */ 118 | 050EA9DBA8F5C296C3E39B8A /* peg */ = { 119 | isa = PBXNativeTarget; 120 | buildConfigurationList = EF4B00311D83FC2C01B276A4 /* Build configuration list for PBXNativeTarget "peg" */; 121 | buildPhases = ( 122 | 74AA795D8990365CCE282118 /* Sources */, 123 | 97D5812F2529A3E39CE17CDE /* Frameworks */, 124 | ); 125 | buildRules = ( 126 | ); 127 | dependencies = ( 128 | ); 129 | name = peg; 130 | productName = peg; 131 | productReference = 4165F882B6F541E12DBD6A0D /* peg */; 132 | productType = "com.apple.product-type.tool"; 133 | }; 134 | 84A1E5C1231D1E337ED0FC84 /* leg */ = { 135 | isa = PBXNativeTarget; 136 | buildConfigurationList = F7568C4D321FF46C2F4B43FB /* Build configuration list for PBXNativeTarget "leg" */; 137 | buildPhases = ( 138 | 915DAD0C515729956FE2BC69 /* Sources */, 139 | 3DF86BD64E76AD4F8D892CF6 /* Frameworks */, 140 | ); 141 | buildRules = ( 142 | ); 143 | dependencies = ( 144 | ); 145 | name = leg; 146 | productName = leg; 147 | productReference = C9B3F1D07DD720C50DE87DC5 /* leg */; 148 | productType = "com.apple.product-type.tool"; 149 | }; 150 | /* End PBXNativeTarget section */ 151 | 152 | /* Begin PBXProject section */ 153 | D23EA86C97C1C940E2591A06 /* Project object */ = { 154 | isa = PBXProject; 155 | attributes = { 156 | BuildIndependentTargetsInParallel = YES; 157 | }; 158 | buildConfigurationList = 283B121430353A60CB56914F /* Build configuration list for PBXProject "peg" */; 159 | compatibilityVersion = "Xcode 3.2"; 160 | hasScannedForEncodings = 1; 161 | mainGroup = AB7FD4EAF4FFE1A1CE63E31B; 162 | projectDirPath = ""; 163 | projectRoot = ""; 164 | targets = ( 165 | EFBC7368F96EACB75989C21D /* All */, 166 | 050EA9DBA8F5C296C3E39B8A /* peg */, 167 | 84A1E5C1231D1E337ED0FC84 /* leg */, 168 | ); 169 | }; 170 | /* End PBXProject section */ 171 | 172 | /* Begin PBXSourcesBuildPhase section */ 173 | 74AA795D8990365CCE282118 /* Sources */ = { 174 | isa = PBXSourcesBuildPhase; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | 7921C7C2AD25A4A4C02470F5 /* peg.c in Sources */, 178 | 8B61C6AE75A1750C17350E64 /* tree.c in Sources */, 179 | 4D30CEABCD51397A50F65058 /* compile.c in Sources */, 180 | ); 181 | runOnlyForDeploymentPostprocessing = 0; 182 | }; 183 | 915DAD0C515729956FE2BC69 /* Sources */ = { 184 | isa = PBXSourcesBuildPhase; 185 | buildActionMask = 2147483647; 186 | files = ( 187 | D8C3FFD80B6642D8BB341B90 /* leg.c in Sources */, 188 | 3FE25C706AB45972C102CBB4 /* tree.c in Sources */, 189 | 2D4E663DE432A398FC78635B /* compile.c in Sources */, 190 | ); 191 | runOnlyForDeploymentPostprocessing = 0; 192 | }; 193 | /* End PBXSourcesBuildPhase section */ 194 | 195 | /* Begin PBXTargetDependency section */ 196 | 3DF530CEA77A591E4DFBFF2F /* PBXTargetDependency */ = { 197 | isa = PBXTargetDependency; 198 | target = 84A1E5C1231D1E337ED0FC84 /* leg */; 199 | targetProxy = 12CD2CA862C5C1693300D7EF /* PBXContainerItemProxy */; 200 | }; 201 | B85F90055126E00C1334834C /* PBXTargetDependency */ = { 202 | isa = PBXTargetDependency; 203 | target = 050EA9DBA8F5C296C3E39B8A /* peg */; 204 | targetProxy = 22C9A5E8EF76D4B801BB24E5 /* PBXContainerItemProxy */; 205 | }; 206 | /* End PBXTargetDependency section */ 207 | 208 | /* Begin XCBuildConfiguration section */ 209 | 05AA053A004215362908ED84 /* Release */ = { 210 | isa = XCBuildConfiguration; 211 | buildSettings = { 212 | EXECUTABLE_PREFIX = ""; 213 | GCC_PREPROCESSOR_DEFINITIONS = "\"NDEBUG\""; 214 | PRODUCT_NAME = peg; 215 | }; 216 | name = Release; 217 | }; 218 | 2CB45BB7949774F10834EB3B /* Release */ = { 219 | isa = XCBuildConfiguration; 220 | buildSettings = { 221 | INTERMEDIATE_DIR = "$(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION)"; 222 | SHARED_INTERMEDIATE_DIR = "$(SYMROOT)/DerivedSources/$(CONFIGURATION)"; 223 | }; 224 | name = Release; 225 | }; 226 | 7C93F597151F1782DBAF2E6E /* Debug */ = { 227 | isa = XCBuildConfiguration; 228 | buildSettings = { 229 | INTERMEDIATE_DIR = "$(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION)"; 230 | SHARED_INTERMEDIATE_DIR = "$(SYMROOT)/DerivedSources/$(CONFIGURATION)"; 231 | }; 232 | name = Debug; 233 | }; 234 | 879858F43394AA4CEFDC7263 /* Release */ = { 235 | isa = XCBuildConfiguration; 236 | buildSettings = { 237 | EXECUTABLE_PREFIX = ""; 238 | GCC_PREPROCESSOR_DEFINITIONS = "\"NDEBUG\""; 239 | PRODUCT_NAME = leg; 240 | }; 241 | name = Release; 242 | }; 243 | 8CF09EF6E825DDB8D49A6EA9 /* Release */ = { 244 | isa = XCBuildConfiguration; 245 | buildSettings = { 246 | PRODUCT_NAME = All; 247 | }; 248 | name = Release; 249 | }; 250 | DEFEA64AA5600BECDDA9A939 /* Debug */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | PRODUCT_NAME = All; 254 | }; 255 | name = Debug; 256 | }; 257 | E2B1202070FAC019FA0BF2ED /* Debug */ = { 258 | isa = XCBuildConfiguration; 259 | buildSettings = { 260 | EXECUTABLE_PREFIX = ""; 261 | GCC_PREPROCESSOR_DEFINITIONS = "\"DEBUG\""; 262 | PRODUCT_NAME = leg; 263 | }; 264 | name = Debug; 265 | }; 266 | F41144D27A6369001B96C713 /* Debug */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | EXECUTABLE_PREFIX = ""; 270 | GCC_PREPROCESSOR_DEFINITIONS = "\"DEBUG\""; 271 | PRODUCT_NAME = peg; 272 | }; 273 | name = Debug; 274 | }; 275 | /* End XCBuildConfiguration section */ 276 | 277 | /* Begin XCConfigurationList section */ 278 | 007E1122105A105C63F8A59F /* Build configuration list for PBXAggregateTarget "All" */ = { 279 | isa = XCConfigurationList; 280 | buildConfigurations = ( 281 | DEFEA64AA5600BECDDA9A939 /* Debug */, 282 | 8CF09EF6E825DDB8D49A6EA9 /* Release */, 283 | ); 284 | defaultConfigurationIsVisible = 1; 285 | defaultConfigurationName = Debug; 286 | }; 287 | 283B121430353A60CB56914F /* Build configuration list for PBXProject "peg" */ = { 288 | isa = XCConfigurationList; 289 | buildConfigurations = ( 290 | 7C93F597151F1782DBAF2E6E /* Debug */, 291 | 2CB45BB7949774F10834EB3B /* Release */, 292 | ); 293 | defaultConfigurationIsVisible = 1; 294 | defaultConfigurationName = Debug; 295 | }; 296 | EF4B00311D83FC2C01B276A4 /* Build configuration list for PBXNativeTarget "peg" */ = { 297 | isa = XCConfigurationList; 298 | buildConfigurations = ( 299 | F41144D27A6369001B96C713 /* Debug */, 300 | 05AA053A004215362908ED84 /* Release */, 301 | ); 302 | defaultConfigurationIsVisible = 1; 303 | defaultConfigurationName = Debug; 304 | }; 305 | F7568C4D321FF46C2F4B43FB /* Build configuration list for PBXNativeTarget "leg" */ = { 306 | isa = XCConfigurationList; 307 | buildConfigurations = ( 308 | E2B1202070FAC019FA0BF2ED /* Debug */, 309 | 879858F43394AA4CEFDC7263 /* Release */, 310 | ); 311 | defaultConfigurationIsVisible = 1; 312 | defaultConfigurationName = Debug; 313 | }; 314 | /* End XCConfigurationList section */ 315 | }; 316 | rootObject = D23EA86C97C1C940E2591A06 /* Project object */; 317 | } 318 | -------------------------------------------------------------------------------- /src/compile.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007--2013 by Ian Piumarta 2 | * All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the 'Software'), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, provided that the above copyright notice(s) and this 10 | * permission notice appear in all copies of the Software. Acknowledgement 11 | * of the use of this Software in supporting documentation would be 12 | * appreciated but is not required. 13 | * 14 | * THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. 15 | * 16 | * Last edited: 2023-11-18 21:07:50 by piumarta on debian 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #ifdef WIN32 25 | # undef inline 26 | # define inline __inline 27 | #endif 28 | 29 | #include "version.h" 30 | #include "tree.h" 31 | 32 | static int yyl(void) 33 | { 34 | static int prev= 0; 35 | return ++prev; 36 | } 37 | 38 | static void charClassSet (unsigned char bits[], int c) { bits[c >> 3] |= (1 << (c & 7)); } 39 | static void charClassClear(unsigned char bits[], int c) { bits[c >> 3] &= ~(1 << (c & 7)); } 40 | 41 | typedef void (*setter)(unsigned char bits[], int c); 42 | 43 | static inline int oigit(int c) { return ('0' <= c && c <= '7'); } 44 | static inline int higit(int c) { return ('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'); } 45 | 46 | static inline int hexval(int c) 47 | { 48 | if ('0' <= c && c <= '9') return c - '0'; 49 | if ('A' <= c && c <= 'F') return 10 - 'A' + c; 50 | if ('a' <= c && c <= 'f') return 10 - 'a' + c; 51 | return 0; 52 | } 53 | 54 | static int cnext(unsigned char **ccp) 55 | { 56 | unsigned char *cclass= *ccp; 57 | int c= *cclass++; 58 | if (c) 59 | { 60 | if ('\\' == c && *cclass) 61 | { 62 | switch (c= *cclass++) 63 | { 64 | case 'a': c= '\a'; break; /* bel */ 65 | case 'b': c= '\b'; break; /* bs */ 66 | case 'e': c= '\033'; break; /* esc */ 67 | case 'f': c= '\f'; break; /* ff */ 68 | case 'n': c= '\n'; break; /* nl */ 69 | case 'r': c= '\r'; break; /* cr */ 70 | case 't': c= '\t'; break; /* ht */ 71 | case 'v': c= '\v'; break; /* vt */ 72 | case 'x': 73 | c= 0; 74 | if (higit(*cclass)) c= (c << 4) + hexval(*cclass++); 75 | if (higit(*cclass)) c= (c << 4) + hexval(*cclass++); 76 | break; 77 | default: 78 | if (oigit(c)) 79 | { 80 | c -= '0'; 81 | if (oigit(*cclass)) c= (c << 3) + *cclass++ - '0'; 82 | if (oigit(*cclass)) c= (c << 3) + *cclass++ - '0'; 83 | } 84 | break; 85 | } 86 | } 87 | *ccp= cclass; 88 | } 89 | return c; 90 | } 91 | 92 | static char *makeCharClass(unsigned char *cclass) 93 | { 94 | unsigned char bits[32]; 95 | setter set; 96 | int c, prev= -1; 97 | static char string[256]; 98 | char *ptr; 99 | 100 | if ('^' == *cclass) 101 | { 102 | memset(bits, 255, 32); 103 | set= charClassClear; 104 | ++cclass; 105 | } 106 | else 107 | { 108 | memset(bits, 0, 32); 109 | set= charClassSet; 110 | } 111 | 112 | while (*cclass) 113 | { 114 | if ('-' == *cclass && cclass[1] && prev >= 0) 115 | { 116 | ++cclass; 117 | for (c= cnext(&cclass); prev <= c; ++prev) 118 | set(bits, prev); 119 | prev= -1; 120 | } 121 | else 122 | { 123 | c= cnext(&cclass); 124 | set(bits, prev= c); 125 | } 126 | } 127 | 128 | ptr= string; 129 | for (c= 0; c < 32; ++c) 130 | ptr += sprintf(ptr, "\\%03o", bits[c]); 131 | 132 | return string; 133 | } 134 | 135 | static void begin(void) { fprintf(output, "\n {"); } 136 | static void end(void) { fprintf(output, "\n }"); } 137 | static void label(int n) { fprintf(output, "\n l%d:;\t", n); } 138 | static void jump(int n) { fprintf(output, " goto l%d;", n); } 139 | static void save(int n) { fprintf(output, " int yypos%d= yy->__pos, yythunkpos%d= yy->__thunkpos;", n, n); } 140 | static void restore(int n) { fprintf(output, " yy->__pos= yypos%d; yy->__thunkpos= yythunkpos%d;", n, n); } 141 | 142 | static int countVariables(Node *node) 143 | { 144 | int count= 0; 145 | while (node) 146 | { 147 | ++count; 148 | node= node->variable.next; 149 | } 150 | return count; 151 | } 152 | 153 | static void allocateVariables(Node *node) 154 | { 155 | int count= 0; 156 | while (node) 157 | { 158 | node->variable.offset= --count; 159 | node= node->variable.next; 160 | } 161 | } 162 | 163 | static void defineVariables(Node *node) 164 | { 165 | while (node) 166 | { 167 | fprintf(output, "#define %s yy->__val[%d]\n", node->variable.name, node->variable.offset); 168 | node= node->variable.next; 169 | } 170 | fprintf(output, "#define __ yy->__\n"); 171 | fprintf(output, "#define yypos yy->__pos\n"); 172 | fprintf(output, "#define yythunkpos yy->__thunkpos\n"); 173 | } 174 | 175 | static void undefineVariables(Node *node) 176 | { 177 | fprintf(output, "#undef yythunkpos\n"); 178 | fprintf(output, "#undef yypos\n"); 179 | fprintf(output, "#undef yy\n"); 180 | while (node) 181 | { 182 | fprintf(output, "#undef %s\n", node->variable.name); 183 | node= node->variable.next; 184 | } 185 | } 186 | 187 | 188 | static void Node_compile_c_ko(Node *node, int ko) 189 | { 190 | assert(node); 191 | switch (node->type) 192 | { 193 | case Rule: 194 | fprintf(stderr, "\ninternal error #1 (%s)\n", node->rule.name); 195 | exit(1); 196 | break; 197 | 198 | case Dot: 199 | fprintf(output, " if (!yymatchDot(yy)) goto l%d;", ko); 200 | break; 201 | 202 | case Name: 203 | fprintf(output, " if (!yy_%s(yy)) goto l%d;", node->name.rule->rule.name, ko); 204 | if (node->name.variable) { 205 | int n = node->name.variable->variable.offset; 206 | fprintf(output, " yySet(yy, 0, %d); yyDo(yy, yySet, %d, 0);", n, n); 207 | } 208 | break; 209 | 210 | case Character: 211 | case String: 212 | { 213 | int len= strlen(node->string.value); 214 | if (1 == len) 215 | { 216 | if ('\'' == node->string.value[0]) 217 | fprintf(output, " if (!yymatchChar(yy, '\\'')) goto l%d;", ko); 218 | else 219 | fprintf(output, " if (!yymatchChar(yy, '%s')) goto l%d;", node->string.value, ko); 220 | } 221 | else 222 | if (2 == len && '\\' == node->string.value[0]) 223 | fprintf(output, " if (!yymatchChar(yy, '%s')) goto l%d;", node->string.value, ko); 224 | else 225 | fprintf(output, " if (!yymatchString(yy, \"%s\")) goto l%d;", node->string.value, ko); 226 | } 227 | break; 228 | 229 | case Class: 230 | fprintf(output, " if (!yymatchClass(yy, (unsigned char *)\"%s\")) goto l%d;", makeCharClass(node->cclass.value), ko); 231 | break; 232 | 233 | case Action: 234 | fprintf(output, " yyDo(yy, yy%s, yy->__begin, yy->__end);", node->action.name); 235 | break; 236 | 237 | case Inline: 238 | fprintf(output, " yyText(yy, yy->__begin, yy->__end);\n"); 239 | defineVariables(node->inLine.rule->rule.variables); 240 | fprintf(output, "#define yytext yy->__text\n"); 241 | fprintf(output, "#define yyleng yy->__textlen\n"); 242 | fprintf(output, "%s;\n", node->inLine.text); 243 | fprintf(output, "#undef yytext\n"); 244 | fprintf(output, "#undef yyleng\n"); 245 | undefineVariables(node->inLine.rule->rule.variables); 246 | break; 247 | 248 | case Predicate: 249 | fprintf(output, " yyText(yy, yy->__begin, yy->__end); {\n"); 250 | fprintf(output, "#define yytext yy->__text\n"); 251 | fprintf(output, "#define yyleng yy->__textlen\n"); 252 | fprintf(output, "if (!(%s)) goto l%d;\n", node->predicate.text, ko); 253 | fprintf(output, "#undef yytext\n"); 254 | fprintf(output, "#undef yyleng\n"); 255 | fprintf(output, " }"); 256 | break; 257 | 258 | case Error: 259 | { 260 | int eok= yyl(), eko= yyl(); 261 | Node_compile_c_ko(node->error.element, eko); 262 | jump(eok); 263 | label(eko); 264 | fprintf(output, " yyText(yy, yy->__begin, yy->__end); {\n"); 265 | fprintf(output, "#define yytext yy->__text\n"); 266 | fprintf(output, "#define yyleng yy->__textlen\n"); 267 | fprintf(output, " %s;\n", node->error.text); 268 | fprintf(output, "#undef yytext\n"); 269 | fprintf(output, "#undef yyleng\n"); 270 | fprintf(output, " }"); 271 | jump(ko); 272 | label(eok); 273 | } 274 | break; 275 | 276 | case Alternate: 277 | { 278 | int ok= yyl(); 279 | begin(); 280 | save(ok); 281 | for (node= node->alternate.first; node; node= node->alternate.next) 282 | if (node->alternate.next) 283 | { 284 | int next= yyl(); 285 | Node_compile_c_ko(node, next); 286 | jump(ok); 287 | label(next); 288 | restore(ok); 289 | } 290 | else 291 | Node_compile_c_ko(node, ko); 292 | end(); 293 | label(ok); 294 | } 295 | break; 296 | 297 | case Sequence: 298 | for (node= node->sequence.first; node; node= node->sequence.next) 299 | Node_compile_c_ko(node, ko); 300 | break; 301 | 302 | case PeekFor: 303 | { 304 | int ok= yyl(); 305 | begin(); 306 | save(ok); 307 | Node_compile_c_ko(node->peekFor.element, ko); 308 | restore(ok); 309 | end(); 310 | } 311 | break; 312 | 313 | case PeekNot: 314 | { 315 | int ok= yyl(); 316 | begin(); 317 | save(ok); 318 | Node_compile_c_ko(node->peekFor.element, ok); 319 | jump(ko); 320 | label(ok); 321 | restore(ok); 322 | end(); 323 | } 324 | break; 325 | 326 | case Query: 327 | { 328 | int qko= yyl(), qok= yyl(); 329 | begin(); 330 | save(qko); 331 | Node_compile_c_ko(node->query.element, qko); 332 | jump(qok); 333 | label(qko); 334 | restore(qko); 335 | end(); 336 | label(qok); 337 | } 338 | break; 339 | 340 | case Star: 341 | { 342 | int again= yyl(), out= yyl(); 343 | label(again); 344 | begin(); 345 | save(out); 346 | Node_compile_c_ko(node->star.element, out); 347 | jump(again); 348 | label(out); 349 | restore(out); 350 | end(); 351 | } 352 | break; 353 | 354 | case Plus: 355 | { 356 | int again= yyl(), out= yyl(); 357 | Node_compile_c_ko(node->plus.element, ko); 358 | label(again); 359 | begin(); 360 | save(out); 361 | Node_compile_c_ko(node->plus.element, out); 362 | jump(again); 363 | label(out); 364 | restore(out); 365 | end(); 366 | } 367 | break; 368 | 369 | default: 370 | fprintf(stderr, "\nNode_compile_c_ko: illegal node type %d\n", node->type); 371 | exit(1); 372 | } 373 | } 374 | 375 | 376 | static void Rule_compile_c2(Node *node) 377 | { 378 | assert(node); 379 | assert(Rule == node->type); 380 | 381 | if (!node->rule.expression) 382 | fprintf(stderr, "rule '%s' used but not defined\n", node->rule.name); 383 | else 384 | { 385 | int ko= yyl(), safe; 386 | 387 | if ((!(RuleUsed & node->rule.flags)) && (node != start)) 388 | fprintf(stderr, "rule '%s' defined but not used\n", node->rule.name); 389 | 390 | safe= ((Query == node->rule.expression->type) || (Star == node->rule.expression->type)); 391 | 392 | fprintf(output, "\nYY_RULE(int) yy_%s(yycontext *yy)\n{", node->rule.name); 393 | if (!safe) save(0); 394 | if (node->rule.variables) { 395 | int n= countVariables(node->rule.variables); 396 | fprintf(output, " yyEnter(yy, %d); yyDo(yy, yyPush, %d, 0);", n, n); 397 | } 398 | fprintf(output, "\n yyprintf((stderr, \"%%s\\n\", \"%s\"));", node->rule.name); 399 | Node_compile_c_ko(node->rule.expression, ko); 400 | fprintf(output, "\n yyprintf((stderr, \" ok %%s @ %%s\\n\", \"%s\", yy->__buf+yy->__pos));", node->rule.name); 401 | if (node->rule.variables) { 402 | int n= countVariables(node->rule.variables); 403 | fprintf(output, "\n yyLeave(yy, %d); yyDo(yy, yyPop, %d, 0);", n, n); 404 | } 405 | fprintf(output, "\n return 1;"); 406 | if (!safe) 407 | { 408 | label(ko); 409 | restore(0); 410 | fprintf(output, "\n yyprintf((stderr, \" fail %%s @ %%s\\n\", \"%s\", yy->__buf+yy->__pos));", node->rule.name); 411 | if (node->rule.variables) { 412 | int n= countVariables(node->rule.variables); 413 | fprintf(output, "\n yyLeave(yy, %d);", n); 414 | } 415 | fprintf(output, "\n return 0;"); 416 | } 417 | fprintf(output, "\n}"); 418 | } 419 | 420 | if (node->rule.next) 421 | Rule_compile_c2(node->rule.next); 422 | } 423 | 424 | static char *header= "\ 425 | #include \n\ 426 | #include \n\ 427 | #include \n\ 428 | "; 429 | 430 | static char *preamble= "\ 431 | #ifndef YY_MALLOC\n\ 432 | #define YY_MALLOC(C, N) malloc(N)\n\ 433 | #endif\n\ 434 | #ifndef YY_REALLOC\n\ 435 | #define YY_REALLOC(C, P, N) realloc(P, N)\n\ 436 | #endif\n\ 437 | #ifndef YY_FREE\n\ 438 | #define YY_FREE(C, P) free(P)\n\ 439 | #endif\n\ 440 | #ifndef YY_LOCAL\n\ 441 | #define YY_LOCAL(T) static T\n\ 442 | #endif\n\ 443 | #ifndef YY_ACTION\n\ 444 | #define YY_ACTION(T) static T\n\ 445 | #endif\n\ 446 | #ifndef YY_RULE\n\ 447 | #define YY_RULE(T) static T\n\ 448 | #endif\n\ 449 | #ifndef YY_PARSE\n\ 450 | #define YY_PARSE(T) T\n\ 451 | #endif\n\ 452 | #ifndef YYPARSE\n\ 453 | #define YYPARSE yyparse\n\ 454 | #endif\n\ 455 | #ifndef YYPARSEFROM_R\n\ 456 | #define YYPARSEFROM_R yyparsefrom_r\n\ 457 | #endif\n\ 458 | #ifndef YYPARSEFROM\n\ 459 | #define YYPARSEFROM yyparsefrom\n\ 460 | #endif\n\ 461 | #ifndef YYRELEASE\n\ 462 | #define YYRELEASE yyrelease\n\ 463 | #endif\n\ 464 | #ifndef YY_BEGIN\n\ 465 | #define YY_BEGIN ( yy->__begin= yy->__pos, 1)\n\ 466 | #endif\n\ 467 | #ifndef YY_END\n\ 468 | #define YY_END ( yy->__end= yy->__pos, 1)\n\ 469 | #endif\n\ 470 | #ifdef YY_DEBUG\n\ 471 | # define yyprintf(args) fprintf args\n\ 472 | #else\n\ 473 | # define yyprintf(args)\n\ 474 | #endif\n\ 475 | #ifndef YYSTYPE\n\ 476 | #define YYSTYPE int\n\ 477 | #endif\n\ 478 | #ifndef YY_STACK_SIZE\n\ 479 | #define YY_STACK_SIZE 128\n\ 480 | #endif\n\ 481 | \n\ 482 | #ifndef YY_BUFFER_SIZE\n\ 483 | #define YY_BUFFER_SIZE 1024\n\ 484 | #endif\n\ 485 | \n\ 486 | #ifndef YY_PART\n\ 487 | \n\ 488 | typedef struct _yycontext yycontext;\n\ 489 | typedef void (*yyaction)(yycontext *yy, char *yytext, int yyleng);\n\ 490 | typedef struct _yythunk { int begin, end; yyaction action; struct _yythunk *next; } yythunk;\n\ 491 | \n\ 492 | struct _yycontext {\n\ 493 | char *__buf;\n\ 494 | int __buflen;\n\ 495 | int __pos;\n\ 496 | int __limit;\n\ 497 | char *__text;\n\ 498 | int __textlen;\n\ 499 | int __begin;\n\ 500 | int __end;\n\ 501 | int __textmax;\n\ 502 | yythunk *__thunks;\n\ 503 | int __thunkslen;\n\ 504 | int __thunkpos;\n\ 505 | YYSTYPE __;\n\ 506 | YYSTYPE *__val;\n\ 507 | YYSTYPE *__vals;\n\ 508 | int __valslen;\n\ 509 | #ifdef YY_CTX_MEMBERS\n\ 510 | YY_CTX_MEMBERS\n\ 511 | #endif\n\ 512 | };\n\ 513 | \n\ 514 | #ifdef YY_CTX_LOCAL\n\ 515 | #define YY_CTX_PARAM_ yycontext *yyctx,\n\ 516 | #define YY_CTX_PARAM yycontext *yyctx\n\ 517 | #define YY_CTX_ARG_ yyctx,\n\ 518 | #define YY_CTX_ARG yyctx\n\ 519 | #ifndef YY_INPUT\n\ 520 | #define YY_INPUT(yy, buf, result, max_size) \\\n\ 521 | { \\\n\ 522 | int yyc= getchar(); \\\n\ 523 | result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \\\n\ 524 | yyprintf((stderr, \"<%c>\", yyc)); \\\n\ 525 | }\n\ 526 | #endif\n\ 527 | #else\n\ 528 | #define YY_CTX_PARAM_\n\ 529 | #define YY_CTX_PARAM\n\ 530 | #define YY_CTX_ARG_\n\ 531 | #define YY_CTX_ARG\n\ 532 | yycontext _yyctx= { 0, 0 };\n\ 533 | yycontext *yyctx= &_yyctx;\n\ 534 | #ifndef YY_INPUT\n\ 535 | #define YY_INPUT(buf, result, max_size) \\\n\ 536 | { \\\n\ 537 | int yyc= getchar(); \\\n\ 538 | result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \\\n\ 539 | yyprintf((stderr, \"<%c>\", yyc)); \\\n\ 540 | }\n\ 541 | #endif\n\ 542 | #endif\n\ 543 | \n\ 544 | YY_LOCAL(int) yyrefill(yycontext *yy)\n\ 545 | {\n\ 546 | int yyn;\n\ 547 | while (yy->__buflen - yy->__pos < 512)\n\ 548 | {\n\ 549 | yy->__buflen *= 2;\n\ 550 | yy->__buf= (char *)YY_REALLOC(yy, yy->__buf, yy->__buflen);\n\ 551 | }\n\ 552 | #ifdef YY_CTX_LOCAL\n\ 553 | YY_INPUT(yy, (yy->__buf + yy->__pos), yyn, (yy->__buflen - yy->__pos));\n\ 554 | #else\n\ 555 | YY_INPUT((yy->__buf + yy->__pos), yyn, (yy->__buflen - yy->__pos));\n\ 556 | #endif\n\ 557 | if (!yyn) return 0;\n\ 558 | yy->__limit += yyn;\n\ 559 | return 1;\n\ 560 | }\n\ 561 | \n\ 562 | YY_LOCAL(int) yymatchDot(yycontext *yy)\n\ 563 | {\n\ 564 | if (yy->__pos >= yy->__limit && !yyrefill(yy)) return 0;\n\ 565 | ++yy->__pos;\n\ 566 | return 1;\n\ 567 | }\n\ 568 | \n\ 569 | YY_LOCAL(int) yymatchChar(yycontext *yy, int c)\n\ 570 | {\n\ 571 | if (yy->__pos >= yy->__limit && !yyrefill(yy)) return 0;\n\ 572 | if ((unsigned char)yy->__buf[yy->__pos] == c)\n\ 573 | {\n\ 574 | ++yy->__pos;\n\ 575 | yyprintf((stderr, \" ok yymatchChar(yy, %c) @ %s\\n\", c, yy->__buf+yy->__pos));\n\ 576 | return 1;\n\ 577 | }\n\ 578 | yyprintf((stderr, \" fail yymatchChar(yy, %c) @ %s\\n\", c, yy->__buf+yy->__pos));\n\ 579 | return 0;\n\ 580 | }\n\ 581 | \n\ 582 | YY_LOCAL(int) yymatchString(yycontext *yy, const char *s)\n\ 583 | {\n\ 584 | int yysav= yy->__pos;\n\ 585 | while (*s)\n\ 586 | {\n\ 587 | if (yy->__pos >= yy->__limit && !yyrefill(yy)) return 0;\n\ 588 | if (yy->__buf[yy->__pos] != *s)\n\ 589 | {\n\ 590 | yy->__pos= yysav;\n\ 591 | return 0;\n\ 592 | }\n\ 593 | ++s;\n\ 594 | ++yy->__pos;\n\ 595 | }\n\ 596 | return 1;\n\ 597 | }\n\ 598 | \n\ 599 | YY_LOCAL(int) yymatchClass(yycontext *yy, unsigned char *bits)\n\ 600 | {\n\ 601 | int c;\n\ 602 | if (yy->__pos >= yy->__limit && !yyrefill(yy)) return 0;\n\ 603 | c= (unsigned char)yy->__buf[yy->__pos];\n\ 604 | if (bits[c >> 3] & (1 << (c & 7)))\n\ 605 | {\n\ 606 | ++yy->__pos;\n\ 607 | yyprintf((stderr, \" ok yymatchClass @ %s\\n\", yy->__buf+yy->__pos));\n\ 608 | return 1;\n\ 609 | }\n\ 610 | yyprintf((stderr, \" fail yymatchClass @ %s\\n\", yy->__buf+yy->__pos));\n\ 611 | return 0;\n\ 612 | }\n\ 613 | \n\ 614 | YY_LOCAL(void) yyDo(yycontext *yy, yyaction action, int begin, int end)\n\ 615 | {\n\ 616 | while (yy->__thunkpos >= yy->__thunkslen)\n\ 617 | {\n\ 618 | yy->__thunkslen *= 2;\n\ 619 | yy->__thunks= (yythunk *)YY_REALLOC(yy, yy->__thunks, sizeof(yythunk) * yy->__thunkslen);\n\ 620 | }\n\ 621 | yy->__thunks[yy->__thunkpos].begin= begin;\n\ 622 | yy->__thunks[yy->__thunkpos].end= end;\n\ 623 | yy->__thunks[yy->__thunkpos].action= action;\n\ 624 | ++yy->__thunkpos;\n\ 625 | }\n\ 626 | \n\ 627 | YY_LOCAL(int) yyText(yycontext *yy, int begin, int end)\n\ 628 | {\n\ 629 | int yyleng= end - begin;\n\ 630 | if (yyleng <= 0)\n\ 631 | yyleng= 0;\n\ 632 | else\n\ 633 | {\n\ 634 | while (yy->__textlen < (yyleng + 1))\n\ 635 | {\n\ 636 | yy->__textlen *= 2;\n\ 637 | yy->__text= (char *)YY_REALLOC(yy, yy->__text, yy->__textlen);\n\ 638 | }\n\ 639 | memcpy(yy->__text, yy->__buf + begin, yyleng);\n\ 640 | }\n\ 641 | yy->__text[yyleng]= '\\0';\n\ 642 | return yyleng;\n\ 643 | }\n\ 644 | \n\ 645 | YY_LOCAL(void) yyDone(yycontext *yy, int yythunkpos)\n\ 646 | {\n\ 647 | int pos;\n\ 648 | for (pos= yythunkpos; pos < yy->__thunkpos; ++pos)\n\ 649 | {\n\ 650 | yythunk *thunk= &yy->__thunks[pos];\n\ 651 | int yyleng= thunk->end ? yyText(yy, thunk->begin, thunk->end) : thunk->begin;\n\ 652 | yyprintf((stderr, \"DO [%d] %p %s\\n\", pos, thunk->action, yy->__text));\n\ 653 | thunk->action(yy, yy->__text, yyleng);\n\ 654 | }\n\ 655 | yy->__thunkpos= 0;\n\ 656 | }\n\ 657 | \n\ 658 | YY_LOCAL(void) yyCommit(yycontext *yy)\n\ 659 | {\n\ 660 | if ((yy->__limit -= yy->__pos))\n\ 661 | {\n\ 662 | memmove(yy->__buf, yy->__buf + yy->__pos, yy->__limit);\n\ 663 | }\n\ 664 | yy->__begin -= yy->__pos;\n\ 665 | yy->__end -= yy->__pos;\n\ 666 | yy->__pos= yy->__thunkpos= 0;\n\ 667 | }\n\ 668 | \n\ 669 | YY_LOCAL(int) yyAccept(yycontext *yy, int tp0)\n\ 670 | {\n\ 671 | if (tp0)\n\ 672 | {\n\ 673 | fprintf(stderr, \"accept denied at %d\\n\", tp0);\n\ 674 | return 0;\n\ 675 | }\n\ 676 | else\n\ 677 | {\n\ 678 | yyDone(yy, 0);\n\ 679 | yyCommit(yy);\n\ 680 | }\n\ 681 | return 1;\n\ 682 | }\n\ 683 | \n\ 684 | YY_LOCAL(void) yyPush(yycontext *yy, char *text, int count)\n\ 685 | {\n\ 686 | yy->__val += count;\n\ 687 | while (yy->__valslen <= yy->__val - yy->__vals)\n\ 688 | {\n\ 689 | long offset= yy->__val - yy->__vals;\n\ 690 | yy->__valslen *= 2;\n\ 691 | yy->__vals= (YYSTYPE *)YY_REALLOC(yy, yy->__vals, sizeof(YYSTYPE) * yy->__valslen);\n\ 692 | yy->__val= yy->__vals + offset;\n\ 693 | }\n\ 694 | }\n\ 695 | YY_LOCAL(void) yyPop(yycontext *yy, char *text, int count) { yy->__val -= count; }\n\ 696 | YY_LOCAL(void) yySet(yycontext *yy, char *text, int count) { yy->__val[count]= yy->__; }\n\ 697 | \n\ 698 | #endif /* YY_PART */\n\ 699 | \n\ 700 | #define YYACCEPT yyAccept(yy, yythunkpos0)\n\ 701 | \n\ 702 | #define yyEnter(YY, N) yyPush(YY, 0, N)\n\ 703 | #define yyLeave(YY, N) yyPop (YY, 0, N)\n\ 704 | \n\ 705 | "; 706 | 707 | static char *footer= "\n\ 708 | \n\ 709 | #ifndef YY_PART\n\ 710 | \n\ 711 | typedef int (*yyrule)(yycontext *yy);\n\ 712 | \n\ 713 | YY_PARSE(int) YYPARSEFROM_R(YY_CTX_PARAM_ yyrule yystart)\n\ 714 | {\n\ 715 | int yyok, yythunkpos;\n\ 716 | YYSTYPE *yyval;\n\ 717 | if (!yyctx->__buflen)\n\ 718 | {\n\ 719 | yyctx->__buflen= YY_BUFFER_SIZE;\n\ 720 | yyctx->__buf= (char *)YY_MALLOC(yyctx, yyctx->__buflen);\n\ 721 | yyctx->__textlen= YY_BUFFER_SIZE;\n\ 722 | yyctx->__text= (char *)YY_MALLOC(yyctx, yyctx->__textlen);\n\ 723 | yyctx->__thunkslen= YY_STACK_SIZE;\n\ 724 | yyctx->__thunks= (yythunk *)YY_MALLOC(yyctx, sizeof(yythunk) * yyctx->__thunkslen);\n\ 725 | yyctx->__valslen= YY_STACK_SIZE;\n\ 726 | yyctx->__val= yyctx->__vals= (YYSTYPE *)YY_MALLOC(yyctx, sizeof(YYSTYPE) * yyctx->__valslen);\n\ 727 | yyctx->__begin= yyctx->__end= yyctx->__pos= yyctx->__limit= yyctx->__thunkpos= 0;\n\ 728 | }\n\ 729 | yyctx->__begin= yyctx->__end= yyctx->__pos;\n\ 730 | yythunkpos= yyctx->__thunkpos;\n\ 731 | yyval= yyctx->__val;\n\ 732 | yyok= yystart(yyctx);\n\ 733 | if (yyok) yyDone(yyctx, yythunkpos);\n\ 734 | yyctx->__thunkpos= yythunkpos;\n\ 735 | yyctx->__val= yyval;\n\ 736 | return yyok;\n\ 737 | }\n\ 738 | \n\ 739 | YY_PARSE(int) YYPARSEFROM(YY_CTX_PARAM_ yyrule yystart)\n\ 740 | {\n\ 741 | int yyok;\n\ 742 | yyctx->__thunkpos= 0;\n\ 743 | yyctx->__val= yyctx->__vals;\n\ 744 | yyok= YYPARSEFROM_R(YY_CTX_ARG_ yystart);\n\ 745 | yyCommit(yyctx);\n\ 746 | return yyok;\n\ 747 | }\n\ 748 | \n\ 749 | YY_PARSE(int) YYPARSE(YY_CTX_PARAM)\n\ 750 | {\n\ 751 | return YYPARSEFROM(YY_CTX_ARG_ yy_%s);\n\ 752 | }\n\ 753 | \n\ 754 | YY_PARSE(yycontext *) YYRELEASE(yycontext *yyctx)\n\ 755 | {\n\ 756 | if (yyctx->__buflen)\n\ 757 | {\n\ 758 | yyctx->__buflen= 0;\n\ 759 | YY_FREE(yyctx, yyctx->__buf);\n\ 760 | YY_FREE(yyctx, yyctx->__text);\n\ 761 | YY_FREE(yyctx, yyctx->__thunks);\n\ 762 | YY_FREE(yyctx, yyctx->__vals);\n\ 763 | }\n\ 764 | return yyctx;\n\ 765 | }\n\ 766 | \n\ 767 | #endif\n\ 768 | "; 769 | 770 | void Rule_compile_c_header(void) 771 | { 772 | fprintf(output, "/* A recursive-descent parser generated by peg %d.%d.%d */\n", PEG_MAJOR, PEG_MINOR, PEG_LEVEL); 773 | fprintf(output, "\n"); 774 | fprintf(output, "%s", header); 775 | fprintf(output, "#define YYRULECOUNT %d\n", ruleCount); 776 | } 777 | 778 | int consumesInput(Node *node) 779 | { 780 | if (!node) return 0; 781 | 782 | switch (node->type) 783 | { 784 | case Rule: 785 | { 786 | int result= 0; 787 | if (RuleReached & node->rule.flags) 788 | fprintf(stderr, "possible infinite left recursion in rule '%s'\n", node->rule.name); 789 | else 790 | { 791 | node->rule.flags |= RuleReached; 792 | result= consumesInput(node->rule.expression); 793 | node->rule.flags &= ~RuleReached; 794 | } 795 | return result; 796 | } 797 | break; 798 | 799 | case Dot: return 1; 800 | case Name: return consumesInput(node->name.rule); 801 | case Character: 802 | case String: return strlen(node->string.value) > 0; 803 | case Class: return 1; 804 | case Action: return 0; 805 | case Inline: return 0; 806 | case Predicate: return 0; 807 | case Error: return consumesInput(node->error.element); 808 | 809 | case Alternate: 810 | { 811 | Node *n; 812 | for (n= node->alternate.first; n; n= n->alternate.next) 813 | if (!consumesInput(n)) 814 | return 0; 815 | } 816 | return 1; 817 | 818 | case Sequence: 819 | { 820 | Node *n; 821 | for (n= node->alternate.first; n; n= n->alternate.next) 822 | if (consumesInput(n)) 823 | return 1; 824 | } 825 | return 0; 826 | 827 | case PeekFor: return 0; 828 | case PeekNot: return 0; 829 | case Query: return 0; 830 | case Star: return 0; 831 | case Plus: return consumesInput(node->plus.element); 832 | 833 | default: 834 | fprintf(stderr, "\nconsumesInput: illegal node type %d\n", node->type); 835 | exit(1); 836 | } 837 | return 0; 838 | } 839 | 840 | 841 | void Rule_compile_c(Node *node, int nolines) 842 | { 843 | Node *n; 844 | 845 | for (n= rules; n; n= n->rule.next) 846 | consumesInput(n); 847 | 848 | fprintf(output, "%s", preamble); 849 | for (n= node; n; n= n->rule.next) { 850 | fprintf(output, "YY_RULE(int) yy_%s(yycontext *yy); /* %d */\n", n->rule.name, n->rule.id); 851 | allocateVariables(n->rule.variables); 852 | } 853 | fprintf(output, "\n"); 854 | for (n= actions; n; n= n->action.list) 855 | { 856 | fprintf(output, "YY_ACTION(void) yy%s(yycontext *yy, char *yytext, int yyleng)\n{\n", n->action.name); 857 | defineVariables(n->action.rule->rule.variables); 858 | fprintf(output, " yyprintf((stderr, \"do yy%s\\n\"));\n", n->action.name); 859 | fprintf(output, " {\n"); 860 | if (!nolines) 861 | fprintf(output, "#line %i\n", n->action.line); 862 | fprintf(output, " %s;\n", n->action.text); 863 | fprintf(output, " }\n"); 864 | undefineVariables(n->action.rule->rule.variables); 865 | fprintf(output, "}\n"); 866 | } 867 | Rule_compile_c2(node); 868 | fprintf(output, footer, start->rule.name); 869 | } 870 | -------------------------------------------------------------------------------- /src/leg.leg: -------------------------------------------------------------------------------- 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: 2023-11-19 12:06:51 by piumarta on zora 19 | 20 | %{ 21 | # include "tree.h" 22 | # include "version.h" 23 | 24 | # include 25 | # include 26 | # include 27 | # include 28 | # include 29 | # include 30 | 31 | typedef struct Header Header; 32 | 33 | struct Header { 34 | int line; 35 | char *text; 36 | Header *next; 37 | }; 38 | 39 | FILE *input= 0; 40 | 41 | int verboseFlag= 0; 42 | int nolinesFlag= 0; 43 | 44 | static int lineNumber= 0; 45 | static int headerLine= 0; 46 | static int actionLine= 0; 47 | static char *fileName= 0; 48 | static int trailerLine= 0; 49 | static char *trailer= 0; 50 | static Header *headers= 0; 51 | 52 | void makeHeader(int line, char *text); 53 | void makeTrailer(int line, char *text); 54 | 55 | void yyerror(char *message); 56 | 57 | # define YY_INPUT(buf, result, max) \ 58 | { \ 59 | int c= getc(input); \ 60 | /* if ('\n' == c || '\r' == c) ++lineNumber; */ \ 61 | result= (EOF == c) ? 0 : (*(buf)= c, 1); \ 62 | } 63 | 64 | # define YY_LOCAL(T) static T 65 | # define YY_RULE(T) static T 66 | %} 67 | 68 | # Hierarchical syntax 69 | 70 | grammar= - ( declaration | definition )+ trailer? end-of-file 71 | 72 | declaration= '%{' { headerLine= lineNumber; } 73 | < ( !'%}' (end-of-line | .) )* > 74 | RPERCENT { makeHeader(headerLine, yytext); } #{YYACCEPT} 75 | 76 | trailer= '%%' { headerLine= lineNumber } 77 | < .* > { makeTrailer(headerLine, yytext); } #{YYACCEPT} 78 | 79 | definition= identifier { if (push(beginRule(findRule(yytext)))->rule.expression) 80 | fprintf(stderr, "rule '%s' redefined\n", yytext); } 81 | EQUAL expression { Node *e= pop(); Rule_setExpression(pop(), e); } 82 | SEMICOLON? #{YYACCEPT} 83 | 84 | expression= sequence (BAR sequence { Node *f= pop(); push(Alternate_append(pop(), f)); } 85 | )* 86 | 87 | sequence= error (error { Node *f= pop(); push(Sequence_append(pop(), f)); } 88 | )* 89 | 90 | error= prefix (TILDE action { push(makeError(pop(), yytext)); } 91 | )? 92 | 93 | prefix= AT action { push(makeInline(yytext)); } 94 | | AND action { push(makePredicate(yytext)); } 95 | | AND suffix { push(makePeekFor(pop())); } 96 | | NOT suffix { push(makePeekNot(pop())); } 97 | | suffix 98 | 99 | suffix= primary (QUESTION { push(makeQuery(pop())); } 100 | | STAR { push(makeStar (pop())); } 101 | | PLUS { push(makePlus (pop())); } 102 | )? 103 | 104 | primary= identifier { push(makeVariable(yytext)); } 105 | COLON identifier !EQUAL { Node *name= makeName(findRule(yytext)); name->name.variable= pop(); push(name); } 106 | | identifier !EQUAL { push(makeName(findRule(yytext))); } 107 | | OPEN expression CLOSE 108 | | literal { push(makeString(yytext)); } 109 | | class { push(makeClass(yytext)); } 110 | | DOT { push(makeDot()); } 111 | | action { push(makeAction(actionLine, yytext)); } 112 | | BEGIN { push(makePredicate("YY_BEGIN")); } 113 | | END { push(makePredicate("YY_END")); } 114 | 115 | # Lexical syntax 116 | 117 | identifier= < [-a-zA-Z_][-a-zA-Z_0-9]* > - 118 | 119 | literal= ['] < ( !['] char )* > ['] - 120 | | ["] < ( !["] char )* > ["] - 121 | 122 | class= '[' < ( !']' range )* > ']' - 123 | 124 | range= char '-' char | char 125 | 126 | char= '\\' [-abefnrtv'"\[\]\\] 127 | | '\\' 'x'[0-9A-Fa-f][0-9A-Fa-f] 128 | | '\\' 'x'[0-9A-Fa-f] 129 | | '\\' [0-3][0-7][0-7] 130 | | '\\' [0-7][0-7]? 131 | | !'\\' . 132 | 133 | action= '{' { actionLine= lineNumber } 134 | < braces* > '}' - 135 | 136 | braces= '{' braces* '}' 137 | | !'}' ( end-of-line | . ) 138 | 139 | EQUAL= '=' - 140 | COLON= ':' - 141 | SEMICOLON= ';' - 142 | BAR= '|' - 143 | AND= '&' - 144 | NOT= '!' - 145 | AT= '@' - 146 | QUESTION= '?' - 147 | STAR= '*' - 148 | PLUS= '+' - 149 | OPEN= '(' - 150 | CLOSE= ')' - 151 | DOT= '.' - 152 | BEGIN= '<' - 153 | END= '>' - 154 | TILDE= '~' - 155 | RPERCENT= '%}' - 156 | 157 | -= (space | comment)* 158 | space= ' ' | '\t' | '\f' | end-of-line 159 | comment= '#' (!end-of-line .)* end-of-line 160 | end-of-line= ( '\r\n' | '\n' | '\r' ) { ++lineNumber } 161 | end-of-file= !. 162 | 163 | %% 164 | 165 | void yyerror(char *message) 166 | { 167 | fprintf(stderr, "%s:%d: %s", fileName, lineNumber, message); 168 | if (yyctx->__text[0]) fprintf(stderr, " near token '%s'", yyctx->__text); 169 | if (yyctx->__pos < yyctx->__limit || !feof(input)) 170 | { 171 | yyctx->__buf[yyctx->__limit]= '\0'; 172 | fprintf(stderr, " before text \""); 173 | while (yyctx->__pos < yyctx->__limit) 174 | { 175 | if ('\n' == yyctx->__buf[yyctx->__pos] || '\r' == yyctx->__buf[yyctx->__pos]) break; 176 | fputc(yyctx->__buf[yyctx->__pos++], stderr); 177 | } 178 | if (yyctx->__pos == yyctx->__limit) 179 | { 180 | int c; 181 | while (EOF != (c= fgetc(input)) && '\n' != c && '\r' != c) 182 | fputc(c, stderr); 183 | } 184 | fputc('\"', stderr); 185 | } 186 | fprintf(stderr, "\n"); 187 | exit(1); 188 | } 189 | 190 | void makeHeader(int line, char *text) 191 | { 192 | Header *header= (Header *)malloc(sizeof(Header)); 193 | header->line= line; 194 | header->text= strdup(text); 195 | header->next= headers; 196 | headers= header; 197 | } 198 | 199 | void makeTrailer(int line, char *text) 200 | { 201 | trailerLine= line; 202 | trailer= strdup(text); 203 | } 204 | 205 | static void version(char *name) 206 | { 207 | printf("%s version %d.%d.%d\n", name, PEG_MAJOR, PEG_MINOR, PEG_LEVEL); 208 | } 209 | 210 | static void usage(char *name) 211 | { 212 | version(name); 213 | fprintf(stderr, "usage: %s [