Compare commits

..
4 Commits
181 changed files with 4604 additions and 12877 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ jobs:
python-version: '3.8'
- name: Setup Java
uses: actions/setup-java@v2
uses: actions/setup-python@v2
with:
distribution: 'adopt'
java-version: '11'
+143 -27
View File
@@ -24,38 +24,89 @@ jobs:
# Linux
- name: linux-gcc-ubsan-ootree
os: ubuntu-latest
generator: Unix Makefiles
build-type: Ubsan
build-dir: .build
cxx-flags: -O2
skeleton: ${{ false }}
- name: linux-gcc-asan-ootree
os: ubuntu-latest
generator: Unix Makefiles
build-type: Asan
build-dir: .build
cxx-flags: -O2
skeleton: ${{ false }}
- name: linux-gcc-debug-ootree-skeleton
os: ubuntu-latest
generator: Unix Makefiles
build-type: Debug
build-dir: .build
cxx-flags: -O2
skeleton: ${{ true }}
- name: linux-gcc-debug-intree-m32-skeleton
os: ubuntu-latest
generator: Unix Makefiles
build-type: Debug
build-dir: .
cxx-flags: -O2 -m32
ld-flags: -m32
skeleton: ${{ true }}
- name: linux-gcc-release-ootree-skeleton
os: ubuntu-latest
generator: Unix Makefiles
build-type: Release
build-dir: .build
skeleton: ${{ true }}
# macOS
- name: macos-clang-debug-ootree-skeleton
os: macos-latest
generator: Unix Makefiles
build-type: Debug
build-dir: .build
cxx-flags: -O2
skeleton: ${{ true }}
- name: macos-clang-debug-intree-skeleton
os: macos-latest
generator: Unix Makefiles
build-type: Debug
build-dir: .
cxx-flags: -O2
skeleton: ${{ true }}
- name: macos-clang-release-ootree-skeleton
os: macos-latest
generator: Unix Makefiles
build-type: Release
build-dir: .build
skeleton: ${{ true }}
# Windows
- name: windows-msvc-debug-ootree
os: windows-latest
generator: Visual Studio 16 2019
build-type: Debug
build-dir: .build
skeleton: ${{ false }}
- name: windows-msvc-debug-intree
os: windows-latest
generator: Visual Studio 16 2019
build-type: Debug
build-dir: .
skeleton: ${{ false }}
- name: windows-msvc-release-ootree
os: windows-latest
generator: Visual Studio 16 2019
build-type: Release
build-dir: .build
skeleton: ${{ false }}
steps:
- name: Checkout Code
@@ -76,10 +127,16 @@ jobs:
case ${{ runner.os }} in
Linux*)
sudo apt install gcc-multilib g++-multilib # for -m32
echo "CC=gcc" >> $GITHUB_ENV
echo "CXX=g++" >> $GITHUB_ENV
;;
macOS*)
sudo xcode-select -switch /Applications/Xcode.app
echo "CC=$(xcrun -f clang)" >> $GITHUB_ENV
echo "CXX=$(xcrun -f clang++)" >> $GITHUB_ENV
echo "SDKROOT=$(xcodebuild -version -sdk macosx Path)" >> $GITHUB_ENV
echo "$(xcodebuild -version -sdk macosx Path)" >> $GITHUB_PATH
;;
Windows*)
@@ -101,49 +158,108 @@ jobs:
python -m pip install --upgrade pip
python -m pip install docutils pygments
- name: Check Available Configure Presets
run: cmake --list-presets
- name: Prepare Configure Command
id: configure-command
run: |
# Common CMake arguments
args=( -S . -B ${{ matrix.build-dir }} )
# Generator's specific stuff.
args+=( -G "${{ matrix.generator }}" )
case "${{ matrix.generator }}" in
'Visual Studio'*)
args+=( -A x64 )
;;
*)
# CMAKE_BUILD_TYPE is not used by multi-config build
# types (e.g Visual Studio) at the configure time
# thus we add it only for single-config build types
args+=( -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} )
;;
esac
# CFLAGS, CXXFLAGS, LDFLAGS
args+=( -DCMAKE_C_FLAGS="${{ matrix.cxx-flags }}" )
args+=( -DCMAKE_CXX_FLAGS="${{ matrix.cxx-flags }}" )
args+=( -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.ld-flags }}" )
args+=( -DCMAKE_SHARED_LINKER_FLAGS="${{ matrix.ld-flags }}" )
# Quote each argument to prevent word split.
echo "::set-output name=cmake::$(printf " '%s'" "${args[@]}")"
- name: Fast Configure
run: cmake --preset=${{ matrix.name }}-fast
run: |
# Read prepared command into an array
args=( ${{ steps.configure-command.outputs.cmake }} )
# Amend Build Options
args+=( -DCMAKE_INSTALL_PREFIX="$(pwd)/install" )
# Disable some defaults for now to speed up the build as
# they are not necessary in a minimal installation
args+=( -DRE2C_BUILD_RE2GO=OFF )
# Print the resulting command line for debugging purposes
printf "cmake" && printf " '%s'" "${args[@]}" && printf "\n"
# Run CMake, pass quoted arguments to prevent word split.
printf " '%s'" "${args[@]}" | xargs cmake
- name: Fast Build
run: cmake --build --preset=${{ matrix.name }}-fast
run: cmake --build ${{ matrix.build-dir }} --config ${{ matrix.build-type }}
- name: Install
run: cmake --build --preset=${{ matrix.name }}-fast --target install
run: |
cmake --build ${{ matrix.build-dir }} --config ${{ matrix.build-type }} --target install
echo -e "Install tree:\n$(find install | sed 's/^/-- /')"
- name: Minimal Install Test
working-directory: ./install/bin
run: ./re2c --version
- name: Full Configure
run: cmake --preset=${{ matrix.name }}-full
run: |
# Read prepared command into an array
args=( ${{ steps.configure-command.outputs.cmake }} )
# Amend Build Options
args+=( -DCMAKE_INSTALL_PREFIX="$(pwd)/install-2" -DRE2C_BUILD_RE2GO=ON -DRE2C_BUILD_LIBS=ON )
args+=( -DRE2C_REBUILD_LEXERS=ON -DRE2C_FOR_BUILD="$(pwd)/install/bin/re2c" )
# Windows does not have a native 'man' and 'sed' commands.
# Disabled until this https://github.com/skvadrik/re2c/issues/327
# will be implemented
case ${{ runner.os }} in
Windows*)
args+=( -DRE2C_REBUILD_DOCS=OFF )
;;
*)
args+=( -DRE2C_REBUILD_DOCS=ON )
;;
esac
# Print the resulting command line for debugging purposes
printf "cmake" && printf " '%s'" "${args[@]}" && printf "\n"
# Run CMake, pass quoted arguments to prevent word split.
printf " '%s'" "${args[@]}" | xargs cmake
- name: Full Build
run: |
find src -name '*.re' | xargs touch
cmake --build --preset=${{ matrix.name }}-full
cmake --build ${{ matrix.build-dir }} --config ${{ matrix.build-type }}
- name: Run Main Test Suite
run: cmake --build --preset=${{ matrix.name }}-full --target tests
- name: Get build dir
id: build-info
run: |
if echo "${{ matrix.name }}" | grep -q "ootree"; then
BUILD_DIR="$(pwd)/.build/${{ matrix.name }}-full"
else
BUILD_DIR="$(pwd)"
fi
echo "::set-output name=BUILD_DIR::$BUILD_DIR"
- name: Run Skeleton Tests
if: "contains(matrix.name, 'skeleton')"
- name: Test
# Remove the following line after fix Windows tests
working-directory: ${{ steps.build-info.outputs.BUILD_DIR }}
run: python run_tests.py --skeleton
working-directory: ${{ matrix.build-dir }}
run: |
# main test suite
cmake --build . --target check
# skeleton tests (if enabled)
if [[ "x${{ matrix.skeleton }}" == "xtrue" ]] ; then
python run_tests.py --skeleton
fi
- name: Archive test artifacts
# Run this step only if tests failed (otherwise there is nothing to upload).
@@ -154,7 +270,7 @@ jobs:
# use a different name per job.
name: test-${{ matrix.name }}
# Tests run in a temporary directory that has a name test_<timestamp>.
path: ${{ steps.build-info.outputs.BUILD_DIR }}/test_[0-9]*
path: ${{ matrix.build-dir }}/test_[0-9]*
# Artifacts are retained for 90 days by default.
# In fact, we don't need such long period.
# In fact we don't need such long period.
retention-days: 30
-3
View File
@@ -12,9 +12,6 @@
/test_*
/.build*
# Ignore user defined CMake presets
CMakeUserPresets.json
# The files autogenerated by automake.
Makefile.in
aclocal.m4
+30 -20
View File
@@ -1,5 +1,9 @@
language: cpp
os:
- linux
- freebsd
# use Ubuntu 20.04 (Focal Fossa) that defaults to Python 3
dist: focal
@@ -10,25 +14,35 @@ compiler:
- gcc
- clang
# preinstalled packages
addons:
apt:
packages:
- bison
- python3-docutils
before_install:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then apt install bison python3-docutils ; fi
- if [ "$TRAVIS_OS_NAME" = "freebsd" ]; then pkg install textproc/py-docutils; fi
# configurations: cmake/autotools, in-tree/out-of-tree, release/debug, etc.
env:
- CMAKE=no BUILD_DIR=. CONFIG_DIR=. COMMON_FLAGS="-O2 -g"
- CMAKE=no BUILD_DIR=.build CONFIG_DIR=.. CONFIG_FLAGS="--enable-debug" COMMON_FLAGS="-O2 -g"
- CMAKE=yes BUILD_DIR=. CONFIG_DIR=. BUILD_TYPE=Debug COMMON_FLAGS="-O2 -g"
- CMAKE=yes BUILD_DIR=.build CONFIG_DIR=.. BUILD_TYPE=Debug COMMON_FLAGS="-O2 -g" SKELETON=yes
- CMAKE=no BUILD_DIR=. CONFIG_DIR=. COMMON_FLAGS="-O2 -g"
- CMAKE=no BUILD_DIR=.build CONFIG_DIR=.. COMMON_FLAGS="-O2 -g"
- CMAKE=yes BUILD_DIR=. CONFIG_DIR=. BUILD_TYPE=Debug
- CMAKE=yes BUILD_DIR=.build CONFIG_DIR=.. BUILD_TYPE=Release
- CMAKE=yes BUILD_DIR=.build CONFIG_DIR=.. BUILD_TYPE=Debug COMMON_FLAGS="-O2 -g -fsanitize=address"
- CMAKE=yes BUILD_DIR=.build CONFIG_DIR=.. BUILD_TYPE=Debug COMMON_FLAGS="-O2 -g -fsanitize=undefined"
- CMAKE=yes BUILD_DIR=. CONFIG_DIR=. BUILD_TYPE=Asan
- CMAKE=yes BUILD_DIR=.build CONFIG_DIR=.. BUILD_TYPE=Ubsan
jobs:
exclude:
- os: freebsd
env: BUILD_TYPE=Asan
- os: freebsd
env: BUILD_TYPE=Ubsan
script:
- |
function ncpus() {
if [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
sysctl -n hw.ncpu
else
nproc
fi
}
function run_cmake() {
cmake \
-B . -S ${CONFIG_DIR} \
@@ -41,7 +55,6 @@ script:
}
function run_configure() {
${CONFIG_DIR}/configure \
${CONFIG_FLAGS} \
CFLAGS="${COMMON_FLAGS}" \
CXXFLAGS="${COMMON_FLAGS}" \
LDFLAGS="${COMMON_FLAGS}" \
@@ -56,7 +69,7 @@ script:
mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
run_configure --prefix="$(pwd)/install"
fi
- make -j$(nproc)
- make -j$(ncpus)
- make install
- |
if [ x${CMAKE} = "xyes" ]; then
@@ -75,10 +88,7 @@ script:
RE2C_FOR_BUILD="$(pwd)/install/bin/re2c"
fi
- find ${CONFIG_DIR}/src -name '*.re' | xargs touch
- make -j$(nproc)
- make -j$(ncpus)
- |
if [ x${SKELETON} = "xyes" ]; then
./run_tests.py --skeleton
else
make -j$(nproc) check VERBOSE=1
fi
make -j$(ncpus) check VERBOSE=1
./run_tests.py --skeleton
-39
View File
@@ -1,45 +1,6 @@
Changelog
=========
----
2.2x
----
2.2 (2021-08-01)
~~~~~~~~~~~~~~~~
- Added named blocks and block lists in directives.
- Added local blocks ``/*!local:re2c ... */``.
- Added in-block ``!include`` directive.
- Added in-block ``!use`` directive.
- Allowed reusable blocks without ``-r --reusable`` option.
- Allowed customizing the generated code with configurations for directives
``max:re2c``, ``maxnmatch:re2c``, ``stags:re2c``, ``mtags:re2c`` and
``types:re2c`` (see directive descriptions for details).
- Forbid arbitrary text at the end of ``max:re2c`` directive. This may break
backwards compatibility, although it is unlikely that this was used by anyone.
The change was necessary in order to allow customization of the generated code
with configurations.
- Deprecated configurations ``flags:i``, ``flags:no-debug-info`` in favour of
the global options ``-i``, ``--no-debug-info``.
- Reimplemented re2c test runner in Python (thanks to
`Serghei Iakovlev <https://github.com/sergeyklay>`_). Improved integration
with GitHub Actions.
- Changes in the experimental libre2c library: added new algorithms that
construct t-string or extract submatch on all repetitions; added TDFA
benchmark written in Java by Angelo Borsotti.
- Updated documentation.
----
2.1x
----
+2 -5
View File
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.12)
project(re2c VERSION 2.2 HOMEPAGE_URL "https://re2c.org/")
project(re2c VERSION 2.1.1 HOMEPAGE_URL "https://re2c.org/")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
@@ -232,6 +232,7 @@ re2c_bootstrap_parser("src/parse/parser.ypp" "src/parse/parser.cc" "src/parse/pa
# docs
set(re2c_docs_sources
"${re2c_manpage_source}"
"doc/manual/api/api.rst_"
"doc/manual/api/interface.rst_"
"doc/manual/conditions/conditions.rst_"
"doc/manual/configurations/configurations.rst_"
@@ -261,10 +262,6 @@ set(re2c_docs_sources
"doc/manual/submatch/submatch_example_stags_fill.rst_"
"doc/manual/submatch/submatch.rst_"
"doc/manual/syntax/syntax.rst_"
"doc/manual/syntax/api1.rst_"
"doc/manual/syntax/api2_c.rst_"
"doc/manual/syntax/api2_go.rst_"
"doc/manual/syntax/api3.rst_"
"doc/manual/warnings/warnings_general.rst_"
"doc/manual/warnings/warnings_list.rst_"
"examples/c/01_basic.re"
-471
View File
@@ -1,471 +0,0 @@
{
"version": 3,
"cmakeMinimumRequired": {
"major": 3,
"minor": 21,
"patch": 1
},
"configurePresets": [
{
"name": "default-full-configuration",
"hidden": true,
"installDir": "${sourceDir}/install-2",
"cacheVariables": {
"RE2C_BUILD_RE2GO": true,
"RE2C_BUILD_LIBS": true,
"RE2C_REBUILD_LEXERS": true,
"RE2C_REBUILD_DOCS": true,
"RE2C_FOR_BUILD": "${sourceDir}/install/bin/re2c"
}
},
{
"name": "linux-config-base",
"hidden": true,
"generator": "Unix Makefiles",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++"
}
},
{
"name": "linux-gcc-ubsan-ootree-fast",
"displayName": "Linux x86_64: GCC / Ubsan / Out of tree (fast)",
"inherits": "linux-config-base",
"binaryDir": "${sourceDir}/.build/${presetName}",
"installDir": "${sourceDir}/install",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Ubsan",
"CMAKE_C_FLAGS": "-O2",
"CMAKE_CXX_FLAGS": "-O2",
"RE2C_BUILD_RE2GO": false
}
},
{
"name": "linux-gcc-ubsan-ootree-full",
"displayName": "Linux x86_64: GCC / Ubsan / Out of tree (full)",
"inherits": ["default-full-configuration", "linux-gcc-ubsan-ootree-fast"]
},
{
"name": "linux-gcc-asan-ootree-fast",
"displayName": "Linux x86_64: GCC / Asan / Out of tree (fast)",
"inherits": "linux-config-base",
"binaryDir": "${sourceDir}/.build/${presetName}",
"installDir": "${sourceDir}/install",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Asan",
"CMAKE_C_FLAGS": "-O2",
"CMAKE_CXX_FLAGS": "-O2",
"RE2C_BUILD_RE2GO": false
}
},
{
"name": "linux-gcc-asan-ootree-full",
"displayName": "Linux x86_64: GCC / Asan / Out of tree (full)",
"inherits": ["default-full-configuration", "linux-gcc-asan-ootree-fast"]
},
{
"name": "linux-gcc-debug-ootree-skeleton-fast",
"displayName": "Linux x86_64: GCC / Debug / Skeleton / Out of tree (fast)",
"inherits": "linux-config-base",
"binaryDir": "${sourceDir}/.build/${presetName}",
"installDir": "${sourceDir}/install",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_C_FLAGS": "-O2",
"CMAKE_CXX_FLAGS": "-O2",
"RE2C_BUILD_RE2GO": false
}
},
{
"name": "linux-gcc-debug-ootree-skeleton-full",
"displayName": "Linux x86_64: GCC / Debug / Skeleton / Out of tree (full)",
"inherits": ["default-full-configuration", "linux-gcc-debug-ootree-skeleton-fast"]
},
{
"name": "linux-gcc-debug-intree-m32-skeleton-fast",
"displayName": "Linux x86: GCC / Debug / Skeleton / In tree (fast)",
"inherits": "linux-config-base",
"binaryDir": "${sourceDir}",
"installDir": "${sourceDir}/install",
"architecture": {
"value": "x86",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_C_FLAGS": "-O2 -m32",
"CMAKE_CXX_FLAGS": "-O2 -m32",
"CMAKE_EXE_LINKER_FLAGS": "-m32",
"CMAKE_SHARED_LINKER_FLAGS": "-m32",
"RE2C_BUILD_RE2GO": false
}
},
{
"name": "linux-gcc-debug-intree-m32-skeleton-full",
"displayName": "Linux x86: GCC / Debug / Skeleton / In tree (full)",
"inherits": ["default-full-configuration", "linux-gcc-debug-intree-m32-skeleton-fast"]
},
{
"name": "linux-gcc-release-ootree-skeleton-fast",
"displayName": "Linux x86_64: GCC / Release / Skeleton / Out of tree (fast)",
"inherits": "linux-config-base",
"binaryDir": "${sourceDir}/.build/${presetName}",
"installDir": "${sourceDir}/install",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"RE2C_BUILD_RE2GO": false
}
},
{
"name": "linux-gcc-release-ootree-skeleton-full",
"displayName": "Linux x86_64: GCC / Release / Skeleton / Out of tree (full)",
"inherits": ["default-full-configuration", "linux-gcc-release-ootree-skeleton-fast"]
},
{
"name": "macos-config-base",
"hidden": true,
"generator": "Unix Makefiles",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++"
}
},
{
"name": "macos-clang-debug-ootree-skeleton-fast",
"displayName": "macOS x86_64: Clang / Debug / Skeleton / Out of tree (fast)",
"inherits": "macos-config-base",
"binaryDir": "${sourceDir}/.build/${presetName}",
"installDir": "${sourceDir}/install",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_C_FLAGS": "-O2",
"CMAKE_CXX_FLAGS": "-O2",
"RE2C_BUILD_RE2GO": false
}
},
{
"name": "macos-clang-debug-ootree-skeleton-full",
"displayName": "macOS x86_64: Clang / Debug / Skeleton / Out of tree (full)",
"inherits": ["default-full-configuration", "macos-clang-debug-ootree-skeleton-fast"]
},
{
"name": "macos-clang-debug-intree-skeleton-fast",
"displayName": "macOS x86_64: Clang / Debug / Skeleton / In tree (fast)",
"inherits": "macos-config-base",
"binaryDir": "${sourceDir}",
"installDir": "${sourceDir}/install",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_C_FLAGS": "-O2",
"CMAKE_CXX_FLAGS": "-O2",
"RE2C_BUILD_RE2GO": false
}
},
{
"name": "macos-clang-debug-intree-skeleton-full",
"displayName": "macOS x86_64: Clang / Debug / Skeleton / In tree (full)",
"inherits": ["default-full-configuration", "macos-clang-debug-intree-skeleton-fast"]
},
{
"name": "macos-clang-release-ootree-skeleton-fast",
"displayName": "macOS x86_64: CLang / Release / Skeleton / Out of tree (fast)",
"inherits": "macos-config-base",
"binaryDir": "${sourceDir}/.build/${presetName}",
"installDir": "${sourceDir}/install",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"RE2C_BUILD_RE2GO": false
}
},
{
"name": "macos-clang-release-ootree-skeleton-full",
"displayName": "macOS x86_64: CLang / Release / Skeleton / Out of tree (full)",
"inherits": ["default-full-configuration", "macos-clang-release-ootree-skeleton-fast"]
},
{
"name": "windows-config-base",
"hidden": true,
"generator": "Visual Studio 16 2019",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_C_COMPILER": "cl",
"CMAKE_CXX_COMPILER": "cl"
}
},
{
"name": "windows-msvc-debug-ootree-fast",
"displayName": "Windows x86_64: MSVC / Debug / Out of tree (fast)",
"inherits": "windows-config-base",
"binaryDir": "${sourceDir}/.build/${presetName}",
"installDir": "${sourceDir}/install",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"RE2C_BUILD_RE2GO": false
}
},
{
"name": "windows-msvc-debug-ootree-full",
"displayName": "Windows x86_64: MSVC / Debug / Out of tree (full)",
"inherits": ["default-full-configuration", "windows-msvc-debug-ootree-fast"],
"cacheVariables": {
"RE2C_REBUILD_DOCS": false
}
},
{
"name": "windows-msvc-debug-intree-fast",
"displayName": "Windows x86_64: MSVC / Debug / In tree (fast)",
"inherits": "windows-config-base",
"binaryDir": "${sourceDir}",
"installDir": "${sourceDir}/install",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"RE2C_BUILD_RE2GO": false
}
},
{
"name": "windows-msvc-debug-intree-full",
"displayName": "Windows x86_64: MSVC / Debug / In tree (full)",
"inherits": ["default-full-configuration", "windows-msvc-debug-intree-fast"],
"cacheVariables": {
"RE2C_REBUILD_DOCS": false
}
},
{
"name": "windows-msvc-release-ootree-fast",
"displayName": "Windows x86_64: MSVC / Release / Out of tree (fast)",
"inherits": "windows-config-base",
"binaryDir": "${sourceDir}/.build/${presetName}",
"installDir": "${sourceDir}/install",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"RE2C_BUILD_RE2GO": false
}
},
{
"name": "windows-msvc-release-ootree-full",
"displayName": "Windows x86_64: MSVC / Release / Out of tree (full)",
"inherits": ["default-full-configuration", "windows-msvc-release-ootree-fast"],
"cacheVariables": {
"RE2C_REBUILD_DOCS": false
}
}
],
"buildPresets": [
{
"name": "linux-build-base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
}
},
{
"name": "linux-gcc-ubsan-ootree-fast",
"displayName": "Linux x86_64: GCC / Ubsan / Out of tree (fast)",
"configurePreset": "linux-gcc-ubsan-ootree-fast",
"inherits": "linux-build-base",
"configuration": "Ubsan"
},
{
"name": "linux-gcc-ubsan-ootree-full",
"displayName": "Linux x86_64: GCC / Ubsan / Out of tree (full)",
"configurePreset": "linux-gcc-ubsan-ootree-full",
"inherits": "linux-build-base",
"configuration": "Ubsan"
},
{
"name": "linux-gcc-asan-ootree-fast",
"displayName": "Linux x86_64: GCC / Asan / Out of tree (fast)",
"configurePreset": "linux-gcc-asan-ootree-fast",
"inherits": "linux-build-base",
"configuration": "Asan"
},
{
"name": "linux-gcc-asan-ootree-full",
"displayName": "Linux x86_64: GCC / Asan / Out of tree (full)",
"configurePreset": "linux-gcc-asan-ootree-full",
"inherits": "linux-build-base",
"configuration": "Asan"
},
{
"name": "linux-gcc-debug-ootree-skeleton-fast",
"displayName": "Linux x86_64: GCC / Debug / Skeleton / Out of tree (fast)",
"configurePreset": "linux-gcc-debug-ootree-skeleton-fast",
"inherits": "linux-build-base",
"configuration": "Debug"
},
{
"name": "linux-gcc-debug-ootree-skeleton-full",
"displayName": "Linux x86_64: GCC / Debug / Skeleton / Out of tree (full)",
"configurePreset": "linux-gcc-debug-ootree-skeleton-full",
"inherits": "linux-build-base",
"configuration": "Debug"
},
{
"name": "linux-gcc-debug-intree-m32-skeleton-fast",
"displayName": "Linux x86: GCC / Debug / Skeleton / In tree (fast)",
"configurePreset": "linux-gcc-debug-intree-m32-skeleton-fast",
"inherits": "linux-build-base",
"configuration": "Debug"
},
{
"name": "linux-gcc-debug-intree-m32-skeleton-full",
"displayName": "Linux x86: GCC / Debug / Skeleton / In tree (full)",
"configurePreset": "linux-gcc-debug-intree-m32-skeleton-full",
"inherits": "linux-build-base",
"configuration": "Debug"
},
{
"name": "linux-gcc-release-ootree-skeleton-fast",
"displayName": "Linux x86_64: GCC / Release / Skeleton / Out of tree (fast)",
"configurePreset": "linux-gcc-release-ootree-skeleton-fast",
"inherits": "linux-build-base",
"configuration": "Release"
},
{
"name": "linux-gcc-release-ootree-skeleton-full",
"displayName": "Linux x86_64: GCC / Release / Skeleton / Out of tree (full)",
"configurePreset": "linux-gcc-release-ootree-skeleton-full",
"inherits": "linux-build-base",
"configuration": "Release"
},
{
"name": "macos-build-base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
}
},
{
"name": "macos-clang-debug-ootree-skeleton-fast",
"displayName": "macOS x86_64: Clang / Debug / Skeleton / Out of tree (fast)",
"configurePreset": "macos-clang-debug-ootree-skeleton-fast",
"inherits": "macos-build-base",
"configuration": "Debug"
},
{
"name": "macos-clang-debug-ootree-skeleton-full",
"displayName": "macOS x86_64: Clang / Debug / Skeleton / Out of tree (full)",
"configurePreset": "macos-clang-debug-ootree-skeleton-full",
"inherits": "macos-build-base",
"configuration": "Debug"
},
{
"name": "macos-clang-debug-intree-skeleton-fast",
"displayName": "macOS x86_64: Clang / Debug / Skeleton / In tree (fast)",
"configurePreset": "macos-clang-debug-intree-skeleton-fast",
"inherits": "macos-build-base",
"configuration": "Debug"
},
{
"name": "macos-clang-debug-intree-skeleton-full",
"displayName": "macOS x86_64: Clang / Debug / Skeleton / In tree (full)",
"configurePreset": "macos-clang-debug-intree-skeleton-full",
"inherits": "macos-build-base",
"configuration": "Debug"
},
{
"name": "macos-clang-release-ootree-skeleton-fast",
"displayName": "macOS x86_64: CLang / Release / Skeleton / Out of tree (fast)",
"configurePreset": "macos-clang-release-ootree-skeleton-fast",
"inherits": "macos-build-base",
"configuration": "Release"
},
{
"name": "macos-clang-release-ootree-skeleton-full",
"displayName": "macOS x86_64: CLang / Release / Skeleton / Out of tree (full)",
"configurePreset": "macos-clang-release-ootree-skeleton-full",
"inherits": "macos-build-base",
"configuration": "Release"
},
{
"name": "windows-build-base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "windows-msvc-debug-ootree-fast",
"displayName": "Windows x86_64: MSVC / Debug / Out of tree (fast)",
"configurePreset": "windows-msvc-debug-ootree-fast",
"inherits": "windows-build-base",
"configuration": "Debug"
},
{
"name": "windows-msvc-debug-ootree-full",
"displayName": "Windows x86_64: MSVC / Debug / Out of tree (full)",
"configurePreset": "windows-msvc-debug-ootree-full",
"inherits": "windows-build-base",
"configuration": "Debug"
},
{
"name": "windows-msvc-debug-intree-fast",
"displayName": "Windows x86_64: MSVC / Debug / In tree (fast)",
"configurePreset": "windows-msvc-debug-intree-fast",
"inherits": "windows-build-base",
"configuration": "Debug"
},
{
"name": "windows-msvc-debug-intree-full",
"displayName": "Windows x86_64: MSVC / Debug / In tree (full)",
"configurePreset": "windows-msvc-debug-intree-full",
"inherits": "windows-build-base",
"configuration": "Debug"
},
{
"name": "windows-msvc-release-ootree-fast",
"displayName": "Windows x86_64: MSVC / Release / Out of tree (fast)",
"configurePreset": "windows-msvc-release-ootree-fast",
"inherits": "windows-build-base",
"configuration": "Release"
},
{
"name": "windows-msvc-release-ootree-full",
"displayName": "Windows x86_64: MSVC / Release / Out of tree (full)",
"configurePreset": "windows-msvc-release-ootree-full",
"inherits": "windows-build-base",
"configuration": "Release"
}
]
}
+1 -4
View File
@@ -215,6 +215,7 @@ re2c_CUSTOM = \
# docs
re2c_SRC_DOC = doc/manpage.rst
re2c_SRC_DOC_EXT = \
doc/manual/api/api.rst_ \
doc/manual/api/interface.rst_ \
doc/manual/conditions/conditions.rst_ \
doc/manual/configurations/configurations.rst_ \
@@ -244,10 +245,6 @@ re2c_SRC_DOC_EXT = \
doc/manual/submatch/submatch_example_stags_fill.rst_ \
doc/manual/submatch/submatch.rst_ \
doc/manual/syntax/syntax.rst_ \
doc/manual/syntax/api1.rst_ \
doc/manual/syntax/api2_c.rst_ \
doc/manual/syntax/api2_go.rst_ \
doc/manual/syntax/api3.rst_ \
doc/manual/warnings/warnings_general.rst_ \
doc/manual/warnings/warnings_list.rst_ \
examples/c/01_basic.re \
+1 -1
View File
@@ -1,5 +1,5 @@
bench_submatch_dfa_jit_CXXFLAGS = $(AM_CXXFLAGS) -std=c++11 -O3 -I $(top_srcdir)
bench_submatch_dfa_jit_LDFLAGS = $(LDFLAGS_RE2) -lbenchmark -lpthread
bench_submatch_dfa_jit_LDFLAGS = $(LDFLAGS_RE2) -lbenchmark
bench_submatch_dfa_jit_LDADD = $(top_builddir)/libre2c.la
noinst_PROGRAMS = bench_submatch_dfa_jit
+1 -1
View File
@@ -1,5 +1,5 @@
bench_submatch_nfa_CXXFLAGS = $(AM_CXXFLAGS) -std=c++11 -O3 -I $(top_srcdir)
bench_submatch_nfa_LDFLAGS = $(LDFLAGS_RE2) -lbenchmark -lpthread
bench_submatch_nfa_LDFLAGS = $(LDFLAGS_RE2) -lbenchmark
bench_submatch_nfa_LDADD = $(top_builddir)/libre2c.la
noinst_PROGRAMS = bench_submatch_nfa
+365 -457
View File
File diff suppressed because it is too large Load Diff
+366 -464
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+409 -415
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
/* Generated by re2c 2.2 on Mon Nov 22 21:59:42 2021 */
/* Generated by re2c 2.1.1 on Fri Jul 16 08:52:38 2021 */
#ifndef _RE2C_PARSE_LEX_
#define _RE2C_PARSE_LEX_
File diff suppressed because it is too large Load Diff
+10 -21
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -e
@@ -14,33 +14,22 @@ autoreconf -i -W all
# try to be portable on various MAKEs
for make_prog in make bmake
do
rm -rf "$builddir"
mkdir "$builddir"
cd "$builddir"
# stage 1
mkdir stage1
../configure --prefix "$(pwd)/stage1" \
&& $make_prog \
&& $make_prog install
# stage 2
rm -rf $builddir
mkdir $builddir
cd $builddir
# 'make' implies 'make docs'; running both in parallel may cause data races
# configure without --enable-debug, this is the release binary
../configure \
--enable-docs \
--enable-libs \
--enable-lexers RE2C_FOR_BUILD="$(pwd)/stage1/bin/re2c" \
&& $make_prog bootstrap -j"$(nproc)" \
&& $make_prog distcheck -j"$(nproc)"
../configure --enable-docs --enable-libs \
&& $make_prog bootstrap -j$(nproc) \
&& $make_prog distcheck -j$(nproc)
cd ..
done
# test that the release tarball builds with CMake
cd "$builddir"
cd $builddir
tarball=$(find . -name 're2c-*.tar.xz')
test -f "$tarball" && tar -xf "$tarball" \
|| { echo "*** failed to extract tarball ***" && exit 1; }
cd "${tarball%.tar.xz}" && cmake . && make -j"$(nproc)" && cd .. \
|| { echo "*** failed to find tarball ***" && exit 1; }
cd "${tarball%.tar.xz}" && cmake . && make -j$(nproc) && cd .. \
|| { echo "*** failed to build with cmake ***" && exit 1; }
cd ..
-3
View File
@@ -9,11 +9,9 @@ lang="$3"
case $lang in
c) ext=h
lang_name=C
disclaimer=
;;
go) ext=go
lang_name=Go
disclaimer="Note: This manual includes examples for Go, but it refers to re2c (rather than re2go) as the name of the program in general."
;;
*) echo "*** $0: unknown lang: $lang"
@@ -22,7 +20,6 @@ case $lang in
esac
LANG=C sed \
-e "s/RE2C_LANG_NAME/$lang_name/g" \
-e "s/RE2C_LANG/$lang/g" \
-e "s/RE2C_HEADER_EXT/$ext/g" \
-e "s/RE2C_DISCLAIMER/$disclaimer/g" \
-4
View File
@@ -1,10 +1,8 @@
function(re2c_gen_manpage source target bootstrap lang)
if(RE2C_REBUILD_DOCS)
get_filename_component(targetdir "${target}" DIRECTORY)
set(source_l "${source}.${lang}")
add_custom_command(
OUTPUT "${target}"
COMMAND "${CMAKE_COMMAND}" -E make_directory ${targetdir}
COMMAND "${re2c_splitman}" "${source}" "${source_l}" "${lang}"
COMMAND "${RST2MAN}" --tab-width=4 "${source_l}" "${target}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${target}" "${bootstrap}"
@@ -25,10 +23,8 @@ endfunction()
function(re2c_gen_help source target bootstrap)
if(RE2C_REBUILD_DOCS)
get_filename_component(targetdir "${target}" DIRECTORY)
add_custom_command(
OUTPUT "${target}"
COMMAND "${CMAKE_COMMAND}" -E make_directory ${targetdir}
COMMAND "${RST2MAN}" "${source}" "${target}.1"
COMMAND "${re2c_genhelp}" "${target}.1" "${target}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${target}" "${bootstrap}"
+1 -1
View File
@@ -1,4 +1,4 @@
AC_INIT([re2c],[2.2],[re2c-general@lists.sourceforge.net])
AC_INIT([re2c],[2.1.1],[re2c-general@lists.sourceforge.net])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([foreign subdir-objects dist-xz dist-lzip no-dist-gzip])
AM_SILENT_RULES([yes])
+36 -26
View File
@@ -2,9 +2,9 @@
re2c
++++
================================================
generate fast lexical analyzers for C/C++ and Go
================================================
===================================
compile regular expressions to code
===================================
:Manual section: 1
@@ -15,55 +15,65 @@ SYNOPSIS
``re2go [OPTIONS] INPUT [-o OUTPUT]``
DESCRIPTION
===========
re2c is a tool for generating fast lexical analyzers for C, C++ and Go.
RE2C_DISCLAIMER
Introduction
============
Syntax
======
.. include:: @top_srcdir@/doc/manual/syntax/syntax.rst_
.. include:: @top_srcdir@/doc/manual/syntax/api1.rst_
.. include:: @top_srcdir@/doc/manual/syntax/api2_RE2C_LANG.rst_
.. include:: @top_srcdir@/doc/manual/syntax/api3.rst_
Example
EXAMPLE
=======
Here is a simple re2c program:
Input file
----------
.. include:: @top_srcdir@/examples/RE2C_LANG/01_basic.re
:literal:
:code: RE2C_LANG
The generated code looks like this:
Output file
-----------
.. include:: @top_srcdir@/examples/RE2C_LANG/01_basic.RE2C_LANG
:literal:
:code: RE2C_LANG
Command-line options
====================
Command-line interface consists of options and warnings.
Some of the options have corresponding `configurations`_,
others are global and cannot be changed after re2c starts reading the input file.
Debug options generally require building re2c in debug configuration.
Internal options are useful for experimenting with the algorithms used in re2c.
Warnings can be invividually enabled, disabled and turned into an error.
Options
=======
.. include:: @top_srcdir@/doc/manual/options/options.rst_
Debug options
-------------
.. include:: @top_srcdir@/doc/manual/options/debug.rst_
Internal options
----------------
.. include:: @top_srcdir@/doc/manual/options/internal.rst_
Warnings
--------
.. include:: @top_srcdir@/doc/manual/warnings/warnings_general.rst_
.. include:: @top_srcdir@/doc/manual/warnings/warnings_list.rst_
Blocks and directives
=====================
.. include:: @top_srcdir@/doc/manual/directives/directives.rst_
Program interface
=================
.. include:: @top_srcdir@/doc/manual/api/api.rst_
Interface primitives
====================
API primitives
--------------
.. include:: @top_srcdir@/doc/manual/api/interface.rst_
Directives
----------
.. include:: @top_srcdir@/doc/manual/directives/directives.rst_
Configurations
==============
--------------
.. include:: @top_srcdir@/doc/manual/configurations/configurations.rst_
Regular expressions
+92
View File
@@ -0,0 +1,92 @@
Re2c has a flexible interface that gives the user both the freedom and the responsibility
to define how the generated code interacts with the outer program.
There are two major options:
- **Pointer API**.
It is also called "default API", since it was historically the first, and for a long time the only one.
This is a more restricted API based on C pointer arithmetics.
It consists of pointer-like primitives ``YYCURSOR``, ``YYMARKER``,
``YYCTXMARKER`` and ``YYLIMIT``, which are normally defined as pointers
of type ``YYCTYPE*``.
Pointer API is enabled by default for the C backend,
and it cannot be used with other backends that do not have pointer arithmetics.
|
- **Generic API**.
This is a less restricted API that does not assume pointer semantics.
It consists of primitives
``YYPEEK``,
``YYSKIP``,
``YYBACKUP``,
``YYBACKUPCTX``,
``YYSTAGP``,
``YYSTAGN``,
``YYMTAGP``,
``YYMTAGN``,
``YYRESTORE``,
``YYRESTORECTX``,
``YYRESTORETAG``,
``YYSHIFT``,
``YYSHIFTSTAG``,
``YYSHIFTMTAG`` and
``YYLESSTHAN``.
For the C backend generic API is enabled with ``--input custom`` option or
``re2c:flags:input = custom;`` configuration;
for the Go backend it is enabled by default.
Generic API was added in version 0.14.
It is intentionally designed to give the user as much freedom as possible
in redefining the input model and the semantics of different actions performed
by the generated code. As an example, one can override ``YYPEEK`` to check for
the end of input before reading the input character, or do some logging, etc.
Generic API has two styles:
- **Function-like**.
This style is enabled with ``re2c:api:style = functions;`` configuration,
and it is the default for C backend. In this style API primitives should be
defined as functions or macros with parentheses, accepting the necessary
arguments. For example, in C the default pointer API can be defined in
function-like style generic API as follows:
.. code-block:: cpp
#define YYPEEK() *YYCURSOR
#define YYSKIP() ++YYCURSOR
#define YYBACKUP() YYMARKER = YYCURSOR
#define YYBACKUPCTX() YYCTXMARKER = YYCURSOR
#define YYRESTORE() YYCURSOR = YYMARKER
#define YYRESTORECTX() YYCURSOR = YYCTXMARKER
#define YYRESTORETAG(tag) YYCURSOR = tag
#define YYLESSTHAN(len) YYLIMIT - YYCURSOR < len
#define YYSTAGP(tag) tag = YYCURSOR
#define YYSTAGN(tag) tag = NULL
#define YYSHIFT(shift) YYCURSOR += shift
#define YYSHIFTSTAG(tag, shift) tag += shift
|
- **Free-form**.
This style is enabled with ``re2c:api:style = free-form;`` configuration, and
it is the default for Go backend. In this style API primitives can be defined
as free-form pieces of code, and instead of arguments they have interpolated
variables of the form ``@@{name}``, or optionally just ``@@`` if there is only one
argument. The ``@@`` text is called "sigil". It can be redefined to any other
text with ``re2c:api:sigil`` configuration. For example, the default pointer API
can be defined in free-form style generic API as follows:
.. code-block:: cpp
re2c:define:YYPEEK = "*YYCURSOR";
re2c:define:YYSKIP = "++YYCURSOR";
re2c:define:YYBACKUP = "YYMARKER = YYCURSOR";
re2c:define:YYBACKUPCTX = "YYCTXMARKER = YYCURSOR";
re2c:define:YYRESTORE = "YYCURSOR = YYMARKER";
re2c:define:YYRESTORECTX = "YYCURSOR = YYCTXMARKER";
re2c:define:YYRESTORETAG = "YYCURSOR = ${tag}";
re2c:define:YYLESSTHAN = "YYLIMIT - YYCURSOR < @@{len}";
re2c:define:YYSTAGP = "@@{tag} = YYCURSOR";
re2c:define:YYSTAGN = "@@{tag} = NULL";
re2c:define:YYSHIFT = "YYCURSOR += @@{shift}";
re2c:define:YYSHIFTSTAG = "@@{tag} += @@{shift}";
+48 -67
View File
@@ -1,13 +1,8 @@
Here is a list of API primitives that may be used by the generated
code in order to interface with the outer program.
Here is a list of API primitives that may be used by the generated code in order to interface with the outer program.
Which primitives are needed depends on multiple factors, including
the complexity of regular expressions, input representation,
buffering, the use of various features and so on.
All the necessary primitives should be defined by the user in the form
of macros, functions, variables, free-form pieces of code, or any other
suitable form.
Re2c does not (and cannot) check the definitions, so if anything is
missing or defined incorrectly the generated code will not compile.
the complexity of regular expressions, input representation, buffering, the use of various features and so on.
All the necessary primitives should be defined by the user in the form of macros, functions, variables, free-form pieces of code or any other suitable form.
Re2c does not (and cannot) check the definitions, so if anything is missing or defined incorrectly the generated code will not compile.
``YYCTYPE``
The type of the input characters (code units).
@@ -19,23 +14,22 @@ missing or defined incorrectly the generated code will not compile.
A pointer-like l-value that stores the current input position (usually a
pointer of type ``YYCTYPE*``). Initially ``YYCURSOR`` should point to the
first input character. It is advanced by the generated code.
When a rule matches, ``YYCURSOR`` points to the position after the
last matched character. It is used only in the default C API.
When a rule matches, ``YYCURSOR`` points to the one after the last matched
character. It is used only in the default C API.
``YYLIMIT``
A pointer-like r-value that stores the end of input position (usually a
pointer of type ``YYCTYPE*``). Initially ``YYLIMIT`` should point to the
position after the last available input character. It is not changed by the
generated code. The lexer compares ``YYCURSOR`` to ``YYLIMIT``
in order to determine if there are enough input characters left.
one after the last available input character. It is not changed by the
generated code. Lexer compares ``YYCURSOR`` to ``YYLIMIT``
in order to determine if there is enough input characters left.
``YYLIMIT`` is used only in the default C API.
``YYMARKER``
A pointer-like l-value (usually a pointer of type ``YYCTYPE*``)
that stores the position of the latest matched rule. It is used to
restore the ``YYCURSOR`` position if the longer match fails and
the lexer needs to rollback. Initialization is not
needed. ``YYMARKER`` is used only in the default C API.
A pointer-like l-value (usually a pointer of type ``YYCTYPE*``) that stores
the position of the latest matched rule. It is used to restores ``YYCURSOR``
position if the longer match fails and lexer needs to rollback.
Initialization is not needed. ``YYMARKER`` is used only in the default C API.
``YYCTXMARKER``
A pointer-like l-value that stores the position of the trailing context
@@ -44,28 +38,24 @@ missing or defined incorrectly the generated code will not compile.
``/``.
``YYFILL``
A generic API primitive with one argument ``len``. ``YYFILL`` requests
that the program provide at least ``len`` more input characters or
fail.
If an EOF rule is used, ``YYFILL`` should always return to the
calling function; the return value should be zero on success and
non-zero on failure.
If an EOF rule is not used, the ``YYFILL`` return value is ignored
and it should not return on failure.
The maximal value of ``len`` is ``YYMAXFILL``, which can be
generated with the ``/*!max:re2c*/`` directive. The definition of
``YYFILL`` can be either function-like or free-form depending on
the API style (see ``re2c:api:style`` and
``re2c:define:YYFILL:naked``).
API primitive with one argument ``len``.
The meaning of ``YYFILL`` is to provide at least ``len`` more input
characters or fail. If EOF rule is used, ``YYFILL`` should always return to
the calling function; the return value should be zero on success and non-zero
on failure. If EOF rule is not used, ``YYFILL`` return value is ignored and
it should not return on failure. Maximal value of ``len`` is ``YYMAXFILL``,
which can be generated with ``/*!max:re2c*/`` directive. The definition of
``YYFILL`` can be either function-like or free-form depending on the API
style (see ``re2c:api:style`` and ``re2c:define:YYFILL:naked``).
``YYMAXFILL``
An integral constant equal to the maximal value of the argument to
``YYFILL``. It can be generated with ``/*!max:re2c*/`` directive.
An integral constant equal to the maximal value of ``YYFILL`` argument.
It can be generated with ``/*!max:re2c*/`` directive.
``YYLESSTHAN``
A generic API primitive with one argument ``len``.
It should be defined as an r-value of boolean type that equals ``true`` if
and only if there are less than ``len`` input characters left.
and only if there is less than ``len`` input characters left.
The definition can be either function-like or free-form depending on the
API style (see ``re2c:api:style``).
@@ -73,101 +63,93 @@ missing or defined incorrectly the generated code will not compile.
A generic API primitive with no arguments.
It should be defined as an r-value of type ``YYCTYPE`` that is equal to the
character at the current input position. The definition can be either
function-like or free-form depending on the API style
(see ``re2c:api:style``).
function-like or free-form depending on the API style (see ``re2c:api:style``).
``YYSKIP``
A generic API primitive with no arguments.
``YYSKIP`` should advance the current input position by one
The meaning of ``YYSKIP`` is to advance the current input position by one
character. The definition can be either function-like or free-form
depending on the API style (see ``re2c:api:style``).
``YYBACKUP``
A generic API primitive with no arguments.
``YYBACKUP`` should save the current input position, which is
The meaning of ``YYBACKUP`` is to save the current input position, which is
later restored with ``YYRESTORE``.
The definition should be either function-like or free-form depending on the
API style (see ``re2c:api:style``).
``YYRESTORE``
A generic API primitive with no arguments.
``YYRESTORE`` should restore the current input position to the
The meaning of ``YYRESTORE`` is to restore the current input position to the
value saved by ``YYBACKUP``.
The definition should be either function-like or free-form depending on the
API style (see ``re2c:api:style``).
``YYBACKUPCTX``
A generic API primitive with zero arguments.
``YYBACKUPCTX`` should save the current input position as the
position of the trailing context, which is later restored by
``YYRESTORECTX``.
The meaning of ``YYBACKUPCTX`` is to save the current input position as the
position of the trailing context, which is later restored by ``YYRESTORECTX``.
The definition should be either function-like or free-form depending on the
API style (see ``re2c:api:style``).
``YYRESTORECTX``
A generic API primitive with no arguments.
``YYRESTORECTX`` should restore the trailing context position
The meaning of ``YYRESTORECTX`` is to restore the trailing context position
saved with ``YYBACKUPCTX``.
The definition should be either function-like or free-form depending on the
API style (see ``re2c:api:style``).
``YYRESTORETAG``
A generic API primitive with one argument ``tag``.
``YYRESTORETAG`` should restore the trailing context position
The meaning of ``YYRESTORETAG`` is to restore the trailing context position
to the value of ``tag``.
The definition should be either function-like or free-form depending on the
API style (see ``re2c:api:style``).
``YYSTAGP``
A generic API primitive with one argument ``tag``.
(``tag`` should represent a pointer or an offset, see the section
on submatch extraction for details.)
``YYSTAGP`` should set the ``tag`` value to the current input
The meaning of ``YYSTAGP`` is to set ``tag`` value to the current input
position.
The definition should be either function-like or free-form depending on the
API style (see ``re2c:api:style``).
``YYSTAGN``
A generic API primitive with one argument ``tag``.
(``tag`` should represent a pointer or an offset, see the section
on submatch extraction for details.)
``YYSTAGN`` should to set the ``tag`` value to null (or
some default value).
The definition should be either function-like or free-form depending on the
API style (see ``re2c:api:style``).
The meaning of ``YYSTAGN`` is to set ``tag`` value to null (or some default
value). The definition should be either function-like or free-form depending
on the API style (see ``re2c:api:style``).
``YYMTAGP``
A generic API primitive with one argument ``tag``.
``YYMTAGP`` should append the current position to the history
of ``tag``. (See the section on submatch extraction for details.)
The meaning of ``YYMTAGP`` is to append the current position to the history
of ``tag``.
The definition should be either function-like or free-form depending on the
API style (see ``re2c:api:style``).
``YYMTAGN``
A generic API primitive with one argument ``tag``.
``YYMTAGN`` should append null (or some other default) value
The meaning of ``YYMTAGN`` is to append null (or some other default) value
to the history of ``tag``.
(See the section on submatch extraction for details.)
The definition can be either function-like or free-form depending on the
API style (see ``re2c:api:style``).
``YYSHIFT``
A generic API primitive with one argument ``shift``.
``YYSHIFT`` should shift the current input position by
The meaning of ``YYSHIFT`` is to shift the current input position by
``shift`` characters (the shift value may be negative). The definition
can be either function-like or free-form depending on the API style
(see ``re2c:api:style``).
``YYSHIFTSTAG``
A generic API primitive with two arguments, ``tag`` and ``shift``.
``YYSHIFTSTAG`` should shift ``tag`` by ``shift`` characters
The meaning of ``YYSHIFTSTAG`` is to shift ``tag`` by ``shift`` characters
(the shift value may be negative).
The definition can be either function-like or free-form depending on the
API style (see ``re2c:api:style``).
``YYSHIFTMTAG``
A generic API primitive with two arguments, ``tag`` and ``shift``.
``YYSHIFTMTAG`` should shift the latest value in the history
The meaning of ``YYSHIFTMTAG`` is to shift the latest value in the history
of ``tag`` by ``shift`` characters (the shift value may be negative).
The definition should be either function-like or free-form depending on the
API style (see ``re2c:api:style``).
@@ -178,8 +160,8 @@ missing or defined incorrectly the generated code will not compile.
``YYCONDTYPE``
The type of the condition enum.
It should be generated either with the ``/*!types:re2c*/``
directive or the ``-t`` ``--type-header`` option.
It should be generated either with ``/*!types:re2c*/`` directive or ``-t``
``--type-header`` option.
``YYGETCONDITION``
An API primitive with zero arguments.
@@ -190,8 +172,8 @@ missing or defined incorrectly the generated code will not compile.
``YYSETCONDITION``
An API primitive with one argument ``cond``.
The meaning of ``YYSETCONDITION`` is to set the current condition
identifier to ``cond``.
The meaning of ``YYSETCONDITION`` is to set the current condition identifier
to ``cond``.
The definition should be either function-like or free-form depending on the
API style (see ``re2c:api:style`` and ``re2c:define:YYSETCONDITION@cond``).
@@ -204,8 +186,7 @@ missing or defined incorrectly the generated code will not compile.
``YYSETSTATE``
An API primitive with one argument ``state``.
The meaning of ``YYSETSTATE`` is to set the current lexer state to
``state``.
The meaning of ``YYSETSTATE`` is to set the current lexer state to ``state``.
The definition should be either function-like or free-form depending on the
API style (see ``re2c:api:style`` and ``re2c:define:YYSETSTATE@state``).
+16 -16
View File
@@ -5,28 +5,28 @@ except that the name can be used to reference a block in other parts of the
program. More information on each directive can be found in the related
sections.
``/*!re2c[:<name>] ... */``
``/*!re2c[:NAME] ... */``
A global re2c block with an optional name. The block may contain named
definitions, configurations and rules in any order. Named definitions and
configurations are defined in the global scope, so they are inherited by
subsequent blocks. The code for a global block is generated at the point
where the block is specified.
``/*!local:re2c[:<name>] ... */``
``/*!local:re2c[:NAME] ... */``
A local re2c block with an optional name. Unlike global blocks, definitions
and configurations inside of a local block are not added into the global
scope. In all other respects local blocks are the same as global blocks.
``/*!rules:re2c[:<name>] ... */``
``/*!rules:re2c[:NAME] ... */``
A reusable block with an optional name. Rules blocks have the same structure
as local or global blocks, but they do not produce any code and they can be
reused multiple times in other blocks with the help of a ``!use:<name>;``
directive or a ``/*!use:re2c[:<name>] ... */`` block. A rules block on its
reused multiple times in other blocks with the help of a ``!use:NAME;``
directive or a ``/*!use:re2c[:NAME] ... */`` block. A rules block on its
own does not add any definitions into the global scope. The code for it is
generated at the point of use. Prior to re2c version 2.2 rules blocks
required ``-r --reusable`` option.
``/*!use:re2c[:<name>] ... */``
``/*!use:re2c[:NAME] ... */``
A use block that references a previously defined rules block. If the name is
specified, re2c looks for a rules blocks with this name. Otherwise the most
recent rules block is used (either a named or an unnamed one). A use block
@@ -34,7 +34,7 @@ sections.
those of the referenced rules block. Prior to re2c version 2.2 use blocks
required ``-r --reusable`` option.
``!use:<name>;``
``!use:NAME;``
An in-block use directive that merges a previously defined rules block with
the specified name into the current block. Named definitions, configurations
and rules of the referenced block are added to the current ones. Conflicts
@@ -45,7 +45,7 @@ sections.
can be placed anywhere inside of a block, and multiple use directives are
allowed.
``/*!max:re2c[:<name1>[:<name2>...]] ... */``
``/*!max:re2c[:NAME1[:NAME2...]] ... */``
A directive that generates ``YYMAXFILL`` definition.
An optional list of block names specifies which blocks should be included
when computing ``YYMAXFILL`` value (if the list is empty, all blocks are
@@ -56,7 +56,7 @@ sections.
configuration ``format`` that specifies a template string where ``@@{max}``
(or ``@@`` for short) is replaced with the numeric value of ``YYMAXFILL``.
``/*!maxnmatch:re2c[:<name1>[:<name2>...]] ... */``
``/*!maxnmatch:re2c[:NAME1[:NAME2...]] ... */``
A directive that generates ``YYMAXNMATCH`` definition (it requires
``-P --posix-captures`` option).
An optional list of block names specifies which blocks should be included
@@ -68,7 +68,7 @@ sections.
configuration ``format`` that specifies a template string where ``@@{max}``
(or ``@@`` for short) is replaced with the numeric value of ``YYMAXNMATCH``.
``/*!stags:re2c[:<name1>[:<name2>...]] ... */``, ``/*!mtags:re2c[:<name1>[:<name2>...]] ... */``
``/*!stags:re2c[:NAME1[:NAME2...]] ... */``, ``/*!mtags:re2c[:NAME1[:NAME2...]] ... */``
Directives that specify a template piece of code that is expanded for each
s-tag/m-tag variable generated by re2c.
An optional list of block names specifies which blocks should be included
@@ -80,7 +80,7 @@ sections.
Configuration ``separator`` specifies a piece of code used to join the
generated ``format`` pieces for different tag variables.
``/*!getstate:re2c[:<name1>[:<name2>...]] ... */``
``/*!getstate:re2c[:NAME1[:NAME2...]] ... */``
A directive that generates conditional dispatch on the lexer state (it
requires ``-f --storable-state`` option).
An optional list of block names specifies which blocks should be included in
@@ -89,7 +89,7 @@ sections.
the default transition goes to the first block in the file that has a start
label.
``/*!types:re2c[:<name1>[:<name2>...]] ... */``
``/*!types:re2c[:NAME1[:NAME2...]] ... */``
A directive that generates condition enumeration (it requires
``-c --conditions`` option).
An optional list of block names specifies which blocks should be included
@@ -103,15 +103,15 @@ sections.
Configuration ``separator`` specifies a piece of code used to join the
generated ``format`` pieces for different conditions.
``/*!include:re2c <file> */``
This directive allows one to include ``<file>``, which must be a double-quoted
``/*!include:re2c FILE */``
This directive allows one to include ``FILE``, which must be a double-quoted
file path. The contents of the file are literally substituted in place of
the directive, in the same way as ``#include`` works in C/C++. This
directive can be used together with the ``--depfile`` option to generate
build system dependencies on the included files.
``!include <file>;``
This directive is the same as ``/*!include:re2c <file> */``, except that it
``!include FILE;``
This directive is the same as ``/*!include:re2c FILE */``, except that it
should be used inside of a re2c block.
``/*!header:re2c:on*/``
-53
View File
@@ -1,53 +0,0 @@
The generated code interfaces with the outer program with the help of
*primitives* -- symbolic names that can be defined as variables, functions or
macros in the target language (collectively referred to as the API).
The primitives should be defined by the user. This approach gives the user
freedom and flexibility in customizing the lexer, but it also requires some
understanding of how the lexer works in order to implement the primitives
correctly and efficiently. The manual provides examples for the most popular
use cases. For the full list of primitives see the `interface primitives`_
section.
.. _generic_api:
There are two *API flavours* that define the set of primitives used by re2c:
**Pointer API**
This API is also called *default API*, since it was historically the first,
and for a long time the only one. This is a more restrictive API based on C
pointer arithmetics. It consists of pointer-like primitives ``YYCURSOR``,
``YYMARKER``, ``YYCTXMARKER``, ``YYLIMIT`` (which are normally defined as
pointers of type ``YYCTYPE*``) and ``YYFILL``. Pointer API is enabled by
default for the C backend, and it cannot be used with backends that do not
support pointer arithmetics.
**Generic API**
This is a more flexible API that does not assume pointer semantics. It
consists of primitives
``YYPEEK``,
``YYSKIP``,
``YYBACKUP``,
``YYBACKUPCTX``,
``YYSTAGP``,
``YYSTAGN``,
``YYMTAGP``,
``YYMTAGN``,
``YYRESTORE``,
``YYRESTORECTX``,
``YYRESTORETAG``,
``YYSHIFT``,
``YYSHIFTSTAG``,
``YYSHIFTMTAG``,
``YYLESSTHAN``
and ``YYFILL``.
For the C backend generic API is enabled with ``--input custom`` option or
``re2c:flags:input = custom;`` configuration; for the Go backend it is
enabled by default. Generic API was added in version 0.14. It is
intentionally designed to give the user as much freedom as possible in
redefining the input model and the semantics of different actions performed
by the generated code.
There are two *API styles* determine the form in which the primitives should be
defined:
-52
View File
@@ -1,52 +0,0 @@
**Free-form**
This style is enabled with ``re2c:api:style = free-form;`` configuration.
Interface primitives should be defined as free-form pieces of code with
interpolated variables of the form ``@@{name}`` or optionally just ``@@``
if there is only one variable. The ``@@`` marker can be customized with the
``re2c:api:sigil`` configuration. In C/C++ free-form style generic API can
be defined in terms of pointers ``cursor``, ``limit``, ``marker`` and
``ctxmarker`` as follows:
.. code-block:: c
/*!re2c
re2c:define:YYPEEK = "*cursor";
re2c:define:YYSKIP = "++cursor";
re2c:define:YYBACKUP = "marker = cursor";
re2c:define:YYRESTORE = "cursor = marker";
re2c:define:YYBACKUPCTX = "ctxmarker = cursor";
re2c:define:YYRESTORECTX = "cursor = ctxmarker";
re2c:define:YYRESTORETAG = "cursor = ${tag}";
re2c:define:YYLESSTHAN = "limit - cursor < @@{len}";
re2c:define:YYSTAGP = "@@{tag} = cursor";
re2c:define:YYSTAGN = "@@{tag} = NULL";
re2c:define:YYSHIFT = "cursor += @@{shift}";
re2c:define:YYSHIFTSTAG = "@@{tag} += @@{shift}";
*/
|
**Function-like**
This style is enabled with ``re2c:api:style = functions;`` configuration.
Primitives should be defined as functions or macros with parentheses,
accepting the necessary number of arguments. For historical reasons this
API style is the default for C/C++ backend. Function style generic API can
be defined in terms of pointers ``cursor``, ``limit``, ``marker`` and
``ctxmarker`` as follows:
.. code-block:: c
#define YYPEEK() *cursor
#define YYSKIP() ++cursor
#define YYBACKUP() marker = cursor
#define YYRESTORE() cursor = marker
#define YYBACKUPCTX() ctxmarker = cursor
#define YYRESTORECTX() cursor = ctxmarker
#define YYRESTORETAG(tag) cursor = tag
#define YYLESSTHAN(len) limit - cursor < len
#define YYSTAGP(tag) tag = cursor
#define YYSTAGN(tag) tag = NULL
#define YYSHIFT(shift) cursor += shift
#define YYSHIFTSTAG(tag, shift) tag += shift
-50
View File
@@ -1,50 +0,0 @@
**Free-form**
This style is enabled with ``re2c:api:style = free-form;`` configuration,
and it is the default for the Go backend. Interface primitives should be
defined as free-form pieces of code with interpolated variables of the form
``@@{name}`` or optionally just ``@@`` if there is only one variable. The
``@@`` text can be customized with the ``re2c:api:sigil`` configuration.
In Go free-form style generic API can be defined in terms of integer
variables ``cursor``, ``limit``, ``marker``, ``ctxmarker`` and a string (or
a byte slice) ``data`` as follows:
.. code-block:: go
/*!re2c
re2c:define:YYPEEK = "data[cursor]";
re2c:define:YYSKIP = "cursor++";
re2c:define:YYBACKUP = "marker = cursor";
re2c:define:YYRESTORE = "cursor = marker";
re2c:define:YYBACKUPCTX = "ctxmarker = cursor";
re2c:define:YYRESTORECTX = "cursor = ctxmarker";
re2c:define:YYRESTORETAG = "cursor = ${tag}";
re2c:define:YYLESSTHAN = "limit - cursor < @@{len}";
re2c:define:YYSTAGP = "@@{tag} = cursor";
re2c:define:YYSTAGN = "@@{tag} = -1";
re2c:define:YYSHIFT = "cursor += @@{shift}";
re2c:define:YYSHIFTSTAG = "@@{tag} += @@{shift}";
*/
|
**Function-like**
This style is enabled with ``re2c:api:style = functions;`` configuration.
Primitives should be defined as functions with parentheses, accepting the
necessary number of arguments. This style can be used with the Go backend,
but it is more restrictive than the free-form style and some primitives are
problematic to define. Most of the primitives can be defined as closures in
terms of integer variables ``cursor``, ``limit``, ``marker``, ``ctxmarker``
and a string (or a byte slice) ``data``:
.. code-block:: go
YYPEEK := func() byte { return data[cursor] }
YYSKIP := func() { cursor++ }
YYBACKUP := func() { marker = cursor }
YYRESTORE := func() { cursor = marker }
YYBACKUPCTX := func() { ctxmarker = cursor }
YYRESTORECTX := func() { cursor = ctxmarker }
YYLESSTHAN := func(n int) bool { return limit-cursor < n }
YYSHIFT := func(n int) { cursor += n }
-5
View File
@@ -1,5 +0,0 @@
For ``YYFILL`` definition and instructions how to customize or disable
end-of-input checks see the `handling the end of input`_ and
`buffer refilling`_ sections.
+20 -70
View File
@@ -1,70 +1,20 @@
Re2c works as a preprocessor. It reads the input file (which is usually a
program in the target language, but can be anything) and looks for blocks of
code enclosed in special-form comments. The text outside of these blocks is
copied verbatim into the output file. The contents of the blocks are processed
by re2c. It translates them to code in the target language and outputs the
generated code in place of the block. There are different kinds of blocks;
see the `blocks and directives`_ section for a full list of them. The main block
kinds are the following:
``/*!re2c[:<name>] ... */``
A *global block* that contains a mixture of named definitions,
configurations, directives and rules (regular expressions with associated
semantic actions). Re2c compiles regular expressions to a deterministic
finite automaton, encodes it in the form of conditional jumps and replaces
the block with the generated code. Names and configurations defined
in the block are added to the global scope and become visible to subsequent
blocks (at the start of the program global scope is initialized with the
`command-line options`_).
The ``:<name>`` part is optional: if specified, the name can be used to
refer to the block in another part of the program.
``/*!local:re2c[:<name>] ... */``
A *local block* is like a global block, but the names and configurations
defined in it have local scope (they do not affect other blocks).
``/*!rules:re2c[:<name>] ... */``
A *rules block* is like a local block, but it does not generate any code and
is meant to be reused in other blocks. This is a way of sharing code
(more details in the `reusable blocks`_ section).
A block may contain the following kinds of statements:
``<name> = <regular expression>;``
A *named definition* binds a name to a regular expression. Names may contain
alphanumeric characters and underscore. The `regular expressions`_ section
gives an overview of re2c syntax for regular expressions. Once defined, the
name can be used in other regular expressions and in rules. Recursion in
named definitions is not allowed, and each name should be defined before it
is used. A block inherits named definitions from the global scope.
Redefining a name that exists in the current scope is an error.
``<configuration> = <value>;``
A *configuration* allows one to change re2c behavior and customize the
generated code. For a full list of configurations supported by re2c see the
`configurations`_ section. Depending on a particular configuration, the
value can be a keyword, a nonnegative integer number or a one-line string
which should be enclosed in double or single quotes unless it consists of
alphanumeric characters. A block inherits configurations from the global
scope and may redefine them or add new ones. Configurations defined inside
of a block affect the whole block, even if they appear at the end of it.
``<regular expression> { <code> }``
A *rule* binds a regular expression to a semantic action (a block of code in
the target language). If the regular expression matches, the associated
semantic action is executed. If multiple rules match, the longest match
takes precedence. If multiple rules match the same string, the earliest one
takes precedence. There are two special rules: the default rule ``*`` and
the end of input rule ``$``. The default rule should always be defined, it
has the lowest priority regardless of its place in the block, and it matches
any code unit (not necessarily a valid character, see the
`encoding support`_ section). The end of input rule should be defined if the
corresponding method for `handling the end of input`_ is used. If
`start conditions`_ are used, rules have more complex syntax.
``!<directive>;``
A *directive* is one of the special predefined statements. Each directive
has a unique purpose. For example, the ``!use`` directive merges a rules
block into the current one (see the `reusable blocks`_ section), and the
``!include`` directive allows one to include an outer file (see the
`include files`_ section).
A re2c program consists of normal code intermixed with re2c blocks and `directives`_.
Each re2c block may contain definitions, configurations and rules.
Definitions are of the form ``name = regexp;`` where ``name`` is an identifier that
consists of letters, digits and underscores, and ``regexp`` is a regular expression.
`Regular expressions`_ may contain other definitions, but recursion is not allowed and each name should be defined before used.
`Configurations`_ are of the form ``re2c:config = value;`` where ``config`` is the configuration descriptor
and ``value`` can be a number, a string or a special word.
Rules consist of a regular expression followed by a semantic action
(a block of code enclosed in curly braces ``{`` and ``}``,
or a raw one line of code preceded with ``:=`` and ended with a newline that is not followed by a whitespace).
If the input matches the regular expression, the associated semantic action is executed.
If multiple rules match, the longest match takes precedence.
If multiple rules match the same string, the earlier rule takes precedence.
There are two special rules: default rule ``*`` and EOF rule ``$``.
Default rule should always be defined, it has the lowest priority regardless of its place and matches any code unit (not necessarily a valid character, see `encoding support`_).
EOF rule matches the end of input, it should be defined if the corresponding method for `handling the end of input`_ is used.
If `start conditions`_ are used, rules have more complex syntax.
All rules of a single block are compiled into a deterministic finite-state automaton (DFA) and encoded in the form of a program in the target language.
The generated code interfaces with the outer program by the means of a few user-defined primitives (see the `program interface`_ section).
`Reusable blocks`_ allow sharing rules, definitions and configurations between different blocks.
+15 -9
View File
@@ -1,13 +1,16 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT --case-ranges -i
int lex(const char *YYCURSOR) { // C/C++ code
// re2c $INPUT -o $OUTPUT -i
#include <assert.h> //
// C/C++ code
int lex(const char *YYCURSOR) //
{
{
char yych;
yych = *YYCURSOR;
switch (yych) {
case 'A' ... 'Z':
case '_':
case 'a' ... 'z': goto yy4;
default: goto yy2;
}
@@ -19,6 +22,7 @@ yy4:
switch (yych) {
case '0' ... '9':
case 'A' ... 'Z':
case '_':
case 'a' ... 'z': goto yy4;
default: goto yy6;
}
@@ -26,8 +30,10 @@ yy6:
{ return 0; }
}
} //
//
int main() { // C/C++ code
return lex("qwerty42"); //
} //
} //
//
int main() //
{ // C/C++ code
assert(lex("_Zer0") == 0); //
return 0; //
} //
+22 -18
View File
@@ -1,18 +1,22 @@
// re2c $INPUT -o $OUTPUT --case-ranges -i
int lex(const char *YYCURSOR) { // C/C++ code
/*!re2c
re2c:define:YYCTYPE = char; // configurations
re2c:yyfill:enable = 0; //
//
alpha = [a-zA-Z]; // named definitions
ident = alpha (alpha | [0-9])*; //
//
ident { return 0; } // rules
* { return 1; } //
*/
} //
//
int main() { // C/C++ code
return lex("qwerty42"); //
} //
// re2c $INPUT -o $OUTPUT -i
#include <assert.h> //
// C/C++ code
int lex(const char *YYCURSOR) //
{
/*!re2c // start of re2c block
re2c:define:YYCTYPE = char; // configuration
re2c:yyfill:enable = 0; // configuration
re2c:flags:case-ranges = 1; // configuration
//
ident = [a-zA-Z_][a-zA-Z_0-9]*; // named definition
//
ident { return 0; } // normal rule
* { return 1; } // default rule
*/
} //
//
int main() //
{ // C/C++ code
assert(lex("_Zer0") == 0); //
return 0; //
} //
+3
View File
@@ -5,6 +5,9 @@
#include <assert.h>
static const uint64_t ERROR = ~0lu;
enum YYCONDTYPE {
};
template<int BASE> static void adddgt(uint64_t &u, unsigned int d)
{
@@ -4,6 +4,7 @@
#include <assert.h>
static const uint64_t ERROR = ~0lu;
/*!types:re2c*/
template<int BASE> static void adddgt(uint64_t &u, unsigned int d)
{
+14 -13
View File
@@ -1,12 +1,11 @@
// Code generated by re2c, DO NOT EDIT.
//go:generate re2go $INPUT -o $OUTPUT -i
package main //
//
func lex(str string) int { // Go code
var cursor int //
package main //
//
func lex(str string) { // Go code
var cursor int //
//
{
var yych byte
yych = str[cursor]
@@ -18,7 +17,7 @@ func lex(str string) { // Go code
}
yy2:
cursor += 1
{ panic("error!"); }
{ return 1; }
yy4:
cursor += 1
yych = str[cursor]
@@ -29,11 +28,13 @@ yy4:
goto yy4
}
yy6:
{ return }
{ return 0; }
}
} //
//
func main() { // Go code
lex("1234\x00") //
} //
} //
//
func main() { //
if lex("1234\x00") != 0 { // Go code
panic("failed!") //
} //
} //
+23 -22
View File
@@ -1,24 +1,25 @@
//go:generate re2go $INPUT -o $OUTPUT -i
package main //
//
func lex(str string) int { // Go code
var cursor int //
package main //
//
func lex(str string) { // Go code
var cursor int //
//
/*!re2c
re2c:define:YYCTYPE = byte; //
re2c:define:YYPEEK = "str[cursor]"; //
re2c:define:YYSKIP = "cursor += 1"; // configurations
re2c:yyfill:enable = 0; //
re2c:flags:nested-ifs = 1; //
//
number = [1-9][0-9]*; // named definition
//
number { return } // rules
* { panic("error!"); } //
*/
} //
//
func main() { // Go code
lex("1234\x00") //
} //
/*!re2c // start of re2c block
re2c:define:YYCTYPE = byte; // configuration
re2c:define:YYPEEK = "str[cursor]"; // configuration
re2c:define:YYSKIP = "cursor += 1"; // configuration
re2c:yyfill:enable = 0; // configuration
re2c:flags:nested-ifs = 1; // configuration
//
number = [1-9][0-9]*; // named definition
//
number { return 0; } // normal rule
* { return 1; } // default rule
*/
} //
//
func main() { //
if lex("1234\x00") != 0 { // Go code
panic("failed!") //
} //
} //
+1 -1
View File
@@ -1,5 +1,5 @@
// Code generated by re2c, DO NOT EDIT.
//go:generate re2go $INPUT -o $OUTPUT -i
//go:generate re2go -c $INPUT -o $OUTPUT -i
package main
import (
+1 -1
View File
@@ -1,4 +1,4 @@
//go:generate re2go $INPUT -o $OUTPUT -i
//go:generate re2go -c $INPUT -o $OUTPUT -i
package main
import (
+1 -1
View File
@@ -1,5 +1,5 @@
// Code generated by re2c, DO NOT EDIT.
//go:generate re2go $INPUT -o $OUTPUT -i
//go:generate re2go -c $INPUT -o $OUTPUT -i
package main
import "testing"
+1 -1
View File
@@ -1,4 +1,4 @@
//go:generate re2go $INPUT -o $OUTPUT -i
//go:generate re2go -c $INPUT -o $OUTPUT -i
package main
import "testing"
-5
View File
@@ -1,14 +1,9 @@
#ifndef _RE2C_LIB_REGOFF_TRIE_
#define _RE2C_LIB_REGOFF_TRIE_
#include <algorithm>
#include "regex.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "src/debug/debug.h"
#include "src/util/forbid_copy.h"
namespace re2c {
+3 -27
View File
@@ -12,7 +12,6 @@ import signal
import subprocess
import sys
import textwrap as _textwrap
from dataclasses import dataclass
from datetime import datetime
from functools import cmp_to_key
from pathlib import Path
@@ -40,7 +39,6 @@ FILEPATH_CONTEXT_PATTERN = re.compile(b'('
+ b')')
@dataclass
class Context:
"""Class for passing a context to parallel processes."""
@@ -253,29 +251,12 @@ def create_tests_tree():
return test_blddir
# We cannot use `shutil.copytree` because we need to copy multiple directories
# into one, and that is problematic for two reasons:
# 1) it requires `dirs_exist_ok` parameter which was added only in python-3.8
# 2) `make distcheck` fails when trying to copy the second directory because
# it makes source files read-only
def copy_dir(src, dst):
"""Copy the contents of directory `src` to directory `dst`, preserving
directory structure."""
for path, dirs, files in os.walk(src, topdown=False):
dstpath = os.path.join(dst, path[len(src)+1:])
if not os.path.isdir(dstpath):
os.makedirs(dstpath)
for f in files:
shutil.copy(os.path.join(path, f), dstpath)
def copy_tests(tests, dst): # type: (list, str) -> None
"""Copy the test structure to 'dst'."""
# preserve directory structure unless given explicit args
if not tests:
copy_dir(here(TOP_SRCDIR, 'test'), dst)
copy_dir(here(TOP_SRCDIR, 'examples'), dst)
shutil.copytree(here(TOP_SRCDIR, 'test'), dst, dirs_exist_ok=True)
shutil.copytree(here(TOP_SRCDIR, 'examples'), dst, dirs_exist_ok=True)
return
files = []
@@ -392,11 +373,6 @@ def run_test(test):
if header:
os.makedirs(os.path.dirname(header), exist_ok=True)
# Disable Wine warnings, or else they are dumped into .stderr files for
# random tests, so the test results don't match and the tests fail.
if _ctx.wine:
os.environ['WINEDEBUG'] = '-all'
# run re2c
args = [_ctx.valgrind] + _ctx.valgrind_opts
args += [_ctx.wine, _ctx.re2c] + _ctx.incpaths + switches.split()
@@ -431,7 +407,7 @@ def run_test(test):
pass # if there is an error, some files may be missing
# On windows we need to patch output to match expected test results.
if os.name == 'nt' or _ctx.wine:
if os.name == 'nt':
patch_newlines_and_slashes(outy, stem)
# compare results
+4
View File
@@ -510,6 +510,10 @@ void DFA::calc_stats(OutputBlock &out)
out.stags.insert(stagnames.begin(), stagnames.end());
out.mtags.insert(mtagnames.begin(), mtagnames.end());
}
if (!cond.empty()) {
out.conds.push_back(cond);
}
}
static bool can_hoist_tags(const State *s, const opt_t *opts)
+2 -1
View File
@@ -21,7 +21,7 @@
namespace re2c {
class Msg;
struct Output;
class Output;
struct dfa_t;
struct opt_t;
struct Label;
@@ -130,6 +130,7 @@ struct DFA {
void reorder();
void prepare(const opt_t *opts);
void calc_stats(OutputBlock &out);
void emit_body(Output &output, CodeList *program) const;
void emit_dot(Output &output, CodeList *program) const;
private:
-3
View File
@@ -63,9 +63,6 @@ void interfere(const tcmd_t *cmd, const bool *live, bool *interf,
memcpy(buf, live, nver * sizeof(bool));
cfg_t::live_through_bblock(p->next, buf);
// a register does not interfere with itself
buf[l] = false;
// if copy command, exclude RHS
if (tcmd_t::iscopy(p)) buf[r] = false;
+17 -37
View File
@@ -9,7 +9,6 @@
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include "src/constants.h"
#include "src/dfa/tcmd.h"
@@ -17,6 +16,7 @@
#include "src/msg/location.h"
#include "src/util/forbid_copy.h"
#include "src/util/slab_allocator.h"
#include "src/util/uniq_vector.h"
#include "src/util/smart_ptr.h"
#include "src/util/string_utils.h"
@@ -30,8 +30,8 @@ struct opt_t;
struct Code;
struct CodeGo;
struct CodeGoIf;
struct Output;
struct OutputBlock;
class Output;
class OutputBlock;
struct State;
struct DFA;
typedef std::vector<smart_ptr<DFA> > dfas_t;
@@ -315,7 +315,6 @@ struct Code {
CodeVar var;
CodeFmt fmt;
CodeLabel label;
CodeList *loop;
loc_t loc;
};
@@ -375,13 +374,6 @@ inline Code *code_stmt(code_alc_t &alc, const char *text)
return x;
}
inline Code *code_loop(code_alc_t &alc, CodeList *loop)
{
Code *x = new_code(alc, CODE_LOOP);
x->loop = loop;
return x;
}
inline Code *code_text(code_alc_t &alc, const char *text)
{
Code *x = new_code(alc, CODE_TEXT);
@@ -471,11 +463,6 @@ inline Code *code_yyaccept_def(code_alc_t &alc)
return new_code(alc, CODE_YYACCEPT);
}
inline Code *code_yystate_def(code_alc_t &alc)
{
return new_code(alc, CODE_YYSTATE);
}
inline Code *code_line_info_output(code_alc_t &alc)
{
return new_code(alc, CODE_LINE_INFO_OUTPUT);
@@ -641,10 +628,12 @@ struct CodegenCtxGlobal {
Scratchbuf &scratchbuf;
Msg &msg;
const opt_t *opts;
const blocks_t &cblocks;
const blocks_t &hblocks;
const blocks_t *pblocks;
mutable blocks_t tmpblocks; // temporary buffer for block lists in directives
uniq_vector_t<std::string> conds;
tagnames_t stags;
tagnames_t mtags;
size_t max_fill;
size_t max_nmatch;
const bool warn_cond_ord;
};
@@ -673,14 +662,6 @@ struct OutputFragment {
uint32_t indent;
};
struct StartCond {
std::string name;
uint32_t number;
};
typedef std::vector<StartCond> StartConds;
typedef std::map<uint32_t, CodeList*> storable_states_t;
struct OutputBlock {
InputBlockKind kind;
std::string name;
@@ -688,7 +669,7 @@ struct OutputBlock {
std::vector<OutputFragment> fragments;
bool used_yyaccept;
bool have_user_code;
StartConds conds;
std::vector<std::string> conds;
tagnames_t stags;
tagnames_t mtags;
const opt_t *opts;
@@ -697,23 +678,25 @@ struct OutputBlock {
size_t max_nmatch; // YYMAXNMATCH
// Used in the state switch (with `-f --storable-state` option).
Label *start_label; // label of the DFA start state
uint32_t fill_index; // next free index in YYFILL state enumeration
uint32_t fill_state; // index of the most recent YYFILL state
storable_states_t fill_goto; // transitions to YYFILL states
Label *start_label; // label of the DFA start state
uint32_t fill_index_start; // start of YYFILL index range
uint32_t fill_index_end; // end of YYFILL index range (not included)
std::vector<CodeList*> fill_goto; // transitions to YYFILL states
OutputBlock(InputBlockKind kind, const std::string &name, const loc_t &loc);
~OutputBlock();
FORBID_COPY(OutputBlock);
};
struct Output {
class Output {
blocks_t cblocks; /* .c file */
blocks_t hblocks; /* .h file */
blocks_t *pblocks; /* selector */
public:
uint32_t label_counter;
bool state_goto;
bool cond_enum_autogen; // true unless an explicit `types:re2c` directive is used
bool cond_enum_in_hdr;
bool cond_goto;
bool warn_condition_order;
bool need_header;
@@ -763,9 +746,6 @@ void gen_goto(Output &output, const DFA &dfa, CodeList *stmts, const State *from
const CodeJump &jump);
const char *gen_lessthan(Scratchbuf &o, const opt_t *opts, size_t n);
void gen_code(Output &output, dfas_t &dfas);
void gen_dfa_as_blocks_with_labels(Output &output, const DFA &dfa, CodeList *stmts);
void gen_dfa_as_switch_cases(Output &output, DFA &dfa, CodeCases *cases);
void wrap_dfas_in_loop_switch(Output &output, CodeList *stmts, CodeCases *cases);
void expand_pass_1(CodegenCtxPass1 &ctx, Code *code);
void expand_pass_2(CodegenCtxPass2 &ctx, Code *code);
+31 -36
View File
@@ -12,7 +12,7 @@
namespace re2c {
static CodeGoIf *code_goif(code_alc_t &alc, CodeGoIf::Kind kind, const Span *sp,
uint32_t nsp, State *next, bool skip, uint32_t eof, const opt_t *opts);
uint32_t nsp, State *next, bool skip, uint32_t eof);
static bool is_eof(uint32_t eof, uint32_t ub)
{
@@ -97,7 +97,7 @@ static CodeCmp *code_cmp(code_alc_t &alc, const char *cmp, uint32_t val)
}
static CodeGoIfB *code_goifb(code_alc_t &alc, const Span *s, uint32_t n, State *next,
bool skip, uint32_t eof, const opt_t *opts)
bool skip, uint32_t eof)
{
const uint32_t l = n / 2;
const uint32_t h = n - l;
@@ -106,13 +106,13 @@ static CodeGoIfB *code_goifb(code_alc_t &alc, const Span *s, uint32_t n, State *
CodeGoIfB *x = alc.alloct<CodeGoIfB>(1);
x->cond = code_cmp(alc, "<=", s[l - 1].ub - 1);
x->gothen = code_goif(alc, tkind, &s[0], l, next, skip, eof, opts);
x->goelse = code_goif(alc, ekind, &s[l], h, next, skip, eof, opts);
x->gothen = code_goif(alc, tkind, &s[0], l, next, skip, eof);
x->goelse = code_goif(alc, ekind, &s[l], h, next, skip, eof);
return x;
}
static void add_branch(CodeGoIfL *go, const CodeCmp *cond, State *to, State *next,
const Span &sp, bool skip, uint32_t eof, const opt_t *opts)
const Span &sp, bool skip, uint32_t eof)
{
CodeGoIfL::Branch &b = go->branches[go->nbranches++];
b.cond = cond;
@@ -121,16 +121,11 @@ static void add_branch(CodeGoIfL *go, const CodeCmp *cond, State *to, State *nex
b.jump.tags = sp.tags;
b.jump.skip = skip && consume(sp.to);
b.jump.eof = is_eof(eof, sp.ub);
// TODO: support transition elision with --loop-switch option. This requires
// used-label analysis before the start of code generation phase, because in Rust
// there is no fallthrough between cases and we can only elide a transition if we can
// elide the whole case, which is only possible if there are no other transitions into
// this state (so its label is unused).
b.jump.elide = !opts->loop_switch && !to;
b.jump.elide = !to;
}
static CodeGoIfL *code_goifl(code_alc_t &alc, const Span *s, uint32_t n, State *next,
bool skip, uint32_t eof, const opt_t *opts)
bool skip, uint32_t eof)
{
CodeGoIfL *x = alc.alloct<CodeGoIfL>(1);
x->nbranches = 0;
@@ -139,17 +134,17 @@ static CodeGoIfL *code_goifl(code_alc_t &alc, const Span *s, uint32_t n, State *
for (;;) {
if (n == 1 && s[0].to == next) {
add_branch(x, NULL, NULL, next, s[0], skip, eof, opts);
add_branch(x, NULL, NULL, next, s[0], skip, eof);
break;
}
else if (n == 1) {
add_branch(x, NULL, s[0].to, next, s[0], skip, eof, opts);
add_branch(x, NULL, s[0].to, next, s[0], skip, eof);
break;
}
else if (n == 2 && s[0].to == next) {
CodeCmp *cmp = code_cmp(alc, ">=", s[0].ub);
add_branch(x, cmp, s[1].to, next, s[1], skip, eof, opts);
add_branch(x, NULL, NULL, next, s[0], skip, eof, opts);
add_branch(x, cmp, s[1].to, next, s[1], skip, eof);
add_branch(x, NULL, NULL, next, s[0], skip, eof);
break;
}
else if (n == 3
@@ -158,8 +153,8 @@ static CodeGoIfL *code_goifl(code_alc_t &alc, const Span *s, uint32_t n, State *
&& s[2].to == s[0].to
&& s[2].tags == s[0].tags) {
CodeCmp *cmp = code_cmp(alc, "!=", s[0].ub);
add_branch(x, cmp, s[0].to, next, s[0], skip, eof, opts);
add_branch(x, NULL, NULL, next, s[1], skip, eof, opts);
add_branch(x, cmp, s[0].to, next, s[0], skip, eof);
add_branch(x, NULL, NULL, next, s[1], skip, eof);
break;
}
else if (n >= 3
@@ -167,13 +162,13 @@ static CodeGoIfL *code_goifl(code_alc_t &alc, const Span *s, uint32_t n, State *
&& s[2].to == s[0].to
&& s[2].tags == s[0].tags) {
CodeCmp *cmp = code_cmp(alc, "==", s[0].ub);
add_branch(x, cmp, s[1].to, next, s[1], skip, eof, opts);
add_branch(x, cmp, s[1].to, next, s[1], skip, eof);
n -= 2;
s += 2;
}
else {
CodeCmp *cmp = code_cmp(alc, "<=", s[0].ub - 1);
add_branch(x, cmp, s[0].to, next, s[0], skip, eof, opts);
add_branch(x, cmp, s[0].to, next, s[0], skip, eof);
n -= 1;
s += 1;
}
@@ -183,35 +178,35 @@ static CodeGoIfL *code_goifl(code_alc_t &alc, const Span *s, uint32_t n, State *
}
static CodeGoIf *code_goif(code_alc_t &alc, CodeGoIf::Kind kind, const Span *sp,
uint32_t nsp, State *next, bool skip, uint32_t eof, const opt_t *opts)
uint32_t nsp, State *next, bool skip, uint32_t eof)
{
CodeGoIf *x = alc.alloct<CodeGoIf>(1);
x->kind = kind;
if (kind == CodeGoIf::BINARY) {
x->goifb = code_goifb(alc, sp, nsp, next, skip, eof, opts);
x->goifb = code_goifb(alc, sp, nsp, next, skip, eof);
}
else {
x->goifl = code_goifl(alc, sp, nsp, next, skip, eof, opts);
x->goifl = code_goifl(alc, sp, nsp, next, skip, eof);
}
return x;
}
static CodeGoSwIf *code_goswif(code_alc_t &alc, const Span *sp, uint32_t nsp,
State *next, bool skip, uint32_t eof, const opt_t *opts)
State *next, bool sflag, bool skip, uint32_t eof)
{
CodeGoSwIf *x = alc.alloct<CodeGoSwIf>(1);
if ((!opts->sFlag && nsp > 2)
if ((!sflag && nsp > 2)
|| (nsp > 8 && (sp[nsp - 2].ub - sp[0].ub <= 3 * (nsp - 2)))) {
x->kind = CodeGoSwIf::SWITCH;
x->gosw = code_gosw(alc, sp, nsp, skip, eof);
}
else if (nsp > 5) {
x->kind = CodeGoSwIf::IF;
x->goif = code_goif(alc, CodeGoIf::BINARY, sp, nsp, next, skip, eof, opts);
x->goif = code_goif(alc, CodeGoIf::BINARY, sp, nsp, next, skip, eof);
}
else {
x->kind = CodeGoSwIf::IF;
x->goif = code_goif(alc, CodeGoIf::LINEAR, sp, nsp, next, skip, eof, opts);
x->goif = code_goif(alc, CodeGoIf::LINEAR, sp, nsp, next, skip, eof);
}
return x;
}
@@ -246,7 +241,7 @@ static uint32_t unmap(Span *new_span, const Span *old_span, uint32_t old_nspans,
static CodeGoBm *code_gobm(code_alc_t &alc, const Span *span, uint32_t nSpans,
const Span *hspan, uint32_t hSpans, const CodeBmState *bm, State *next,
uint32_t eof, const opt_t *opts)
bool sflag, uint32_t eof)
{
CodeGoBm *x = alc.alloct<CodeGoBm>(1);
x->bitmap = bm;
@@ -256,11 +251,11 @@ static CodeGoBm *code_gobm(code_alc_t &alc, const Span *span, uint32_t nSpans,
Span *bspan = allocate<Span>(nSpans); // temporary
uint32_t bSpans = unmap (bspan, span, nSpans, bm->state);
x->lgo = bSpans == 0 ? NULL
: code_goswif(alc, bspan, bSpans, next, false, eof, opts);
: code_goswif(alc, bspan, bSpans, next, sflag, false, eof);
// if there are any low spans, then next state for high spans
// must be NULL to trigger explicit goto generation in linear 'if'
x->hgo = hSpans == 0 ? NULL
: code_goswif(alc, hspan, hSpans, x->lgo ? NULL : next, false, eof, opts);
: code_goswif(alc, hspan, hSpans, x->lgo ? NULL : next, sflag, false, eof);
x->bitmap->state->label->used = true;
operator delete(bspan);
@@ -287,11 +282,11 @@ static CodeGoCpTable *code_gocp_table(code_alc_t &alc, const Span * span, uint32
}
static CodeGoCp *code_gocp(code_alc_t &alc, const Span *span, uint32_t nSpans,
const Span *hspan, uint32_t hSpans, State *next, uint32_t eof, const opt_t *opts)
const Span *hspan, uint32_t hSpans, State *next, bool sflag, uint32_t eof)
{
CodeGoCp *x = alc.alloct<CodeGoCp>(1);
x->hgo = hSpans == 0 ? NULL
: code_goswif(alc, hspan, hSpans, next, false, eof, opts);
: code_goswif(alc, hspan, hSpans, next, sflag, false, eof);
x->table = code_gocp_table(alc, span, nSpans);
return x;
}
@@ -361,18 +356,18 @@ void code_go(code_alc_t &alc, CodeGo *go, const State *from, const opt_t *opts,
&& !low_spans_have_tags) {
go->kind = CodeGo::CPGOTO;
go->gocp = code_gocp(alc, go->span, go->nspans, hspan, hSpans, from->next,
eof, opts);
opts->sFlag, eof);
}
else if (opts->bFlag && !part_skip && nBitmaps > 0) {
go->kind = CodeGo::BITMAP;
go->gobm = code_gobm(alc, go->span, go->nspans, hspan, hSpans, bm,
from->next, eof, opts);
from->next, opts->sFlag, eof);
bitmap->used = true;
}
else {
go->kind = CodeGo::SWITCH_IF;
go->goswif = code_goswif(alc, go->span, go->nspans, from->next,
part_skip, eof, opts);
go->goswif = code_goswif(alc, go->span, go->nspans, from->next, opts->sFlag,
part_skip, eof);
}
}
+121 -234
View File
@@ -9,44 +9,18 @@
namespace re2c {
static OutputBlock *find_block_with_name(CodegenCtxPass1 &ctx, const char *name)
static const OutputBlock *find_block_with_name(CodegenCtxPass1 &ctx,
const char *name, const char *where)
{
const blocks_t &cblocks = ctx.global->cblocks;
for (size_t i = 0; i < cblocks.size(); ++i) {
if (cblocks[i]->name.compare(name) == 0) return cblocks[i];
}
const blocks_t &hblocks = ctx.global->hblocks;
for (size_t i = 0; i < hblocks.size(); ++i) {
if (hblocks[i]->name.compare(name) == 0) return hblocks[i];
const blocks_t &blocks = *ctx.global->pblocks;
for (size_t i = 0; i < blocks.size(); ++i) {
const OutputBlock *b = blocks[i];
if (b->name.compare(name) == 0) return b;
}
error("cannot find block '%s' listed in `%s` directive", name, where);
return NULL;
}
static void find_blocks(CodegenCtxPass1 &ctx, const BlockNameList *names,
blocks_t &blocks, const char *directive)
{
blocks.clear();
for (const BlockNameList *p = names; p; p = p->next) {
OutputBlock *b = find_block_with_name(ctx, p->name);
if (b) {
blocks.push_back(b);
} else {
error("cannot find block '%s' listed in `%s` directive", p->name, directive);
exit(1);
}
}
}
static std::string output_cond_get(const opt_t *opts)
{
return opts->cond_get + (opts->cond_get_naked ? "" : "()");
}
static std::string output_state_get(const opt_t *opts)
{
return opts->state_get + (opts->state_get_naked ? "" : "()");
}
void gen_tags(Scratchbuf &buf, const opt_t *opts, Code *code, const tagnames_t &tags)
{
DASSERT(code->kind == CODE_STAGS || code->kind == CODE_MTAGS);
@@ -75,18 +49,6 @@ void gen_tags(Scratchbuf &buf, const opt_t *opts, Code *code, const tagnames_t &
code->raw.data = buf.flush();
}
static void add_tags_from_blocks(const blocks_t &blocks, tagnames_t &tags, bool multival)
{
for (size_t i = 0; i < blocks.size(); ++i) {
const OutputBlock &block = *blocks[i];
if (multival) {
tags.insert(block.mtags.begin(), block.mtags.end());
} else {
tags.insert(block.stags.begin(), block.stags.end());
}
}
}
static void expand_tags_directive(CodegenCtxPass1 &ctx, Code *code)
{
DASSERT(code->kind == CODE_STAGS || code->kind == CODE_MTAGS);
@@ -96,24 +58,31 @@ static void expand_tags_directive(CodegenCtxPass1 &ctx, Code *code)
}
Scratchbuf &buf = ctx.global->scratchbuf;
bool multival = (code->kind == CODE_MTAGS);
bool oneval = (code->kind == CODE_STAGS);
tagnames_t tags;
if (code->fmt.block_names == NULL) {
// Gather tags from all blocks in the output and header files.
add_tags_from_blocks(ctx.global->cblocks, tags, multival);
add_tags_from_blocks(ctx.global->hblocks, tags, multival);
// Use the global set of tags accumulated from all blocks.
gen_tags(buf, ctx.block->opts, code,
oneval ? ctx.global->stags : ctx.global->mtags);
} else {
// Gather tags from the blocks on the list.
const char *directive = multival ? "mtags:re2c" : "stags:re2c";
find_blocks(ctx, code->fmt.block_names, ctx.global->tmpblocks, directive);
add_tags_from_blocks(ctx.global->tmpblocks, tags, multival);
const char *directive = oneval ? "stags:re2c" : "mtags:re2c";
tagnames_t tags;
for (BlockNameList *p = code->fmt.block_names; p; p = p->next) {
const OutputBlock *b = find_block_with_name(ctx, p->name, directive);
if (!b) exit(1);
if (oneval) {
tags.insert(b->stags.begin(), b->stags.end());
} else {
tags.insert(b->mtags.begin(), b->mtags.end());
}
}
gen_tags(buf, ctx.block->opts, code, tags);
}
gen_tags(buf, ctx.block->opts, code, tags);
}
static void gen_cond_enum(Scratchbuf &buf, code_alc_t &alc, Code *code, const opt_t *opts,
const StartConds &conds)
static void gen_cond_enum(Scratchbuf &buf, code_alc_t &alc, Code *code,
const opt_t *opts, const uniq_vector_t<std::string> &conds)
{
DASSERT(opts->target == TARGET_CODE);
@@ -124,11 +93,10 @@ static void gen_cond_enum(Scratchbuf &buf, code_alc_t &alc, Code *code, const op
for (size_t i = 0; i < conds.size(); ++i) {
if (i > 0 && sep) buf.cstr(sep);
std::ostringstream s(fmt);
// The main substitution (the one allowing unnamed sigil) must go last, or
// else it will erroneously substitute all the named ones.
size_t cid = opts->loop_switch ? conds[i].number : i;
argsubst(s, opts->api_sigil, "num", false, cid);
argsubst(s, opts->api_sigil, "cond", true, conds[i].name);
// The main substitution (the one allowing unnamed sigil) must go
// last, or else it will erroneously substitute all the named ones.
argsubst(s, opts->api_sigil, "num", false, i);
argsubst(s, opts->api_sigil, "cond", true, conds[i]);
buf.str(s.str());
}
buf.cstr("\n");
@@ -138,7 +106,7 @@ static void gen_cond_enum(Scratchbuf &buf, code_alc_t &alc, Code *code, const op
code->raw.data = buf.flush();
} else {
const char *start = NULL, *end = NULL;
const char *text, *start = NULL, *end = NULL;
CodeList *stmts = code_list(alc);
CodeList *block = code_list(alc);
@@ -146,23 +114,15 @@ static void gen_cond_enum(Scratchbuf &buf, code_alc_t &alc, Code *code, const op
start = buf.cstr("enum ").str(opts->yycondtype).cstr(" {").flush();
end = "};";
for (size_t i = 0; i < conds.size(); ++i) {
buf.str(conds[i].name);
if (opts->loop_switch) {
buf.cstr(" = ").u32(conds[i].number);
}
append(block, code_text(alc, buf.cstr(",").flush()));
text = buf.str(conds[i]).cstr(",").flush();
append(block, code_text(alc, text));
}
} else if (opts->lang == LANG_GO) {
start = buf.cstr("const (").flush();
end = ")";
for (size_t i = 0; i < conds.size(); ++i) {
buf.str(conds[i].name);
if (opts->loop_switch) {
buf.cstr(" = ").u32(conds[i].number);
} else if (i == 0) {
buf.cstr(" = iota");
}
append(block, code_text(alc, buf.flush()));
text = buf.str(conds[i]).cstr(i == 0 ? " = iota" : "").flush();
append(block, code_text(alc, text));
}
}
@@ -176,43 +136,6 @@ static void gen_cond_enum(Scratchbuf &buf, code_alc_t &alc, Code *code, const op
}
}
static void add_condition_from_block(const OutputBlock &block, StartConds &conds,
const StartCond &cond)
{
// Condition prefix is specific to the block that defines it. If a few blocks define
// conditions with the same name, but a different prefix, they should have different
// enum entries.
StartCond sc = cond;
sc.name = block.opts->condEnumPrefix + sc.name;
for (size_t i = 0; i < conds.size(); ++i) {
if (conds[i].name == sc.name) {
if (conds[i].number == sc.number) {
// A duplicate condition, it's not an error but don't add it.
return;
} else {
// An error: conditions with idetical names but different numbers.
error("cannot generate condition enumeration: conditon '%s' has "
"different numbers in different blocks (use `re2c:condenumprefix` "
"configuration to set per-block prefix)", sc.name.c_str());
exit(1);
}
}
}
conds.push_back(sc);
}
static void add_conditions_from_blocks(const blocks_t &blocks, StartConds &conds)
{
for (size_t i = 0; i < blocks.size(); ++i) {
const OutputBlock &block = *blocks[i];
for (size_t i = 0; i < block.conds.size(); ++i) {
add_condition_from_block(block, conds, block.conds[i]);
}
}
}
static void expand_cond_enum(CodegenCtxPass1 &ctx, Code *code)
{
Scratchbuf &buf = ctx.global->scratchbuf;
@@ -228,34 +151,37 @@ static void expand_cond_enum(CodegenCtxPass1 &ctx, Code *code)
return;
}
StartConds conds;
if (code->fmt.block_names == NULL) {
// Gather conditions from all blocks in the output and header files.
add_conditions_from_blocks(ctx.global->cblocks, conds);
add_conditions_from_blocks(ctx.global->hblocks, conds);
// Use the global set of conditions accumulated from all blocks.
gen_cond_enum(buf, alc, code, globopts, ctx.global->conds);
} else {
// Gather conditions from the blocks on the list.
find_blocks(ctx, code->fmt.block_names, ctx.global->tmpblocks, "types:re2c");
add_conditions_from_blocks(ctx.global->tmpblocks, conds);
uniq_vector_t<std::string> conds;
for (BlockNameList *p = code->fmt.block_names; p; p = p->next) {
const OutputBlock *b = find_block_with_name(ctx, p->name, "types:re2c");
if (!b) exit(1);
for (size_t i = 0; i < b->conds.size(); ++i) {
// Condition prefix is specific to the block that defines it.
// If a few blocks define conditions with the same name, but a
// different prefix, they result in different enum entries.
conds.find_or_add(b->opts->condEnumPrefix + b->conds[i]);
}
}
gen_cond_enum(buf, alc, code, globopts, conds);
}
// Do not generate empty condition enum. Some compilers or language standards
// allow it, but generally it's more likely to indicate an error in user code.
if (conds.empty()) {
code->kind = CODE_EMPTY;
return;
}
gen_cond_enum(buf, alc, code, globopts, conds);
}
static void gen_state_goto_cases(CodegenCtxPass1 &ctx, CodeCases *cases,
const OutputBlock *block)
{
code_alc_t &alc = ctx.global->allocator;
for (storable_states_t::const_iterator i = block->fill_goto.begin();
i != block->fill_goto.end(); ++i) {
append(cases, code_case_number(alc, i->second, static_cast<int32_t>(i->first)));
uint32_t index_count = block->fill_index_end - block->fill_index_start;
DASSERT(index_count <= block->fill_goto.size());
for (uint32_t i = 0; i < index_count; ++i) {
append(cases, code_case_number(alc, block->fill_goto[i],
static_cast<int32_t>(i + block->fill_index_start)));
}
}
@@ -274,10 +200,6 @@ static void gen_state_goto(CodegenCtxPass1 &ctx, Code *code)
return;
}
// Loop/switch approach is handled differently (by appending special cases
// to the state switch).
DASSERT(!globopts->loop_switch);
Scratchbuf &o = ctx.global->scratchbuf;
code_alc_t &alc = ctx.global->allocator;
const char *text;
@@ -323,18 +245,19 @@ static void gen_state_goto(CodegenCtxPass1 &ctx, Code *code)
}
} else {
// Generate a switch for all specified named blocks.
blocks_t &blocks = ctx.global->tmpblocks;
find_blocks(ctx, code->fmt.block_names, blocks, "getstate:re2c");
for (size_t i = 0; i < blocks.size(); ++i) {
const OutputBlock *b = blocks[i];
for (BlockNameList *p = code->fmt.block_names; p; p = p->next) {
const OutputBlock *b = find_block_with_name(ctx, p->name, "getstate:re2c");
if (!b) exit(1);
if (!b->start_label) {
error("block '%s' does not generate code, so it should not be"
" listed in `getstate:re2c` directive", b->name.c_str());
" listed in `getstate:re2c` directive", p->name);
exit(1);
}
gen_state_goto_cases(ctx, cases, b);
// Use start label of the first block on the list.
if (!bstart) bstart = b;
gen_state_goto_cases(ctx, cases, b);
}
}
@@ -360,7 +283,7 @@ static void gen_state_goto(CodegenCtxPass1 &ctx, Code *code)
}
CodeList *stmts = code_list(alc);
text = o.str(output_state_get(globopts)).flush();
text = o.str(globopts->state_get).cstr(globopts->state_get_naked ? "" : "()").flush();
append(stmts, code_switch(alc, text, cases));
if (globopts->bUseStateNext) {
@@ -399,45 +322,6 @@ static void gen_yyaccept_def(const opt_t *opts, Code *code, bool used_yyaccept)
}
}
static void gen_yystate_def(CodegenCtxPass1 &ctx, Code *code)
{
const opt_t *opts = ctx.block->opts;
Scratchbuf &o = ctx.global->scratchbuf;
if (opts->loop_switch) {
code->kind = CODE_VAR;
code->var.name = o.str(opts->yystate).flush();
if (opts->fFlag) {
// With storable state `yystate` should be initialized to YYGETSTATE.
// Since there is a -1 case, `yystate` should have a signed type.
// If conditions are also used, YYGETSTATE takes priority over YYGETCONDITION,
// because the lexer may be reentered after an YYFILL invocation. In that case
// we use YYSETSTATE instead of YYSETCONDITION in the final states.
code->var.type = "int";
code->var.init = o.str(output_state_get(opts)).flush();
} else if (opts->cFlag) {
// Else with start conditions yystate should be initialized to YYGETCONDITION.
code->var.type = "unsigned int";
code->var.init = o.str(output_cond_get(opts)).flush();
} else {
// Else it should be the start DFA state (always case 0 with --loop-switch).
code->var.type = "unsigned int";
code->var.init = "0";
}
} else {
code->kind = CODE_EMPTY;
}
}
static size_t max_among_blocks(const blocks_t &blocks, size_t max, CodeKind kind)
{
for (size_t i = 0; i < blocks.size(); ++i) {
const OutputBlock &block = *blocks[i];
max = std::max(max, kind == CODE_MAXFILL ? block.max_fill : block.max_nmatch);
}
return max;
}
static void gen_yymax(CodegenCtxPass1 &ctx, Code *code)
{
const opt_t *opts = ctx.block->opts;
@@ -448,19 +332,22 @@ static void gen_yymax(CodegenCtxPass1 &ctx, Code *code)
return;
}
CodeKind kind = code->kind;
const char *dirname = kind == CODE_MAXFILL ? "max:re2c" : "maxnmatch:re2c";
const char *varname = kind == CODE_MAXFILL ? "YYMAXFILL" : "YYMAXNMATCH";
bool is_maxfill = (code->kind == CODE_MAXFILL);
const char *dirname = is_maxfill ? "max:re2c" : "maxnmatch:re2c";
const char *varname = is_maxfill ? "YYMAXFILL" : "YYMAXNMATCH";
size_t max = 1;
size_t max;
if (code->fmt.block_names == NULL) {
// Gather max value from all blocks in the output and header files.
max = max_among_blocks(ctx.global->cblocks, max, kind);
max = max_among_blocks(ctx.global->hblocks, max, kind);
// Global maximum in the file.
max = is_maxfill ? ctx.global->max_fill : ctx.global->max_nmatch;
} else {
// Maximum among the blocks listed in the directive.
find_blocks(ctx, code->fmt.block_names, ctx.global->tmpblocks, dirname);
max = max_among_blocks(ctx.global->tmpblocks, max, kind);
max = 0;
for (BlockNameList *p = code->fmt.block_names; p; p = p->next) {
const OutputBlock *b = find_block_with_name(ctx, p->name, dirname);
if (!b) exit(1);
max = std::max(max, is_maxfill ? b->max_fill : b->max_nmatch);
}
}
if (code->fmt.format) {
@@ -501,59 +388,65 @@ static void gen_yymax(CodegenCtxPass1 &ctx, Code *code)
* dispatch shrinks to unconditional jump
*/
static CodeList *gen_cond_goto_binary(CodegenCtxPass1 &ctx, size_t lower, size_t upper)
static std::string output_cond_get(const opt_t *opts)
{
const opt_t *opts = ctx.block->opts;
code_alc_t &alc = ctx.global->allocator;
Scratchbuf &o = ctx.global->scratchbuf;
return opts->cond_get + (opts->cond_get_naked ? "" : "()");
}
static CodeList *gen_cond_goto_binary(Scratchbuf &o, code_alc_t &alc,
const std::vector<std::string> &conds, const opt_t *opts,
size_t lower, size_t upper)
{
CodeList *stmts = code_list(alc);
const char *text;
if (lower == upper) {
o.cstr("goto ").str(opts->condPrefix).str(ctx.block->conds[lower].name);
append(stmts, code_stmt(alc, o.flush()));
} else {
const size_t middle = lower + (upper - lower + 1) / 2;
CodeList *if_then = gen_cond_goto_binary(ctx, lower, middle - 1);
CodeList *if_else = gen_cond_goto_binary(ctx, middle, upper);
o.str(output_cond_get(opts)).cstr(" < ").u64(middle);
append(stmts, code_if_then_else(alc, o.flush(), if_then, if_else));
text = o.cstr("goto ").str(opts->condPrefix).str(conds[lower]).flush();
append(stmts, code_stmt(alc, text));
}
else {
const size_t middle = lower + (upper - lower + 1) / 2;
text = o.str(output_cond_get(opts)).cstr(" < ").u64(middle).flush();
CodeList *if_then = gen_cond_goto_binary(o, alc, conds, opts, lower, middle - 1);
CodeList *if_else = gen_cond_goto_binary(o, alc, conds, opts, middle, upper);
append(stmts, code_if_then_else(alc, text, if_then, if_else));
}
return stmts;
}
static void gen_cond_goto(CodegenCtxPass1 &ctx, Code *code)
static void gen_cond_goto(Scratchbuf &o, code_alc_t &alc, Code *code,
const std::vector<std::string> &conds, const opt_t *opts, Msg &msg,
bool warn_cond_ord, const loc_t &loc)
{
const opt_t *opts = ctx.block->opts;
code_alc_t &alc = ctx.global->allocator;
Scratchbuf &o = ctx.global->scratchbuf;
const StartConds &conds = ctx.block->conds;
bool warn_cond_ord = ctx.global->warn_cond_ord;
const size_t ncond = conds.size();
CodeList *stmts = code_list(alc);
const char *text;
if (opts->target == TARGET_DOT) {
for (size_t i = 0; i < ncond; ++i) {
const std::string &cond = conds[i].name;
const std::string &cond = conds[i];
text = o.cstr("0 -> ").str(cond).cstr(" [label=\"state=").str(cond)
.cstr("\"]").flush();
append(stmts, code_text(alc, text));
}
} else {
}
else {
if (opts->gFlag) {
text = o.cstr("goto *").str(opts->yyctable).cstr("[")
.str(output_cond_get(opts)).cstr("]").flush();
append(stmts, code_stmt(alc, text));
} else if (opts->sFlag) {
}
else if (opts->sFlag) {
warn_cond_ord &= ncond > 1;
append(stmts, gen_cond_goto_binary(ctx, 0, ncond - 1));
} else {
append(stmts, gen_cond_goto_binary(o, alc, conds, opts, 0, ncond - 1));
}
else {
warn_cond_ord = false;
CodeCases *ccases = code_cases(alc);
for (size_t i = 0; i < ncond; ++i) {
const std::string &cond = conds[i].name;
const std::string &cond = conds[i];
CodeList *body = code_list(alc);
text = o.cstr("goto ").str(opts->condPrefix).str(cond).flush();
@@ -569,7 +462,7 @@ static void gen_cond_goto(CodegenCtxPass1 &ctx, Code *code)
// see note [condition order]
warn_cond_ord &= opts->header_file.empty();
if (warn_cond_ord) {
ctx.global->msg.warn.condition_order(ctx.block->loc);
msg.warn.condition_order(loc);
}
}
@@ -578,23 +471,22 @@ static void gen_cond_goto(CodegenCtxPass1 &ctx, Code *code)
code->block.fmt = CodeBlock::RAW;
}
static void gen_cond_table(CodegenCtxPass1 &ctx, Code *code)
static void gen_cond_table(Scratchbuf &o, code_alc_t &alc, Code *code,
const std::vector<std::string> &conds, const opt_t *opts)
{
const opt_t *opts = ctx.block->opts;
code_alc_t &alc = ctx.global->allocator;
Scratchbuf &o = ctx.global->scratchbuf;
const StartConds &conds = ctx.block->conds;
const size_t ncond = conds.size();
CodeList *stmts = code_list(alc);
const char *text;
o.cstr("static void *").str(opts->yyctable).cstr("[").u64(ncond).cstr("] = {");
append(stmts, code_text(alc, o.flush()));
text = o.cstr("static void *").str(opts->yyctable).cstr("[").u64(ncond)
.cstr("] = {").flush();
append(stmts, code_text(alc, text));
CodeList *block = code_list(alc);
for (size_t i = 0; i < ncond; ++i) {
o.cstr("&&").str(opts->condPrefix).str(conds[i].name).cstr(",");
append(block, code_text(alc, o.flush()));
text = o.cstr("&&").str(opts->condPrefix).str(conds[i]).cstr(",").flush();
append(block, code_text(alc, text));
}
append(stmts, code_block(alc, block, CodeBlock::INDENTED));
@@ -616,6 +508,9 @@ static void expand_pass_1_list(CodegenCtxPass1 &ctx, CodeList *stmts)
void expand_pass_1(CodegenCtxPass1 &ctx, Code *code)
{
const opt_t *opts = ctx.block->opts;
Scratchbuf &buf = ctx.global->scratchbuf;
code_alc_t &alc = ctx.global->allocator;
switch (code->kind) {
case CODE_BLOCK:
expand_pass_1_list(ctx, code->block.stmts);
@@ -629,9 +524,6 @@ void expand_pass_1(CodegenCtxPass1 &ctx, Code *code)
expand_pass_1_list(ctx, x->body);
}
break;
case CODE_LOOP:
expand_pass_1_list(ctx, code->loop);
break;
case CODE_STAGS:
case CODE_MTAGS:
expand_tags_directive(ctx, code);
@@ -646,17 +538,15 @@ void expand_pass_1(CodegenCtxPass1 &ctx, Code *code)
case CODE_YYACCEPT:
gen_yyaccept_def(opts, code, ctx.block->used_yyaccept);
break;
case CODE_YYSTATE:
gen_yystate_def(ctx, code);
break;
case CODE_COND_ENUM:
expand_cond_enum(ctx, code);
break;
case CODE_COND_GOTO:
gen_cond_goto(ctx, code);
gen_cond_goto(buf, alc, code, ctx.block->conds, opts,
ctx.global->msg, ctx.global->warn_cond_ord, ctx.block->loc);
break;
case CODE_COND_TABLE:
gen_cond_table(ctx, code);
gen_cond_table(buf, alc, code, ctx.block->conds, opts);
break;
case CODE_STATE_GOTO:
gen_state_goto(ctx, code);
@@ -728,9 +618,6 @@ void expand_pass_2(CodegenCtxPass2 &ctx, Code *code)
expand_pass_2_list(ctx, x->body);
}
break;
case CODE_LOOP:
expand_pass_2_list(ctx, code->loop);
break;
case CODE_LABEL:
gen_label(ctx.scratchbuf, ctx.opts, code);
break;
+49 -138
View File
@@ -40,9 +40,7 @@ static void emit_state(Output &output, const State *s, CodeList *stmts)
Scratchbuf &o = output.scratchbuf;
const char *text;
if (!opts->loop_switch) {
append(stmts, code_nlabel(alc, s->label));
}
append(stmts, code_nlabel(alc, s->label));
if (opts->dFlag && (s->action.type != Action::INITIAL)) {
text = o.str(opts->yydebug).cstr("(").label(*s->label).cstr(", ")
@@ -51,84 +49,31 @@ static void emit_state(Output &output, const State *s, CodeList *stmts)
}
}
static void gen_storable_state_cases(Output &output, CodeCases *cases)
{
OutputBlock &block = output.block();
const opt_t *opts = block.opts;
code_alc_t &alc = output.allocator;
if (!opts->fFlag || !opts->loop_switch) return;
// TODO: If `re2c:eof` is not used, some of these cases are redundant (they contain a
// single transition to the DFA state that has the corresponding YYFILL invocation).
for (storable_states_t::const_iterator i = block.fill_goto.begin();
i != block.fill_goto.end(); ++i) {
append(cases, code_case_number(alc, i->second, static_cast<int32_t>(i->first)));
}
CodeList *start_case = code_list(alc);
if (opts->lang == LANG_GO) {
append(start_case, code_stmt(alc, "fallthrough"));
}
prepend(cases, code_case_number(alc, start_case, -1));
}
void gen_dfa_as_blocks_with_labels(Output &output, const DFA &dfa, CodeList *stmts)
void DFA::emit_body(Output &output, CodeList *stmts) const
{
const opt_t *opts = output.block().opts;
code_alc_t &alc = output.allocator;
Scratchbuf &o = output.scratchbuf;
const char *text;
gen_settags(output, stmts, dfa, dfa.tags0, /*delayed*/ false);
gen_settags(output, stmts, *this, tags0, false /* delayed */);
// If DFA has transitions into the initial state and --eager-skip option is not used,
// then the initial state must have a YYSKIP statement that must be bypassed when
// first entering the DFA. With --loop-switch that would be impossible, because there
// can be no transitions in the middle of a state.
DASSERT(!opts->loop_switch);
if (dfa.head->label->used && !opts->eager_skip) {
dfa.initial_label->used = true;
o.cstr("goto ").str(opts->labelPrefix).label(*dfa.initial_label);
append(stmts, code_stmt(alc, o.flush()));
// If DFA has transitions to initial state, then initial state
// has a piece of code that advances input position. Wee must
// skip it when entering DFA.
if (head->label->used) {
initial_label->used = true;
text = o.cstr("goto ").str(opts->labelPrefix).label(*initial_label).flush();
append(stmts, code_stmt(alc, text));
}
for (State *s = dfa.head; s; s = s->next) {
for (State * s = head; s; s = s->next) {
emit_state(output, s, stmts);
emit_action(output, dfa, s, stmts);
gen_go(output, dfa, &s->go, s, stmts);
emit_action(output, *this, s, stmts);
gen_go(output, *this, &s->go, s, stmts);
}
}
void gen_dfa_as_switch_cases(Output &output, DFA &dfa, CodeCases *cases)
{
const opt_t *opts = output.block().opts;
code_alc_t &alc = output.allocator;
DASSERT(opts->loop_switch);
DASSERT(dfa.tags0 == TCID0);
for (State *s = dfa.head; s; s = s->next) {
CodeList *body = code_list(alc);
emit_state(output, s, body);
emit_action(output, dfa, s, body);
gen_go(output, dfa, &s->go, s, body);
append(cases, code_case_number(alc, body, static_cast<int32_t>(s->label->index)));
}
}
void wrap_dfas_in_loop_switch(Output &output, CodeList *stmts, CodeCases *cases)
{
const opt_t *opts = output.block().opts;
code_alc_t &alc = output.allocator;
DASSERT(opts->loop_switch);
CodeList* loop = code_list(alc);
gen_storable_state_cases(output, cases);
append(loop, code_switch(alc, opts->yystate.c_str(), cases));
append(stmts, code_loop(alc, loop));
}
void DFA::emit_dot(Output &output, CodeList *program) const
{
code_alc_t &alc = output.allocator;
@@ -198,50 +143,28 @@ void gen_code(Output &output, dfas_t &dfas)
const bool first = i == b;
DFA &dfa = *(*i);
if (opts->loop_switch && (first || opts->target == TARGET_SKELETON)) {
// With loop/switch there are no labels, and each block has its own state
// switch where all conditions are joined. Restart state counter from zero so
// that cases start from zero. With skeleton conditions are separate.
output.label_counter = 0;
if (first) {
if (opts->startlabel_force) {
// User-enforced start label.
dfa.start_label = new_label(alc, output.label_counter++);
dfa.start_label->used = true;
} else if (opts->fFlag) {
// Start label is needed in `-f` mode: it points to state 0 (the
// beginning of block, before condition dispatch in `-c` mode).
dfa.start_label = new_label(alc, output.label_counter++);
}
oblock.start_label = dfa.start_label;
}
if (!opts->loop_switch) {
if (first) {
if (opts->startlabel_force) {
// User-enforced start label.
dfa.start_label = new_label(alc, output.label_counter++);
dfa.start_label->used = true;
} else if (opts->fFlag) {
// Start label is needed in `-f` mode: it points to state 0 (the
// beginning of block, before condition dispatch in `-c` mode).
dfa.start_label = new_label(alc, output.label_counter++);
}
oblock.start_label = dfa.start_label;
}
// Initial label points to the beginning of the DFA (after condition
// dispatch in `-c` mode).
dfa.initial_label = new_label(alc, output.label_counter++);
dfa.head->action.set_initial();
}
// Initial label points to the beginning of the DFA (after condition
// dispatch in `-c` mode).
dfa.initial_label = new_label(alc, output.label_counter++);
dfa.head->action.set_initial();
for (State *s = dfa.head; s; s = s->next) {
s->label = new_label(alc, output.label_counter++);
}
// With loop/switch storable states need their own cases in the state switch, as
// they have some logic on top of transition to the state that invoked YYFILL.
// Give them continuous indices after the last state index.
if (opts->loop_switch && opts->fFlag) {
oblock.fill_index = output.label_counter;
}
if (!dfa.cond.empty()) {
// If loop/switch is used, condition numbers are the numeric indices of their
// initial DFA state. Otherwise we do not assign explicit numbers, and
// conditions are implicitly assigned consecutive numbers starting from zero.
StartCond sc = {dfa.cond, opts->loop_switch ? dfa.head->label->index : 0};
oblock.conds.push_back(sc);
}
if (opts->bFlag) {
dfa.bitmap = code_bitmap(alc, std::min(dfa.ubChar, 256u));
for (State *s = dfa.head; s; s = s->next) {
@@ -282,7 +205,6 @@ void gen_code(Output &output, dfas_t &dfas)
const char *text;
CodeList *program1 = code_list(alc);
CodeCases *cases = code_cases(alc);
for (i = b; i != e; ++i) {
const bool first = i == b;
DFA &dfa = *(*i);
@@ -298,9 +220,6 @@ void gen_code(Output &output, dfas_t &dfas)
append(program1, code_yych_decl(alc));
append(program1, code_yyaccept_def(alc));
}
if (first) {
append(program1, code_yystate_def(alc));
}
if (!is_cond_block && bms) {
append(program1, bms);
@@ -310,7 +229,7 @@ void gen_code(Output &output, dfas_t &dfas)
append(program1, code_cond_table(alc));
}
if (opts->fFlag && !output.state_goto && !opts->loop_switch) {
if (opts->fFlag && !output.state_goto) {
append(program1, code_state_goto(alc,
block_list_for_implicit_state_goto(alc, oblock)));
output.state_goto = true;
@@ -327,11 +246,12 @@ void gen_code(Output &output, dfas_t &dfas)
append(program1, code_slabel(alc, text));
}
if (is_cond_block && !opts->loop_switch) {
if (!output.cond_goto) {
append(program1, code_cond_goto(alc));
output.cond_goto = true;
}
if (is_cond_block && !output.cond_goto) {
append(program1, code_cond_goto(alc));
output.cond_goto = true;
}
if (is_cond_block && !dfa.cond.empty()) {
if (opts->condDivider.length()) {
o.str(opts->condDivider);
argsubst(o.stream(), opts->condDividerParam, "cond", true, dfa.cond);
@@ -341,28 +261,19 @@ void gen_code(Output &output, dfas_t &dfas)
append(program1, code_slabel(alc, text));
}
if (!opts->loop_switch) {
// In the goto/label mode, generate DFA states as blocks of code preceded
// with labels, and `goto` transitions between states.
CodeList *body = code_list(alc);
gen_dfa_as_blocks_with_labels(output, dfa, body);
if (is_cond_block && bms) {
CodeList *block = code_list(alc);
append(block, bms);
append(block, body);
append(program1, code_block(alc, block, CodeBlock::WRAPPED));
} else {
append(program1, body);
}
} else {
// In the loop/switch mode append all DFA states as cases of the `yystate`
// switch. Merge DFAs for different conditions together in one switch.
DASSERT(!bms);
gen_dfa_as_switch_cases(output, dfa, cases);
// generate code for DFA
CodeList *body = code_list(alc);
dfa.emit_body(output, body);
if (is_cond_block && bms) {
CodeList *block = code_list(alc);
append(block, bms);
append(block, body);
append(program1, code_block(alc, block, CodeBlock::WRAPPED));
}
else {
append(program1, body);
}
}
if (opts->loop_switch) {
wrap_dfas_in_loop_switch(output, program1, cases);
}
const bool prolog = (opts->fFlag && opts->gFlag)
+42 -12
View File
@@ -14,6 +14,7 @@
#include "src/util/file_utils.h"
#include "src/util/string_utils.h"
#include "src/util/temp_file.h"
#include "src/util/uniq_vector.h"
namespace re2c {
@@ -58,8 +59,8 @@ OutputBlock::OutputBlock(InputBlockKind kind, const std::string &name,
, max_fill(1)
, max_nmatch(1)
, start_label(NULL)
, fill_index(0)
, fill_state(0)
, fill_index_start(0)
, fill_index_end(0)
, fill_goto()
{}
@@ -74,7 +75,7 @@ Output::Output(Msg &msg)
, pblocks(&cblocks)
, label_counter(0)
, state_goto(false)
, cond_enum_autogen(true)
, cond_enum_in_hdr(false)
, cond_goto(false)
, warn_condition_order(true)
, need_header(false)
@@ -168,7 +169,8 @@ void Output::new_block(Opt &opts, InputBlockKind kind, const std::string &name,
b->opts = opts.snapshot();
b->fill_index = total_fill_index;
b->fill_index_start = total_fill_index;
b->fill_index_end = total_fill_index;
pblocks->push_back(b);
@@ -181,7 +183,7 @@ void Output::gather_info_from_block()
{
DASSERT(!pblocks->empty());
const OutputBlock *b = pblocks->back();
total_fill_index = b->fill_index;
total_fill_index = b->fill_index_end;
}
static void fix_first_block_opts(const blocks_t &blocks)
@@ -274,6 +276,23 @@ bool Output::emit_blocks(const std::string &fname, const CodegenCtxGlobal &globa
return true;
}
static void add_symbols(const OutputBlock &block, CodegenCtxGlobal &ctx)
{
DASSERT(!block.name.empty());
const std::string &condenumprefix = block.opts->condEnumPrefix;
for (size_t j = 0; j < block.conds.size(); ++j) {
ctx.conds.find_or_add(condenumprefix + block.conds[j]);
}
const tagnames_t &st = block.stags, &mt = block.mtags;
ctx.stags.insert(st.begin(), st.end());
ctx.mtags.insert(mt.begin(), mt.end());
ctx.max_fill = std::max(ctx.max_fill, block.max_fill);
ctx.max_nmatch = std::max(ctx.max_nmatch, block.max_nmatch);
}
bool Output::emit()
{
if (msg.warn.error()) return false;
@@ -283,31 +302,42 @@ bool Output::emit()
, scratchbuf
, msg
, total_opts
, cblocks
, hblocks
, /*pblocks*/ NULL
, /*tmpblocks*/ blocks_t()
, /*conditions*/ uniq_vector_t<std::string>()
, /*stags*/ tagnames_t()
, /*mtags*/ tagnames_t()
, /*max_fill*/ 1
, /*max_nmatch*/ 1
, warn_condition_order
};
// gather global data accumulated across all blocks and files
for (uint32_t i = 0; i < cblocks.size(); ++i) {
add_symbols (*cblocks[i], ctx);
}
for (uint32_t i = 0; i < hblocks.size(); ++i) {
add_symbols (*hblocks[i], ctx);
}
// global options are last block's options
const opt_t *opts = block().opts;
bool ok = true;
// Emit header file.
// emit .h file
if (!opts->header_file.empty() || need_header) {
if (opts->cFlag && this->cond_enum_autogen) {
// Old-style -t, --type-headers usage implies condition enum.
// old-style -t, --type-headers usage implies condition generation
if (!ctx.conds.empty() && !this->cond_enum_in_hdr) {
header_mode(true);
wdelay_stmt(0, code_newline(allocator));
wdelay_stmt(0, code_fmt(allocator, CODE_COND_ENUM, NULL, NULL, NULL));
header_mode(false);
}
ctx.pblocks = &hblocks;
ok &= emit_blocks(opts->header_file, ctx);
}
// Emit output file.
// emit .c file
ctx.pblocks = &cblocks;
ok &= emit_blocks(opts->output_file, ctx);
+68 -116
View File
@@ -226,7 +226,54 @@ void emit_accept(Output &output, CodeList *stmts, const DFA &dfa, const accept_t
append(stmts, code_switch(alc, text, cases));
}
static void gen_setstate(Output &output, CodeList *stmts, const char *fillidx)
void emit_rule(Output &output, CodeList *stmts, const DFA &dfa, size_t rule_idx)
{
const opt_t *opts = output.block().opts;
const Rule &rule = dfa.rules[rule_idx];
const SemAct *semact = rule.semact;
const std::string &cond = semact->cond;
code_alc_t &alc = output.allocator;
Scratchbuf &o = output.scratchbuf;
std::string s;
const char *text;
gen_fintags(output, stmts, dfa, rule);
if (opts->target == TARGET_SKELETON) {
emit_skeleton_action(output, stmts, dfa, rule_idx);
}
else {
if (!cond.empty() && dfa.cond != cond) {
o.str(opts->cond_set);
argsubst(o.stream(), opts->cond_set_arg, "cond", true,
opts->condEnumPrefix + cond);
if (opts->cond_set_naked) {
append(stmts, code_text(alc, o.flush()));
} else {
o.cstr("(").str(opts->condEnumPrefix).str(cond).cstr(")");
append(stmts, code_stmt(alc, o.flush()));
}
}
if (!semact->autogen) {
if (!dfa.setup.empty()) {
text = o.str(dfa.setup).flush();
append(stmts, code_text(alc, text));
}
append(stmts, code_line_info_input(alc, semact->loc));
text = o.str(semact->text).flush();
append(stmts, code_text(alc, text));
append(stmts, code_line_info_output(alc));
}
else if (!cond.empty()) {
o.str(opts->condGoto);
argsubst(o.stream(), opts->condGotoParam, "cond", true,
opts->condPrefix + cond);
append(stmts, code_text(alc, o.flush()));
}
}
}
static void gen_setstate(Output &output, CodeList *stmts, uint32_t fillidx)
{
const opt_t *opts = output.block().opts;
code_alc_t &alc = output.allocator;
@@ -237,85 +284,11 @@ static void gen_setstate(Output &output, CodeList *stmts, const char *fillidx)
if (opts->state_set_naked) {
append(stmts, code_text(alc, o.flush()));
} else {
o.cstr("(").cstr(fillidx).cstr(")");
o.cstr("(").u32(fillidx).cstr(")");
append(stmts, code_stmt(alc, o.flush()));
}
}
static void gen_setcondition(Output &output, CodeList *stmts, const char *cond)
{
const opt_t *opts = output.block().opts;
code_alc_t &alc = output.allocator;
Scratchbuf &o = output.scratchbuf;
o.str(opts->cond_set);
argsubst(o.stream(), opts->cond_set_arg, "cond", true, cond);
if (opts->cond_set_naked) {
append(stmts, code_text(alc, o.flush()));
} else {
o.cstr("(").cstr(cond).cstr(")");
append(stmts, code_stmt(alc, o.flush()));
}
}
void emit_rule(Output &output, CodeList *stmts, const DFA &dfa, size_t rule_idx)
{
const opt_t *opts = output.block().opts;
const Rule &rule = dfa.rules[rule_idx];
const SemAct *semact = rule.semact;
code_alc_t &alc = output.allocator;
Scratchbuf &o = output.scratchbuf;
gen_fintags(output, stmts, dfa, rule);
if (opts->target == TARGET_SKELETON) {
emit_skeleton_action(output, stmts, dfa, rule_idx);
return;
}
bool is_cond_block = !dfa.cond.empty();
const std::string &cond = semact->cond.empty() ? dfa.cond : semact->cond;
const char *next = is_cond_block
? o.str(opts->condEnumPrefix).str(cond).flush() : "0";
if (opts->loop_switch && opts->fFlag) {
// With loop/switch and storable state we need YYSETSTATE in the final state,
// because the user may enclose lexer in an outer loop and expect the next
// iteration to start from the initial DFA state. Since `yystate` is initialized
// to YYGETSTATE, we need to do YYSETSTATE before the user-defined action.
//
// If both storable state and start conditions are used, only one of YYGETSTATE
// and YYGETCONDITION can be used to initialize `yystate`. It must be YYGETSTATE
// because the lexer may be reentered after an YYFILL invocation. Consequently we
// need to use YYSETSTATE instead of YYSETCONDITION in the final state to match
// YYGETSTATE in `yystate` initialization.
gen_setstate(output, stmts, next);
} else if (is_cond_block && cond != dfa.cond) {
// Omit YYSETCONDITION if the current condition is the same as the new one.
gen_setcondition(output, stmts, next);
}
if (!semact->autogen) {
// User-defined semantic action.
if (!dfa.setup.empty()) append(stmts, code_text(alc, o.str(dfa.setup).flush()));
append(stmts, code_line_info_input(alc, semact->loc));
append(stmts, code_text(alc, o.str(semact->text).flush()));
append(stmts, code_line_info_output(alc));
} else if (opts->loop_switch) {
// Autogenerated action for the :=> rule, loop/switch mode: set `yystate` to the
// initial state of the next condition and continue to the head of the loop.
o.str(opts->yystate).cstr(" = ").cstr(next);
append(stmts, code_stmt(alc, o.flush()));
append(stmts, code_stmt(alc, "continue"));
} else {
// Autogenerated action for the :=> rule, goto/label mode: emit `cond:goto`
// configuration with `cond:goto@cond` replaced by the next condition label.
o.str(opts->condGoto);
argsubst(o.stream(), opts->condGotoParam, "cond", true, opts->condPrefix + cond);
append(stmts, code_text(alc, o.flush()));
}
}
static CodeList *gen_fill_falllback(Output &output, const DFA &dfa,
const State *from, const State *to)
{
@@ -357,14 +330,8 @@ static CodeList *gen_fill_falllback(Output &output, const DFA &dfa,
// go to fallback state
fallback->label->used = true;
if (!opts->loop_switch) {
append(fallback_trans, code_stmt(alc, output.scratchbuf.cstr("goto ")
.str(opts->labelPrefix).label(*fallback->label).flush()));
} else {
append(fallback_trans, code_stmt(alc, output.scratchbuf.str(opts->yystate)
.cstr(" = ").label(*fallback->label).flush()));
append(fallback_trans, code_stmt(alc, "continue"));
}
append(fallback_trans, code_stmt(alc, output.scratchbuf.cstr("goto ")
.str(opts->labelPrefix).label(*fallback->label).flush()));
}
else {
// Transition can be elided, because control flow "falls through" to an
@@ -379,7 +346,7 @@ static void gen_fill(Output &output, CodeList *stmts, const DFA &dfa,
{
const opt_t *opts = output.block().opts;
const bool eof_rule = opts->eof != NOEOF;
const uint32_t fillidx = output.block().fill_index - 1;
const uint32_t fillidx = output.block().fill_index_end - 1;
const size_t need = eof_rule ? 1 : from->fill;
code_alc_t &alc = output.allocator;
Scratchbuf &o = output.scratchbuf;
@@ -389,19 +356,13 @@ static void gen_fill(Output &output, CodeList *stmts, const DFA &dfa,
// Transition to YYFILL label from the initial state dispatch.
CodeList *goto_fill = code_list(alc);
if (!opts->loop_switch) {
const char *flabel = gen_fill_label(output, fillidx);
append(goto_fill, code_stmt(alc, o.cstr("goto ").cstr(flabel).flush()));
} else {
o.str(opts->yystate).cstr(" = ").u32(output.block().fill_state);
append(goto_fill, code_stmt(alc, o.flush()));
append(goto_fill, code_stmt(alc, "continue"));
}
const char *flabel = gen_fill_label(output, fillidx);
append(goto_fill, code_stmt(alc, o.cstr("goto ").cstr(flabel).flush()));
CodeList *fill = code_list(alc);
if (opts->fFlag) {
gen_setstate(output, eof_rule ? fill : stmts, o.u32(fillidx).flush());
gen_setstate(output, eof_rule ? fill : stmts, fillidx);
}
if (opts->fill_use) {
@@ -446,7 +407,7 @@ static void gen_fill(Output &output, CodeList *stmts, const DFA &dfa,
}
}
if (opts->fFlag) {
output.block().fill_goto[fillidx] = goto_fill;
output.block().fill_goto.push_back(goto_fill);
}
if (opts->fill_check && fill->head) {
@@ -468,8 +429,7 @@ void gen_fill_and_label(Output &output, CodeList *stmts, const DFA &dfa, const S
const bool need_fill_label = need_fill_on_trans || (need_fill_in_state && opts->fFlag);
if (need_fill_label) {
++output.block().fill_index;
output.block().fill_state = s->label->index;
++output.block().fill_index_end;
}
if (need_fill_in_state) {
@@ -485,8 +445,8 @@ void gen_fill_and_label(Output &output, CodeList *stmts, const DFA &dfa, const S
gen_settags(output, stmts, dfa, s->go.tags, opts->stadfa /* delayed */);
}
if (need_fill_label && !opts->loop_switch) {
const char *flabel = gen_fill_label(output, output.block().fill_index - 1);
if (need_fill_label) {
const char *flabel = gen_fill_label(output, output.block().fill_index_end - 1);
append(stmts, code_slabel(output.allocator, flabel));
}
}
@@ -515,14 +475,8 @@ void gen_goto(Output &output, const DFA &dfa, CodeList *stmts, const State *from
if (!jump.elide) {
jump.to->label->used = true;
if (!opts->loop_switch) {
text = o.cstr("goto ").str(opts->labelPrefix).label(*jump.to->label).flush();
append(stmts, code_stmt(alc, text));
} else {
text = o.str(opts->yystate).cstr(" = ").label(*jump.to->label).flush();
append(stmts, code_stmt(alc, text));
append(stmts, code_stmt(alc, "continue"));
}
text = o.cstr("goto ").str(opts->labelPrefix).label(*jump.to->label).flush();
append(stmts, code_stmt(alc, text));
}
else {
// Goto can be elided, because control flow "falls through" to the
@@ -723,7 +677,7 @@ void gen_fintags(Output &output, CodeList *stmts, const DFA &dfa, const Rule &ru
CodeList *varops = code_list(alc);
CodeList *fixops = code_list(alc);
CodeList *trailops = code_list(alc);
CodeList *fixtrailops = code_list(alc);
CodeList *fixpostops = code_list(alc);
std::string negtag;
@@ -741,9 +695,9 @@ void gen_fintags(Output &output, CodeList *stmts, const DFA &dfa, const Rule &ru
if (trailing(tag)) {
const bool notag = dfa.oldstyle_ctxmarker;
if (generic) {
gen_restorectx(output, trailops, notag ? "" : expr);
gen_restorectx(output, varops, notag ? "" : expr);
} else {
gen_assign(output, trailops, opts->yycursor,
gen_assign(output, varops, opts->yycursor,
notag ? opts->yyctxmarker : expr);
}
} else {
@@ -762,9 +716,9 @@ void gen_fintags(Output &output, CodeList *stmts, const DFA &dfa, const Rule &ru
DASSERT(tag.toplevel);
if (generic) {
if (!fixed_on_cursor) {
gen_restorectx(output, trailops, base);
gen_restorectx(output, fixtrailops, base);
}
gen_shift(output, trailops, -dist, "", false /* unused */);
gen_shift(output, fixtrailops, -dist, "", false /* unused */);
} else {
if (!fixed_on_cursor) {
o.str(opts->yycursor).cstr(" = ").str(base);
@@ -772,7 +726,7 @@ void gen_fintags(Output &output, CodeList *stmts, const DFA &dfa, const Rule &ru
} else if (dist > 0) {
o.str(opts->yycursor).cstr(" -= ").i32(dist);
}
append(trailops, code_stmt(alc, o.flush()));
append(fixtrailops, code_stmt(alc, o.flush()));
}
} else {
DASSERT(!fintags.empty());
@@ -824,11 +778,9 @@ void gen_fintags(Output &output, CodeList *stmts, const DFA &dfa, const Rule &ru
}
}
// Variable tags must be set before fixed tags which depend on them. Trailing context
// is updated after all tags, because fixed tags may depend on the rightmost position.
append(stmts, varops);
append(stmts, fixtrailops);
append(stmts, fixops);
append(stmts, trailops);
if (!negtag.empty()) {
// With generic API there is no explicit negative NULL value, so it is
-29
View File
@@ -334,31 +334,6 @@ static void render_func(RenderContext &rctx, const CodeFunc *func)
++rctx.line;
}
static void render_loop(RenderContext &rctx, const CodeList *loop)
{
std::ostringstream &os = rctx.os;
const opt_t *opts = rctx.opts;
os << indent(rctx.ind, opts->indString);
switch (opts->lang) {
case LANG_C:
os << "for (;;) {";
break;
case LANG_GO:
os << "for {";
break;
}
os << std::endl;
++rctx.line;
++rctx.ind;
render_list(rctx, loop);
--rctx.ind;
os << indent(rctx.ind, opts->indString) << "}" << std::endl;
++rctx.line;
}
static inline void yych_conv(std::ostream &os, const opt_t *opts)
{
if (opts->yychConversion) {
@@ -534,9 +509,6 @@ void render(RenderContext &rctx, const Code *code)
case CODE_FUNC:
render_func(rctx, &code->func);
break;
case CODE_LOOP:
render_loop(rctx, code->loop);
break;
case CODE_TEXT_RAW:
os << code->text << std::endl;
line += count_lines_text(code->text) + 1;
@@ -604,7 +576,6 @@ void render(RenderContext &rctx, const Code *code)
case CODE_MAXNMATCH:
case CODE_YYCH:
case CODE_YYACCEPT:
case CODE_YYSTATE:
case CODE_COND_ENUM:
case CODE_COND_GOTO:
case CODE_COND_TABLE:
-8
View File
@@ -204,14 +204,6 @@ void compile(Scanner &input, Output &output, Opt &opts)
output.total_opts = accum_opts ? accum_opts : rblocks.last_opts();
// For special targets (skeleton and .dot) merge header into the output file.
if (globopts->target != TARGET_CODE && output.need_header) {
output.need_header = false;
blocks_t &cblocks = output.cblocks, &hblocks = output.hblocks;
cblocks.insert(cblocks.end(), hblocks.begin(), hblocks.end());
hblocks.clear();
}
if (globopts->target == TARGET_SKELETON) {
output.wdelay_stmt(0, emit_skeleton_epilog(output));
}
+1 -1
View File
@@ -6,7 +6,7 @@ namespace re2c {
class Scanner;
struct Opt;
struct Output;
class Output;
void compile(Scanner &input, Output &output, Opt &opts);
-2
View File
@@ -97,10 +97,8 @@ enum CodeKind {
CODE_MAXNMATCH,
CODE_YYCH,
CODE_YYACCEPT,
CODE_YYSTATE,
CODE_VAR,
CODE_STMT,
CODE_LOOP,
CODE_TEXT,
CODE_TEXT_RAW,
CODE_RAW,
+1 -1
View File
@@ -219,7 +219,7 @@ void generate_versions(ctx_t &ctx)
const tagver_t v = history(tag) ? vs[t] : TAGVER_ZERO;
newver_t x = {t, v, h};
const tagver_t
n = maxver + 1,
n = (maxver + 1) * (h0 == TAGVER_BOTTOM ? -1 : 1),
m = newvers.insert(std::make_pair(x, n)).first->second;
if (n == m) ++maxver;
+14 -7
View File
@@ -485,9 +485,14 @@ void reserve_buffers(ctx_t &ctx)
kbufs.indegree = alc.alloct<uint32_t>(n);
if (!stadfa) {
kbufs.x2y = alc.alloct<tagver_t>(n);
kbufs.y2x = alc.alloct<tagver_t>(n);
kbufs.x2t = alc.alloct<size_t>(n);
const size_t m = 2 * n + 1;
// point to the center (zero index) of each buffer
// indexes in range [-N .. N] must be valid, where N is capacity
kbufs.x2y = alc.alloct<tagver_t>(m) + n;
kbufs.y2x = alc.alloct<tagver_t>(m) + n;
kbufs.x2t = alc.alloct<size_t>(m) + n;
kbufs.backup_actions = alc.alloct<tcmd_t>(n);
}
}
@@ -644,8 +649,8 @@ bool kernel_map_t<ctx_t, regless>::operator()(const kernel_t *x, const kernel_t
// map tag versions of one kernel to that of another
// and check that lookahead versions (if any) coincide
std::fill(x2y, x2y + max, TAGVER_ZERO);
std::fill(y2x, y2x + max, TAGVER_ZERO);
std::fill(x2y - max, x2y + max, TAGVER_ZERO);
std::fill(y2x - max, y2x + max, TAGVER_ZERO);
for (size_t i = 0; i < n; ++i) {
const tagver_t
*xvs = ctx.dc_tagvertbl[x->tvers[i]],
@@ -686,13 +691,15 @@ bool kernel_map_t<ctx_t, regless>::operator()(const kernel_t *x, const kernel_t
// fix LHS of 'save' commands to reuse old version
// see note [save(X), copy(Y,X) optimization]
for (a = *pacts; a; a = a->next) {
const tagver_t yv = a->lhs, xv = y2x[yv];
const tagver_t
yv = a->lhs * (a->history[0] == TAGVER_BOTTOM ? -1 : 1),
xv = y2x[yv];
a->lhs = abs(xv);
y2x[yv] = x2y[xv] = TAGVER_ZERO;
}
// create 'copy' commands
for (tagver_t xv = 0; xv < max; ++xv) {
for (tagver_t xv = -max; xv < max; ++xv) {
const tagver_t yv = x2y[xv], axv = abs(xv), ayv = abs(yv);
if (yv != TAGVER_ZERO && xv != yv && !fixed(tags[x2t[xv]])) {
DASSERT(axv != ayv);
+4 -35
View File
@@ -16,6 +16,10 @@ static void fix_conopt(conopt_t &glob)
glob.iFlag = true;
}
if (!glob.lookahead) {
glob.eager_skip = true;
}
// append directory separator '/' to all paths that do not have it
for (size_t i = 0; i < glob.incpaths.size(); ++i) {
std::string &p = glob.incpaths[i];
@@ -25,13 +29,6 @@ static void fix_conopt(conopt_t &glob)
}
}
if (!glob.lookahead || glob.loop_switch) {
// for loop-switch enable eager-skip always (not only in cases when
// YYFILL labels are used) to avoid special handling of initial state
// when there are transitions into it.
glob.eager_skip = true;
}
if (!glob.dep_file.empty() && glob.output_file.empty()) {
error("cannot generate dep file, output file not specified");
exit(1);
@@ -123,7 +120,6 @@ static void fix_mutopt(const conopt_t &glob, const mutopt_t &defaults,
real.yych = defaults.yych;
real.bEmitYYCh = defaults.bEmitYYCh;
real.yychConversion = defaults.yychConversion;
real.yystate = defaults.yystate;
real.fill = defaults.fill;
real.fill_use = defaults.fill_use;
real.fill_check = defaults.fill_check;
@@ -252,14 +248,6 @@ static void fix_mutopt(const conopt_t &glob, const mutopt_t &defaults,
if (real.fill_naked) {
real.fill_arg_use = false;
}
if (glob.loop_switch) {
// With --loop-switch there is no `goto`.
real.yyctable = defaults.yyctable;
real.condDivider = defaults.condDivider;
real.condDividerParam = defaults.condDividerParam;
real.condGoto = defaults.condGoto;
real.condGotoParam = defaults.condGotoParam;
}
// errors
if (glob.target == TARGET_SKELETON && glob.lang != LANG_C) {
@@ -322,25 +310,6 @@ static void fix_mutopt(const conopt_t &glob, const mutopt_t &defaults,
error("storable state requires YYFILL to be enabled");
exit(1);
}
if (glob.loop_switch) {
if (real.gFlag) {
error("cannot combine loop switch and computed gotos");
exit(1);
}
if (real.bFlag) {
// TODO: generate bitmaps before the joined loop/switch for all conditions.
error("bitmaps with loop switch are not supported");
exit(1);
}
if (!glob.lookahead) {
// The problem here is that TDFA(0) may have initial register operations that
// should be executed on DFA entry. With loop/switch these operations would
// need to go in a special initial state (they can't go before the `yystate`
// loop because that would not work with start conditions).
error("TDFA(0) with loop switch is not supported");
exit(1);
}
}
}
Opt::Opt(const conopt_t &globopts)
+1 -3
View File
@@ -70,12 +70,11 @@ class Msg;
CONSTOPT (posix_prectable_alg_t, posix_prectable, POSIX_PRECTABLE_COMPLEX) \
CONSTOPT (fixed_tags_t, fixed_tags, FIXTAG_ALL) \
CONSTOPT (bool, lookahead, true) \
CONSTOPT (bool, eager_skip, false) \
CONSTOPT (bool, optimize_tags, true) \
CONSTOPT (bool, backward, false) \
CONSTOPT (bool, stadfa, false) \
CONSTOPT (bool, nested_negative_tags, true) \
CONSTOPT (bool, eager_skip, false) \
CONSTOPT (bool, loop_switch, false) \
/* debug */ \
CONSTOPT (bool, dump_nfa, false) \
CONSTOPT (bool, dump_dfa_raw, false) \
@@ -137,7 +136,6 @@ class Msg;
MUTOPT (bool, yybmHexTable, false) \
MUTOPT (bool, gFlag, false) \
MUTOPT (bool, case_ranges, false) \
MUTOPT (std::string, yystate, "yystate") \
MUTOPT (std::string, yytarget, "yytarget") \
MUTOPT (uint32_t, cGotoThreshold, 9) \
MUTOPT (uint32_t, eof, NOEOF) \
+1 -2
View File
@@ -167,8 +167,6 @@ opt_long:
"no-generation-date" end { globopts.bNoGenerationDate = true; goto opt; }
"no-version" end { globopts.version = false; goto opt; }
"skeleton" end { globopts.target = TARGET_SKELETON; goto opt; }
"eager-skip" end { globopts.eager_skip = true; goto opt; }
"loop-switch" end { globopts.loop_switch = true; goto opt; }
"bit-vectors" end { opts.set_bFlag (true); goto opt; }
"debug-output" end { opts.set_dFlag (true); goto opt; }
@@ -211,6 +209,7 @@ opt_long:
"fixed-tags" end { NEXT_ARG("--fixed-tags", opt_fixed_tags); }
"no-lookahead" end { globopts.lookahead = false; goto opt; }
"no-optimize-tags" end { globopts.optimize_tags = false; goto opt; }
"eager-skip" end { globopts.eager_skip = true; goto opt; }
"stadfa" end { globopts.stadfa = true; goto opt; }
// debug options
+1 -1
View File
@@ -9,7 +9,7 @@ namespace re2c {
struct AST;
struct loc_t;
class Msg;
struct Msg;
typedef std::map<std::string, const AST*> symtab_t;
+1 -1
View File
@@ -13,7 +13,7 @@
namespace re2c {
struct SemAct;
template <class Ty> class free_list;
template <class _Ty> class free_list;
struct ASTChar {
uint32_t chr;
+2 -8
View File
@@ -189,7 +189,7 @@ loop:
}
"/*!types:re2c" {
out.cond_enum_autogen = false;
out.cond_enum_in_hdr = out.in_header();
out.warn_condition_order = false; // see note [condition order]
uint32_t allow = DCONF_FORMAT | DCONF_SEPARATOR;
if (!lex_block(out, CODE_COND_ENUM, opts->topIndent, allow)) return INPUT_ERROR;
@@ -202,12 +202,6 @@ loop:
msg.error(cur_loc(), "`getstate:re2c` without `-f --storable-state` option");
return INPUT_ERROR;
}
if (opts->loop_switch) {
msg.error(cur_loc(), "`getstate:re2c` is incompatible with the --loop-switch "
"option, as it requires cross-block transitions that are unsupported "
"without the `goto` statement");
return INPUT_ERROR;
}
if (!lex_block(out, CODE_STATE_GOTO, opts->topIndent, 0)) return INPUT_ERROR;
goto next;
}
@@ -215,7 +209,7 @@ loop:
"/*!header:re2c:on" {
out.wraw(tok, ptr);
out.header_mode(true);
out.need_header = true;
out.need_header = opts->target == TARGET_CODE;
if (!lex_block_end(out)) return INPUT_ERROR;
goto next;
}
-1
View File
@@ -119,7 +119,6 @@ void Scanner::lex_conf(Opt &opts)
return;
}
"variable:yytarget" { opts.set_yytarget (lex_conf_string ()); return; }
"variable:yystate" { opts.set_yystate (lex_conf_string ()); return; }
"define:YYCURSOR" { opts.set_yycursor (lex_conf_string ()); return; }
"define:YYMARKER" { opts.set_yymarker (lex_conf_string ()); return; }
+1 -1
View File
@@ -21,7 +21,7 @@
namespace re2c {
class Msg;
struct Output;
class Output;
struct AST;
struct ASTChar;
struct BlockNameList;
+4 -2
View File
@@ -163,8 +163,10 @@ static void find_fixed_tags(RESpec &spec, std::vector<StackItem> &stack,
l.tag = re->tag.idx;
l.dist_to_tag = 0;
}
// Trailing context is not special: tags are fixed on the rightmost cursor
// position, and trailing context is just another tag.
if (trailing(tag)) {
l.dist_to_tag = 0;
}
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ namespace re2c {
struct AST;
struct ASTRule;
class Msg;
struct Msg;
struct Rule;
struct opt_t;
+7 -28
View File
@@ -152,7 +152,7 @@ static void emit_skeleton_defines(Output &output, CodeList *code, const DFA &dfa
append(code, code_textraw(alc, "#define YYSHIFT(o) cursor += o"));
append(code, code_textraw(alc, "#define YYLESSTHAN(n) (limit - cursor) < n"));
append(code, code_textraw(alc, opts->eof == NOEOF
? "#define YYFILL(n) { goto loop_end; }"
? "#define YYFILL(n) { break; }"
: "#define YYFILL(n) 1 /* fail */"));
append(code, code_newline(alc));
}
@@ -610,17 +610,8 @@ static void emit_skeleton_function_lex(Output &output, CodeList *code, DFA &dfa)
append(block, code_textraw(alc, ""));
// Don't use `for` loops or `while` loops: the generated code may contain an
// inner loop if the --loop-switch option is used, and then `continue` and
// `break` statements may result in unexpected control flow. Use `goto` loop.
append(block, code_stmt(alc, "i = 0"));
append(block, code_slabel(alc, "loop"));
block2 = code_list(alc);
append(block2, code_stmt(alc, "goto loop_end"));
append(block, code_if_then_else(alc,
"!(status == 0 && cursor < eof && i < keys_count)", block2, NULL));
append(block, code_text(alc,
"for (i = 0; status == 0 && cursor < eof && i < keys_count;) {"));
block2 = code_list(alc);
append(block2, code_stmt(alc, "token = cursor"));
if (dfa.need_backup) {
@@ -633,9 +624,6 @@ static void emit_skeleton_function_lex(Output &output, CodeList *code, DFA &dfa)
if (dfa.need_accept) {
append(block2, code_stmt(alc, "unsigned int yyaccept = 0"));
}
if (opts->loop_switch) {
append(block2, code_stmt(alc, o.cstr("unsigned int yystate = 0").flush()));
}
// autogenerated stag variables
if (!dfa.stagnames.empty()) {
text = o.cstr("\n").str(indent(2, opts->indString))
@@ -688,20 +676,11 @@ static void emit_skeleton_function_lex(Output &output, CodeList *code, DFA &dfa)
}
append(block2, code_textraw(alc, ""));
if (!opts->loop_switch) {
gen_dfa_as_blocks_with_labels(output, dfa, block2);
} else {
// With loop/switch there are no labels, and each block has its own state switch.
// Restart state counter from zero so that cases start from zero.
output.label_counter = 0;
CodeCases *cases = code_cases(alc);
gen_dfa_as_switch_cases(output, dfa, cases);
wrap_dfas_in_loop_switch(output, block2, cases);
}
dfa.emit_body(output, block2);
append(block2, code_textraw(alc, ""));
append(block, code_block(alc, block2, CodeBlock::WRAPPED));
append(block, code_slabel(alc, "loop_end"));
append(block, code_block(alc, block2, CodeBlock::INDENTED));
append(block, code_text(alc, "}"));
if_code = code_list(alc);
@@ -858,7 +837,7 @@ void emit_skeleton_action(Output &output, CodeList *code, const DFA &dfa, size_t
append(code, code_block(alc, hangafter, CodeBlock::INDENTED));
append(code, code_stmt(alc, "goto loop"));
append(code, code_stmt(alc, "continue"));
}
} // namespace re2c
+2 -2
View File
@@ -343,8 +343,8 @@ static void write_keys(const path_t &path, Skeleton &skel, size_t width)
tval = tags[tver];
if (tval != Skeleton::DEFTAG) tval -= tag.dist;
} else {
// fixed-length tag based on the rightmost position
tval = f - tag.dist;
// fixed-length tag based on cursor
tval = matched - tag.dist;
}
*k++ = to_le(static_cast<key_t>(tval));
}
-1
View File
@@ -1,7 +1,6 @@
#ifndef _RE2C_UTIL_FIXED_ALLOCATOR_
#define _RE2C_UTIL_FIXED_ALLOCATOR_
#include <stddef.h>
#include "src/util/c99_stdint.h"
#include <vector> // slab queue
+8 -8
View File
@@ -6,25 +6,25 @@
namespace re2c {
template<class Ty>
class free_list: protected std::set<Ty>
template<class _Ty>
class free_list: protected std::set<_Ty>
{
public:
typedef typename std::set<Ty>::iterator iterator;
typedef typename std::set<Ty>::size_type size_type;
typedef typename std::set<Ty>::key_type key_type;
typedef typename std::set<_Ty>::iterator iterator;
typedef typename std::set<_Ty>::size_type size_type;
typedef typename std::set<_Ty>::key_type key_type;
free_list(): in_clear(false)
{
}
using std::set<Ty>::insert;
using std::set<_Ty>::insert;
size_type erase(const key_type& key)
{
if (!in_clear)
{
return std::set<Ty>::erase(key);
return std::set<_Ty>::erase(key);
}
return 0;
}
@@ -37,7 +37,7 @@ public:
{
delete *it;
}
std::set<Ty>::clear();
std::set<_Ty>::clear();
in_clear = false;
}
-1
View File
@@ -1,7 +1,6 @@
#ifndef _RE2C_UTIL_STRING_UTILS_
#define _RE2C_UTIL_STRING_UTILS_
#include <string.h>
#include <sstream>
#include <string>
-4
View File
@@ -1,7 +1,3 @@
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE 1 // for fdopen
#endif
#include "config.h"
#include <time.h>
#include "src/util/temp_file.h"
-1
View File
@@ -1,7 +1,6 @@
#ifndef _RE2C_UTIL_UNIQ_VECTOR_
#define _RE2C_UTIL_UNIQ_VECTOR_
#include <stddef.h>
#include <vector>
+2
View File
@@ -2,6 +2,8 @@
#line 1 "bug152.re"
// re2c $INPUT -o $OUTPUT -c
#line 5 "bug152.c"
enum YYCONDTYPE {
};
#line 2 "bug152.re"
-54
View File
@@ -1,54 +0,0 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT --case-ranges --loop-switch -i
int lex(const char *YYCURSOR) { // C/C++ code
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = *YYCURSOR;
++YYCURSOR;
switch (yych) {
case 'A' ... 'Z':
case 'a' ... 'z':
yystate = 3;
continue;
default:
yystate = 1;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return 1; }
case 3:
yych = *YYCURSOR;
yystate = 4;
continue;
case 4:
switch (yych) {
case '0' ... '9':
case 'A' ... 'Z':
case 'a' ... 'z':
++YYCURSOR;
yystate = 3;
continue;
default:
yystate = 5;
continue;
}
case 5:
{ return 0; }
}
}
}
} //
//
int main() { // C/C++ code
return lex("qwerty42"); //
} //
-18
View File
@@ -1,18 +0,0 @@
// re2c $INPUT -o $OUTPUT --case-ranges --loop-switch -i
int lex(const char *YYCURSOR) { // C/C++ code
/*!re2c
re2c:define:YYCTYPE = char; // configurations
re2c:yyfill:enable = 0; //
//
alpha = [a-zA-Z]; // named definitions
ident = alpha (alpha | [0-9])*; //
//
ident { return 0; } // rules
* { return 1; } //
*/
} //
//
int main() { // C/C++ code
return lex("qwerty42"); //
} //
@@ -1,121 +0,0 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#define YYMAXFILL 1
// expect YYMAXFILL-padded string
static int lex(const char *str, unsigned int len)
{
const char *YYCURSOR = str, *YYLIMIT = str + len + YYMAXFILL;
int count = 0;
loop:
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
if (YYLIMIT <= YYCURSOR) return -1;
yych = *YYCURSOR;
++YYCURSOR;
switch (yych) {
case 0x00:
yystate = 1;
continue;
case ' ':
yystate = 5;
continue;
case '\'':
yystate = 8;
continue;
default:
yystate = 3;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return YYCURSOR + YYMAXFILL - 1 == YYLIMIT ? count : -1; }
case 3:
yystate = 4;
continue;
case 4:
{ return -1; }
case 5:
if (YYLIMIT <= YYCURSOR) return -1;
yych = *YYCURSOR;
yystate = 6;
continue;
case 6:
switch (yych) {
case ' ':
++YYCURSOR;
yystate = 5;
continue;
default:
yystate = 7;
continue;
}
case 7:
{ goto loop; }
case 8:
if (YYLIMIT <= YYCURSOR) return -1;
yych = *YYCURSOR;
yystate = 9;
continue;
case 9:
++YYCURSOR;
switch (yych) {
case '\'':
yystate = 10;
continue;
case '\\':
yystate = 12;
continue;
default:
yystate = 8;
continue;
}
case 10:
yystate = 11;
continue;
case 11:
{ ++count; goto loop; }
case 12:
if (YYLIMIT <= YYCURSOR) return -1;
yych = *YYCURSOR;
++YYCURSOR;
yystate = 8;
continue;
}
}
}
}
// make a copy of the string with YYMAXFILL zeroes at the end
static void test(const char *str, unsigned int len, int res)
{
char *s = (char*) malloc(len + YYMAXFILL);
memcpy(s, str, len);
memset(s + len, 0, YYMAXFILL);
int r = lex(s, len);
free(s);
assert(r == res);
}
#define TEST(s, r) test(s, sizeof(s) - 1, r)
int main()
{
TEST("", 0);
TEST("'qu\0tes' 'are' 'fine: \\'' ", 3);
TEST("'unterminated\\'", -1);
return 0;
}
@@ -1,46 +0,0 @@
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
#include <stdlib.h>
#include <string.h>
/*!max:re2c*/
// expect YYMAXFILL-padded string
static int lex(const char *str, unsigned int len)
{
const char *YYCURSOR = str, *YYLIMIT = str + len + YYMAXFILL;
int count = 0;
loop:
/*!re2c
re2c:api:style = free-form;
re2c:define:YYCTYPE = char;
re2c:define:YYFILL = "return -1;";
* { return -1; }
[\x00] { return YYCURSOR + YYMAXFILL - 1 == YYLIMIT ? count : -1; }
['] ([^'\\] | [\\][^])* ['] { ++count; goto loop; }
[ ]+ { goto loop; }
*/
}
// make a copy of the string with YYMAXFILL zeroes at the end
static void test(const char *str, unsigned int len, int res)
{
char *s = (char*) malloc(len + YYMAXFILL);
memcpy(s, str, len);
memset(s + len, 0, YYMAXFILL);
int r = lex(s, len);
free(s);
assert(r == res);
}
#define TEST(s, r) test(s, sizeof(s) - 1, r)
int main()
{
TEST("", 0);
TEST("'qu\0tes' 'are' 'fine: \\'' ", 3);
TEST("'unterminated\\'", -1);
return 0;
}
-134
View File
@@ -1,134 +0,0 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
// expect a null-terminated string
static int lex(const char *str, unsigned int len)
{
const char *YYCURSOR = str, *YYLIMIT = str + len, *YYMARKER;
int count = 0;
loop:
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = *YYCURSOR;
switch (yych) {
case ' ':
++YYCURSOR;
yystate = 3;
continue;
case '\'':
++YYCURSOR;
yystate = 6;
continue;
default:
if (YYLIMIT <= YYCURSOR) {
yystate = 12;
continue;
}
++YYCURSOR;
yystate = 1;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return -1; }
case 3:
yych = *YYCURSOR;
yystate = 4;
continue;
case 4:
switch (yych) {
case ' ':
++YYCURSOR;
yystate = 3;
continue;
default:
yystate = 5;
continue;
}
case 5:
{ goto loop; }
case 6:
YYMARKER = YYCURSOR;
yych = *YYCURSOR;
if (yych >= 0x01) {
yystate = 8;
continue;
}
if (YYLIMIT <= YYCURSOR) {
yystate = 2;
continue;
}
++YYCURSOR;
yystate = 7;
continue;
case 7:
yych = *YYCURSOR;
yystate = 8;
continue;
case 8:
switch (yych) {
case '\'':
++YYCURSOR;
yystate = 9;
continue;
case '\\':
++YYCURSOR;
yystate = 11;
continue;
default:
if (YYLIMIT <= YYCURSOR) {
yystate = 13;
continue;
}
++YYCURSOR;
yystate = 7;
continue;
}
case 9:
yystate = 10;
continue;
case 10:
{ ++count; goto loop; }
case 11:
yych = *YYCURSOR;
if (yych <= 0x00) {
if (YYLIMIT <= YYCURSOR) {
yystate = 13;
continue;
}
++YYCURSOR;
yystate = 7;
continue;
}
++YYCURSOR;
yystate = 7;
continue;
case 12:
{ return count; }
case 13:
YYCURSOR = YYMARKER;
yystate = 2;
continue;
}
}
}
}
#define TEST(s, r) assert(lex(s, sizeof(s) - 1) == r)
int main()
{
TEST("", 0);
TEST("'qu\0tes' 'are' 'fine: \\'' ", 3);
TEST("'unterminated\\'", -1);
return 0;
}
-31
View File
@@ -1,31 +0,0 @@
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
// expect a null-terminated string
static int lex(const char *str, unsigned int len)
{
const char *YYCURSOR = str, *YYLIMIT = str + len, *YYMARKER;
int count = 0;
loop:
/*!re2c
re2c:define:YYCTYPE = char;
re2c:yyfill:enable = 0;
re2c:eof = 0;
* { return -1; }
$ { return count; }
['] ([^'\\] | [\\][^])* ['] { ++count; goto loop; }
[ ]+ { goto loop; }
*/
}
#define TEST(s, r) assert(lex(s, sizeof(s) - 1) == r)
int main()
{
TEST("", 0);
TEST("'qu\0tes' 'are' 'fine: \\'' ", 3);
TEST("'unterminated\\'", -1);
return 0;
}
-207
View File
@@ -1,207 +0,0 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
#include <stdio.h>
#include <string.h>
#define SIZE 4096
typedef struct {
FILE *file;
char buf[SIZE + 1], *lim, *cur, *mar, *tok;
int eof;
} Input;
static int fill(Input *in)
{
if (in->eof) {
return 1;
}
const size_t free = in->tok - in->buf;
if (free < 1) {
return 2;
}
memmove(in->buf, in->tok, in->lim - in->tok);
in->lim -= free;
in->cur -= free;
in->mar -= free;
in->tok -= free;
in->lim += fread(in->lim, 1, free, in->file);
in->lim[0] = 0;
in->eof |= in->lim < in->buf + SIZE;
return 0;
}
static void init(Input *in, FILE *file)
{
in->file = file;
in->cur = in->mar = in->tok = in->lim = in->buf + SIZE;
in->eof = 0;
fill(in);
}
static int lex(Input *in)
{
int count = 0;
loop:
in->tok = in->cur;
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = *in->cur;
switch (yych) {
case ' ':
++in->cur;
yystate = 3;
continue;
case '\'':
++in->cur;
yystate = 6;
continue;
default:
if (in->lim <= in->cur) {
if (fill(in) == 0) {
yystate = 0;
continue;
}
yystate = 12;
continue;
}
++in->cur;
yystate = 1;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return -1; }
case 3:
yych = *in->cur;
yystate = 4;
continue;
case 4:
switch (yych) {
case ' ':
++in->cur;
yystate = 3;
continue;
default:
if (in->lim <= in->cur) {
if (fill(in) == 0) {
yystate = 3;
continue;
}
}
yystate = 5;
continue;
}
case 5:
{ goto loop; }
case 6:
in->mar = in->cur;
yych = *in->cur;
if (yych >= 0x01) {
yystate = 8;
continue;
}
if (in->lim <= in->cur) {
if (fill(in) == 0) {
yystate = 6;
continue;
}
yystate = 2;
continue;
}
++in->cur;
yystate = 7;
continue;
case 7:
yych = *in->cur;
yystate = 8;
continue;
case 8:
switch (yych) {
case '\'':
++in->cur;
yystate = 9;
continue;
case '\\':
++in->cur;
yystate = 11;
continue;
default:
if (in->lim <= in->cur) {
if (fill(in) == 0) {
yystate = 7;
continue;
}
yystate = 13;
continue;
}
++in->cur;
yystate = 7;
continue;
}
case 9:
yystate = 10;
continue;
case 10:
{ ++count; goto loop; }
case 11:
yych = *in->cur;
if (yych <= 0x00) {
if (in->lim <= in->cur) {
if (fill(in) == 0) {
yystate = 11;
continue;
}
yystate = 13;
continue;
}
++in->cur;
yystate = 7;
continue;
}
++in->cur;
yystate = 7;
continue;
case 12:
{ return count; }
case 13:
in->cur = in->mar;
yystate = 2;
continue;
}
}
}
}
int main()
{
const char *fname = "input";
const char str[] = "'qu\0tes' 'are' 'fine: \\'' ";
FILE *f;
Input in;
// prepare input file: a few times the size of the buffer,
// containing strings with zeroes and escaped quotes
f = fopen(fname, "w");
for (int i = 0; i < SIZE; ++i) {
fwrite(str, 1, sizeof(str) - 1, f);
}
fclose(f);
f = fopen(fname, "r");
init(&in, f);
assert(lex(&in) == SIZE * 3);
fclose(f);
remove(fname);
return 0;
}
-86
View File
@@ -1,86 +0,0 @@
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
#include <stdio.h>
#include <string.h>
#define SIZE 4096
typedef struct {
FILE *file;
char buf[SIZE + 1], *lim, *cur, *mar, *tok;
int eof;
} Input;
static int fill(Input *in)
{
if (in->eof) {
return 1;
}
const size_t free = in->tok - in->buf;
if (free < 1) {
return 2;
}
memmove(in->buf, in->tok, in->lim - in->tok);
in->lim -= free;
in->cur -= free;
in->mar -= free;
in->tok -= free;
in->lim += fread(in->lim, 1, free, in->file);
in->lim[0] = 0;
in->eof |= in->lim < in->buf + SIZE;
return 0;
}
static void init(Input *in, FILE *file)
{
in->file = file;
in->cur = in->mar = in->tok = in->lim = in->buf + SIZE;
in->eof = 0;
fill(in);
}
static int lex(Input *in)
{
int count = 0;
loop:
in->tok = in->cur;
/*!re2c
re2c:eof = 0;
re2c:api:style = free-form;
re2c:define:YYCTYPE = char;
re2c:define:YYCURSOR = in->cur;
re2c:define:YYMARKER = in->mar;
re2c:define:YYLIMIT = in->lim;
re2c:define:YYFILL = "fill(in) == 0";
* { return -1; }
$ { return count; }
['] ([^'\\] | [\\][^])* ['] { ++count; goto loop; }
[ ]+ { goto loop; }
*/
}
int main()
{
const char *fname = "input";
const char str[] = "'qu\0tes' 'are' 'fine: \\'' ";
FILE *f;
Input in;
// prepare input file: a few times the size of the buffer,
// containing strings with zeroes and escaped quotes
f = fopen(fname, "w");
for (int i = 0; i < SIZE; ++i) {
fwrite(str, 1, sizeof(str) - 1, f);
}
fclose(f);
f = fopen(fname, "r");
init(&in, f);
assert(lex(&in) == SIZE * 3);
fclose(f);
remove(fname);
return 0;
}
-161
View File
@@ -1,161 +0,0 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
#include <stdio.h>
#include <string.h>
#define YYMAXFILL 1
#define SIZE 4096
typedef struct {
FILE *file;
char buf[SIZE + YYMAXFILL], *lim, *cur, *mar, *tok;
int eof;
} Input;
static int fill(Input *in, size_t need)
{
if (in->eof) {
return 1;
}
const size_t free = in->tok - in->buf;
if (free < need) {
return 2;
}
memmove(in->buf, in->tok, in->lim - in->tok);
in->lim -= free;
in->cur -= free;
in->mar -= free;
in->tok -= free;
in->lim += fread(in->lim, 1, free, in->file);
if (in->lim < in->buf + SIZE) {
in->eof = 1;
memset(in->lim, 0, YYMAXFILL);
in->lim += YYMAXFILL;
}
return 0;
}
static void init(Input *in, FILE *file)
{
in->file = file;
in->cur = in->mar = in->tok = in->lim = in->buf + SIZE;
in->eof = 0;
fill(in, 1);
}
static int lex(Input *in)
{
int count = 0;
loop:
in->tok = in->cur;
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
if (in->lim <= in->cur) if (fill(in, 1) != 0) return -1;
yych = *in->cur;
++in->cur;
switch (yych) {
case 0x00:
yystate = 1;
continue;
case ' ':
yystate = 5;
continue;
case '\'':
yystate = 8;
continue;
default:
yystate = 3;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return (in->lim - in->cur == YYMAXFILL - 1) ? count : -1; }
case 3:
yystate = 4;
continue;
case 4:
{ return -1; }
case 5:
if (in->lim <= in->cur) if (fill(in, 1) != 0) return -1;
yych = *in->cur;
yystate = 6;
continue;
case 6:
switch (yych) {
case ' ':
++in->cur;
yystate = 5;
continue;
default:
yystate = 7;
continue;
}
case 7:
{ goto loop; }
case 8:
if (in->lim <= in->cur) if (fill(in, 1) != 0) return -1;
yych = *in->cur;
yystate = 9;
continue;
case 9:
++in->cur;
switch (yych) {
case '\'':
yystate = 10;
continue;
case '\\':
yystate = 12;
continue;
default:
yystate = 8;
continue;
}
case 10:
yystate = 11;
continue;
case 11:
{ ++count; goto loop; }
case 12:
if (in->lim <= in->cur) if (fill(in, 1) != 0) return -1;
yych = *in->cur;
++in->cur;
yystate = 8;
continue;
}
}
}
}
int main()
{
const char *fname = "input";
const char str[] = "'qu\0tes' 'are' 'fine: \\'' ";
FILE *f;
Input in;
// prepare input file: a few times the size of the buffer,
// containing strings with zeroes and escaped quotes
f = fopen(fname, "w");
for (int i = 0; i < SIZE; ++i) {
fwrite(str, 1, sizeof(str) - 1, f);
}
fclose(f);
f = fopen(fname, "r");
init(&in, f);
assert(lex(&in) == SIZE * 3);
fclose(f);
remove(fname);
return 0;
}
-89
View File
@@ -1,89 +0,0 @@
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
#include <stdio.h>
#include <string.h>
/*!max:re2c*/
#define SIZE 4096
typedef struct {
FILE *file;
char buf[SIZE + YYMAXFILL], *lim, *cur, *mar, *tok;
int eof;
} Input;
static int fill(Input *in, size_t need)
{
if (in->eof) {
return 1;
}
const size_t free = in->tok - in->buf;
if (free < need) {
return 2;
}
memmove(in->buf, in->tok, in->lim - in->tok);
in->lim -= free;
in->cur -= free;
in->mar -= free;
in->tok -= free;
in->lim += fread(in->lim, 1, free, in->file);
if (in->lim < in->buf + SIZE) {
in->eof = 1;
memset(in->lim, 0, YYMAXFILL);
in->lim += YYMAXFILL;
}
return 0;
}
static void init(Input *in, FILE *file)
{
in->file = file;
in->cur = in->mar = in->tok = in->lim = in->buf + SIZE;
in->eof = 0;
fill(in, 1);
}
static int lex(Input *in)
{
int count = 0;
loop:
in->tok = in->cur;
/*!re2c
re2c:api:style = free-form;
re2c:define:YYCTYPE = char;
re2c:define:YYCURSOR = in->cur;
re2c:define:YYMARKER = in->mar;
re2c:define:YYLIMIT = in->lim;
re2c:define:YYFILL = "if (fill(in, @@) != 0) return -1;";
* { return -1; }
[\x00] { return (in->lim - in->cur == YYMAXFILL - 1) ? count : -1; }
['] ([^'\\] | [\\][^])* ['] { ++count; goto loop; }
[ ]+ { goto loop; }
*/
}
int main()
{
const char *fname = "input";
const char str[] = "'qu\0tes' 'are' 'fine: \\'' ";
FILE *f;
Input in;
// prepare input file: a few times the size of the buffer,
// containing strings with zeroes and escaped quotes
f = fopen(fname, "w");
for (int i = 0; i < SIZE; ++i) {
fwrite(str, 1, sizeof(str) - 1, f);
}
fclose(f);
f = fopen(fname, "r");
init(&in, f);
assert(lex(&in) == SIZE * 3);
fclose(f);
remove(fname);
return 0;
}
@@ -1,146 +0,0 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
#include <stdlib.h>
#include <string.h>
// expect a string without terminating null
static int lex(const char *str, unsigned int len)
{
const char *cur = str, *lim = str + len, *mar;
int count = 0;
loop:
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = cur < lim ? *cur : 0;
switch (yych) {
case ' ':
++cur;
yystate = 3;
continue;
case '\'':
++cur;
yystate = 6;
continue;
default:
if (cur >= lim) {
yystate = 12;
continue;
}
++cur;
yystate = 1;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return -1; }
case 3:
yych = cur < lim ? *cur : 0;
yystate = 4;
continue;
case 4:
switch (yych) {
case ' ':
++cur;
yystate = 3;
continue;
default:
yystate = 5;
continue;
}
case 5:
{ goto loop; }
case 6:
mar = cur;
yych = cur < lim ? *cur : 0;
if (yych >= 0x01) {
yystate = 8;
continue;
}
if (cur >= lim) {
yystate = 2;
continue;
}
++cur;
yystate = 7;
continue;
case 7:
yych = cur < lim ? *cur : 0;
yystate = 8;
continue;
case 8:
switch (yych) {
case '\'':
++cur;
yystate = 9;
continue;
case '\\':
++cur;
yystate = 11;
continue;
default:
if (cur >= lim) {
yystate = 13;
continue;
}
++cur;
yystate = 7;
continue;
}
case 9:
yystate = 10;
continue;
case 10:
{ ++count; goto loop; }
case 11:
yych = cur < lim ? *cur : 0;
if (yych <= 0x00) {
if (cur >= lim) {
yystate = 13;
continue;
}
++cur;
yystate = 7;
continue;
}
++cur;
yystate = 7;
continue;
case 12:
{ return count; }
case 13:
cur = mar;
yystate = 2;
continue;
}
}
}
}
// make a copy of the string without terminating null
static void test(const char *str, unsigned int len, int res)
{
char *s = (char*) malloc(len);
memcpy(s, str, len);
int r = lex(s, len);
free(s);
assert(r == res);
}
#define TEST(s, r) test(s, sizeof(s) - 1, r)
int main()
{
TEST("", 0);
TEST("'qu\0tes' 'are' 'fine: \\'' ", 3);
TEST("'unterminated\\'", -1);
return 0;
}
@@ -1,50 +0,0 @@
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
#include <stdlib.h>
#include <string.h>
// expect a string without terminating null
static int lex(const char *str, unsigned int len)
{
const char *cur = str, *lim = str + len, *mar;
int count = 0;
loop:
/*!re2c
re2c:yyfill:enable = 0;
re2c:eof = 0;
re2c:flags:input = custom;
re2c:api:style = free-form;
re2c:define:YYCTYPE = char;
re2c:define:YYLESSTHAN = "cur >= lim";
re2c:define:YYPEEK = "cur < lim ? *cur : 0"; // fake null
re2c:define:YYSKIP = "++cur;";
re2c:define:YYBACKUP = "mar = cur;";
re2c:define:YYRESTORE = "cur = mar;";
* { return -1; }
$ { return count; }
['] ([^'\\] | [\\][^])* ['] { ++count; goto loop; }
[ ]+ { goto loop; }
*/
}
// make a copy of the string without terminating null
static void test(const char *str, unsigned int len, int res)
{
char *s = (char*) malloc(len);
memcpy(s, str, len);
int r = lex(s, len);
free(s);
assert(r == res);
}
#define TEST(s, r) test(s, sizeof(s) - 1, r)
int main()
{
TEST("", 0);
TEST("'qu\0tes' 'are' 'fine: \\'' ", 3);
TEST("'unterminated\\'", -1);
return 0;
}
@@ -1,152 +0,0 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
#include <stdlib.h>
#include <string.h>
// expect a string without terminating null
static int lex(const char *str, unsigned int len)
{
const char *cur = str, *lim = str + len;
int count = 0;
loop:
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = cur < lim ? *cur : 0;
++cur;
switch (yych) {
case 0x00:
yystate = 1;
continue;
case ' ':
yystate = 5;
continue;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
yystate = 8;
continue;
default:
yystate = 3;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return count; }
case 3:
yystate = 4;
continue;
case 4:
{ return -1; }
case 5:
yych = cur < lim ? *cur : 0;
yystate = 6;
continue;
case 6:
switch (yych) {
case ' ':
++cur;
yystate = 5;
continue;
default:
yystate = 7;
continue;
}
case 7:
{ goto loop; }
case 8:
yych = cur < lim ? *cur : 0;
yystate = 9;
continue;
case 9:
switch (yych) {
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
++cur;
yystate = 8;
continue;
default:
yystate = 10;
continue;
}
case 10:
{ ++count; goto loop; }
}
}
}
}
// make a copy of the string without terminating null
static void test(const char *str, unsigned int len, int res)
{
char *s = (char*) malloc(len);
memcpy(s, str, len);
int r = lex(s, len);
free(s);
assert(r == res);
}
#define TEST(s, r) test(s, sizeof(s) - 1, r)
int main()
{
TEST("", 0);
TEST("one two three ", 3);
TEST("f0ur", -1);
return 0;
}
@@ -1,47 +0,0 @@
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
#include <stdlib.h>
#include <string.h>
// expect a string without terminating null
static int lex(const char *str, unsigned int len)
{
const char *cur = str, *lim = str + len;
int count = 0;
loop:
/*!re2c
re2c:yyfill:enable = 0;
re2c:flags:input = custom;
re2c:api:style = free-form;
re2c:define:YYCTYPE = char;
re2c:define:YYLESSTHAN = "cur >= lim";
re2c:define:YYPEEK = "cur < lim ? *cur : 0"; // fake null
re2c:define:YYSKIP = "++cur;";
* { return -1; }
[\x00] { return count; }
[a-z]+ { ++count; goto loop; }
[ ]+ { goto loop; }
*/
}
// make a copy of the string without terminating null
static void test(const char *str, unsigned int len, int res)
{
char *s = (char*) malloc(len);
memcpy(s, str, len);
int r = lex(s, len);
free(s);
assert(r == res);
}
#define TEST(s, r) test(s, sizeof(s) - 1, r)
int main()
{
TEST("", 0);
TEST("one two three ", 3);
TEST("f0ur", -1);
return 0;
}
@@ -1,366 +0,0 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT -i --loop-switch
#include <stdint.h>
#include <limits.h>
#include <assert.h>
static const uint64_t ERROR = ~0lu;
template<int BASE> static void adddgt(uint64_t &u, unsigned int d)
{
u = u * BASE + d;
if (u > UINT32_MAX) u = ERROR;
}
static uint64_t parse_u32(const char *s)
{
const char *YYMARKER;
uint64_t u = 0;
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = *s;
++s;
switch (yych) {
case '0':
yystate = 3;
continue;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
yystate = 5;
continue;
default:
yystate = 1;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return ERROR; }
case 3:
YYMARKER = s;
yych = *s;
switch (yych) {
case 'B':
case 'b':
++s;
yystate = 7;
continue;
case 'X':
case 'x':
++s;
yystate = 9;
continue;
default:
yystate = 4;
continue;
}
case 4:
{ goto oct; }
case 5:
yystate = 6;
continue;
case 6:
s -= 1;
{ goto dec; }
case 7:
yych = *s;
switch (yych) {
case '0':
case '1':
++s;
yystate = 10;
continue;
default:
yystate = 8;
continue;
}
case 8:
s = YYMARKER;
yystate = 4;
continue;
case 9:
yych = *s;
switch (yych) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
++s;
yystate = 12;
continue;
default:
yystate = 8;
continue;
}
case 10:
yystate = 11;
continue;
case 11:
s -= 1;
{ goto bin; }
case 12:
yystate = 13;
continue;
case 13:
s -= 1;
{ goto hex; }
}
}
}
bin:
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = *s;
++s;
switch (yych) {
case 0x00:
yystate = 1;
continue;
case '0':
case '1':
yystate = 5;
continue;
default:
yystate = 3;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return u; }
case 3:
yystate = 4;
continue;
case 4:
{ return ERROR; }
case 5:
yystate = 6;
continue;
case 6:
{ adddgt<2>(u, s[-1] - '0'); goto bin; }
}
}
}
oct:
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = *s;
++s;
switch (yych) {
case 0x00:
yystate = 1;
continue;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
yystate = 5;
continue;
default:
yystate = 3;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return u; }
case 3:
yystate = 4;
continue;
case 4:
{ return ERROR; }
case 5:
yystate = 6;
continue;
case 6:
{ adddgt<8>(u, s[-1] - '0'); goto oct; }
}
}
}
dec:
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = *s;
++s;
switch (yych) {
case 0x00:
yystate = 1;
continue;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
yystate = 5;
continue;
default:
yystate = 3;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return u; }
case 3:
yystate = 4;
continue;
case 4:
{ return ERROR; }
case 5:
yystate = 6;
continue;
case 6:
{ adddgt<10>(u, s[-1] - '0'); goto dec; }
}
}
}
hex:
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = *s;
++s;
switch (yych) {
case 0x00:
yystate = 1;
continue;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
yystate = 5;
continue;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
yystate = 7;
continue;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
yystate = 9;
continue;
default:
yystate = 3;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return u; }
case 3:
yystate = 4;
continue;
case 4:
{ return ERROR; }
case 5:
yystate = 6;
continue;
case 6:
{ adddgt<16>(u, s[-1] - '0'); goto hex; }
case 7:
yystate = 8;
continue;
case 8:
{ adddgt<16>(u, s[-1] - 'A' + 10); goto hex; }
case 9:
yystate = 10;
continue;
case 10:
{ adddgt<16>(u, s[-1] - 'a' + 10); goto hex; }
}
}
}
}
int main()
{
assert(parse_u32("1234567890") == 1234567890);
assert(parse_u32("0b1101") == 13);
assert(parse_u32("0x7Fe") == 2046);
assert(parse_u32("0644") == 420);
assert(parse_u32("9999999999") == ERROR);
assert(parse_u32("") == ERROR);
return 0;
}
@@ -1,69 +0,0 @@
// re2c $INPUT -o $OUTPUT -i --loop-switch
#include <stdint.h>
#include <limits.h>
#include <assert.h>
static const uint64_t ERROR = ~0lu;
template<int BASE> static void adddgt(uint64_t &u, unsigned int d)
{
u = u * BASE + d;
if (u > UINT32_MAX) u = ERROR;
}
static uint64_t parse_u32(const char *s)
{
const char *YYMARKER;
uint64_t u = 0;
/*!re2c
re2c:yyfill:enable = 0;
re2c:define:YYCTYPE = char;
re2c:define:YYCURSOR = s;
end = "\x00";
'0b' / [01] { goto bin; }
"0" { goto oct; }
"" / [1-9] { goto dec; }
'0x' / [0-9a-fA-F] { goto hex; }
* { return ERROR; }
*/
bin:
/*!re2c
end { return u; }
[01] { adddgt<2>(u, s[-1] - '0'); goto bin; }
* { return ERROR; }
*/
oct:
/*!re2c
end { return u; }
[0-7] { adddgt<8>(u, s[-1] - '0'); goto oct; }
* { return ERROR; }
*/
dec:
/*!re2c
end { return u; }
[0-9] { adddgt<10>(u, s[-1] - '0'); goto dec; }
* { return ERROR; }
*/
hex:
/*!re2c
end { return u; }
[0-9] { adddgt<16>(u, s[-1] - '0'); goto hex; }
[a-f] { adddgt<16>(u, s[-1] - 'a' + 10); goto hex; }
[A-F] { adddgt<16>(u, s[-1] - 'A' + 10); goto hex; }
* { return ERROR; }
*/
}
int main()
{
assert(parse_u32("1234567890") == 1234567890);
assert(parse_u32("0b1101") == 13);
assert(parse_u32("0x7Fe") == 2046);
assert(parse_u32("0644") == 420);
assert(parse_u32("9999999999") == ERROR);
assert(parse_u32("") == ERROR);
return 0;
}
@@ -1,340 +0,0 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT -ci --loop-switch
#include <stdint.h>
#include <limits.h>
#include <assert.h>
static const uint64_t ERROR = ~0lu;
enum YYCONDTYPE {
yycinit = 0,
yycbin = 14,
yycdec = 21,
yychex = 28,
yycoct = 39,
};
template<int BASE> static void adddgt(uint64_t &u, unsigned int d)
{
u = u * BASE + d;
if (u > UINT32_MAX) u = ERROR;
}
static uint64_t parse_u32(const char *s)
{
const char *YYMARKER;
int c = yycinit;
uint64_t u = 0;
loop:
{
char yych;
unsigned int yystate = c;
for (;;) {
switch (yystate) {
case 0:
yych = *s;
++s;
switch (yych) {
case '0':
yystate = 3;
continue;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
yystate = 5;
continue;
default:
yystate = 1;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return ERROR; }
case 3:
YYMARKER = s;
yych = *s;
switch (yych) {
case 'B':
case 'b':
++s;
yystate = 7;
continue;
case 'X':
case 'x':
++s;
yystate = 9;
continue;
default:
yystate = 4;
continue;
}
case 4:
c = yycoct;
yystate = yycoct;
continue;
case 5:
yystate = 6;
continue;
case 6:
s -= 1;
c = yycdec;
yystate = yycdec;
continue;
case 7:
yych = *s;
switch (yych) {
case '0':
case '1':
++s;
yystate = 10;
continue;
default:
yystate = 8;
continue;
}
case 8:
s = YYMARKER;
yystate = 4;
continue;
case 9:
yych = *s;
switch (yych) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
++s;
yystate = 12;
continue;
default:
yystate = 8;
continue;
}
case 10:
yystate = 11;
continue;
case 11:
s -= 1;
c = yycbin;
yystate = yycbin;
continue;
case 12:
yystate = 13;
continue;
case 13:
s -= 1;
c = yychex;
yystate = yychex;
continue;
case 14:
yych = *s;
++s;
switch (yych) {
case 0x00:
yystate = 15;
continue;
case '0':
case '1':
yystate = 19;
continue;
default:
yystate = 17;
continue;
}
case 15:
yystate = 16;
continue;
case 16:
{ return u; }
case 17:
yystate = 18;
continue;
case 18:
{ return ERROR; }
case 19:
yystate = 20;
continue;
case 20:
{ adddgt<2> (u, s[-1] - '0'); goto loop; }
case 21:
yych = *s;
++s;
switch (yych) {
case 0x00:
yystate = 22;
continue;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
yystate = 26;
continue;
default:
yystate = 24;
continue;
}
case 22:
yystate = 23;
continue;
case 23:
{ return u; }
case 24:
yystate = 25;
continue;
case 25:
{ return ERROR; }
case 26:
yystate = 27;
continue;
case 27:
{ adddgt<10>(u, s[-1] - '0'); goto loop; }
case 28:
yych = *s;
++s;
switch (yych) {
case 0x00:
yystate = 29;
continue;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
yystate = 33;
continue;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
yystate = 35;
continue;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
yystate = 37;
continue;
default:
yystate = 31;
continue;
}
case 29:
yystate = 30;
continue;
case 30:
{ return u; }
case 31:
yystate = 32;
continue;
case 32:
{ return ERROR; }
case 33:
yystate = 34;
continue;
case 34:
{ adddgt<16>(u, s[-1] - '0'); goto loop; }
case 35:
yystate = 36;
continue;
case 36:
{ adddgt<16>(u, s[-1] - 'A' + 10); goto loop; }
case 37:
yystate = 38;
continue;
case 38:
{ adddgt<16>(u, s[-1] - 'a' + 10); goto loop; }
case 39:
yych = *s;
++s;
switch (yych) {
case 0x00:
yystate = 40;
continue;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
yystate = 44;
continue;
default:
yystate = 42;
continue;
}
case 40:
yystate = 41;
continue;
case 41:
{ return u; }
case 42:
yystate = 43;
continue;
case 43:
{ return ERROR; }
case 44:
yystate = 45;
continue;
case 45:
{ adddgt<8> (u, s[-1] - '0'); goto loop; }
}
}
}
}
int main()
{
assert(parse_u32("1234567890") == 1234567890);
assert(parse_u32("0b1101") == 13);
assert(parse_u32("0x7Fe") == 2046);
assert(parse_u32("0644") == 420);
assert(parse_u32("9999999999") == ERROR);
assert(parse_u32("") == ERROR);
return 0;
}
@@ -1,57 +0,0 @@
// re2c $INPUT -o $OUTPUT -ci --loop-switch
#include <stdint.h>
#include <limits.h>
#include <assert.h>
static const uint64_t ERROR = ~0lu;
/*!types:re2c*/
template<int BASE> static void adddgt(uint64_t &u, unsigned int d)
{
u = u * BASE + d;
if (u > UINT32_MAX) u = ERROR;
}
static uint64_t parse_u32(const char *s)
{
const char *YYMARKER;
int c = yycinit;
uint64_t u = 0;
loop:
/*!re2c
re2c:yyfill:enable = 0;
re2c:api:style = free-form;
re2c:define:YYCTYPE = char;
re2c:define:YYCURSOR = s;
re2c:define:YYGETCONDITION = "c";
re2c:define:YYSETCONDITION = "c = @@;";
<*> * { return ERROR; }
<init> '0b' / [01] :=> bin
<init> "0" :=> oct
<init> "" / [1-9] :=> dec
<init> '0x' / [0-9a-fA-F] :=> hex
<bin, oct, dec, hex> "\x00" { return u; }
<bin> [01] { adddgt<2> (u, s[-1] - '0'); goto loop; }
<oct> [0-7] { adddgt<8> (u, s[-1] - '0'); goto loop; }
<dec> [0-9] { adddgt<10>(u, s[-1] - '0'); goto loop; }
<hex> [0-9] { adddgt<16>(u, s[-1] - '0'); goto loop; }
<hex> [a-f] { adddgt<16>(u, s[-1] - 'a' + 10); goto loop; }
<hex> [A-F] { adddgt<16>(u, s[-1] - 'A' + 10); goto loop; }
*/
}
int main()
{
assert(parse_u32("1234567890") == 1234567890);
assert(parse_u32("0b1101") == 13);
assert(parse_u32("0x7Fe") == 2046);
assert(parse_u32("0644") == 420);
assert(parse_u32("9999999999") == ERROR);
assert(parse_u32("") == ERROR);
return 0;
}
-229
View File
@@ -1,229 +0,0 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT --input-encoding utf8 --loop-switch -i
// This example supports multiple input encodings: UTF-8 and UTF-32.
// Both lexers are generated from the same rules block, and the use
// blocks add only encoding-specific configurations.
#include <assert.h>
#include <stdint.h>
static int lex_utf8(const uint8_t *YYCURSOR)
{
const uint8_t *YYMARKER;
{
uint8_t yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = *YYCURSOR;
++YYCURSOR;
switch (yych) {
case 0xE2:
yystate = 3;
continue;
default:
yystate = 1;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return 1; }
case 3:
YYMARKER = YYCURSOR;
yych = *YYCURSOR;
switch (yych) {
case 0x88:
++YYCURSOR;
yystate = 4;
continue;
default:
yystate = 2;
continue;
}
case 4:
yych = *YYCURSOR;
switch (yych) {
case 0x80:
++YYCURSOR;
yystate = 6;
continue;
default:
yystate = 5;
continue;
}
case 5:
YYCURSOR = YYMARKER;
yystate = 2;
continue;
case 6:
yych = *YYCURSOR;
switch (yych) {
case 'x':
++YYCURSOR;
yystate = 7;
continue;
default:
yystate = 5;
continue;
}
case 7:
yych = *YYCURSOR;
switch (yych) {
case ' ':
++YYCURSOR;
yystate = 8;
continue;
default:
yystate = 5;
continue;
}
case 8:
yych = *YYCURSOR;
switch (yych) {
case 0xE2:
++YYCURSOR;
yystate = 9;
continue;
default:
yystate = 5;
continue;
}
case 9:
yych = *YYCURSOR;
switch (yych) {
case 0x88:
++YYCURSOR;
yystate = 10;
continue;
default:
yystate = 5;
continue;
}
case 10:
yych = *YYCURSOR;
switch (yych) {
case 0x83:
++YYCURSOR;
yystate = 11;
continue;
default:
yystate = 5;
continue;
}
case 11:
yych = *YYCURSOR;
switch (yych) {
case 'y':
++YYCURSOR;
yystate = 12;
continue;
default:
yystate = 5;
continue;
}
case 12:
yystate = 13;
continue;
case 13:
{ return 0; }
}
}
}
}
static int lex_utf32(const uint32_t *YYCURSOR)
{
const uint32_t *YYMARKER;
{
uint32_t yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = *YYCURSOR;
++YYCURSOR;
if (yych == 0x00002200) {
yystate = 3;
continue;
}
yystate = 1;
continue;
case 1:
yystate = 2;
continue;
case 2:
{ return 1; }
case 3:
YYMARKER = YYCURSOR;
yych = *YYCURSOR;
if (yych != 'x') {
yystate = 2;
continue;
}
++YYCURSOR;
yystate = 4;
continue;
case 4:
yych = *YYCURSOR;
if (yych == ' ') {
++YYCURSOR;
yystate = 6;
continue;
}
yystate = 5;
continue;
case 5:
YYCURSOR = YYMARKER;
yystate = 2;
continue;
case 6:
yych = *YYCURSOR;
if (yych != 0x00002203) {
yystate = 5;
continue;
}
++YYCURSOR;
yystate = 7;
continue;
case 7:
yych = *YYCURSOR;
if (yych != 'y') {
yystate = 5;
continue;
}
++YYCURSOR;
yystate = 8;
continue;
case 8:
yystate = 9;
continue;
case 9:
{ return 0; }
}
}
}
}
int main()
{
static const uint8_t s8[] = // UTF-8
{ 0xe2, 0x88, 0x80, 0x78, 0x20, 0xe2, 0x88, 0x83, 0x79 };
static const uint32_t s32[] = // UTF32
{ 0x00002200, 0x00000078, 0x00000020, 0x00002203, 0x00000079 };
assert(lex_utf8(s8) == 0);
assert(lex_utf32(s32) == 0);
return 0;
}
-48
View File
@@ -1,48 +0,0 @@
// re2c $INPUT -o $OUTPUT --input-encoding utf8 --loop-switch -i
// This example supports multiple input encodings: UTF-8 and UTF-32.
// Both lexers are generated from the same rules block, and the use
// blocks add only encoding-specific configurations.
#include <assert.h>
#include <stdint.h>
/*!rules:re2c
re2c:yyfill:enable = 0;
"∀x ∃y" { return 0; }
* { return 1; }
*/
static int lex_utf8(const uint8_t *YYCURSOR)
{
const uint8_t *YYMARKER;
/*!use:re2c
re2c:define:YYCTYPE = uint8_t;
re2c:flags:8 = 1;
*/
}
static int lex_utf32(const uint32_t *YYCURSOR)
{
const uint32_t *YYMARKER;
/*!use:re2c
re2c:define:YYCTYPE = uint32_t;
re2c:flags:8 = 0;
re2c:flags:u = 1;
*/
}
int main()
{
static const uint8_t s8[] = // UTF-8
{ 0xe2, 0x88, 0x80, 0x78, 0x20, 0xe2, 0x88, 0x83, 0x79 };
static const uint32_t s32[] = // UTF32
{ 0x00002200, 0x00000078, 0x00000020, 0x00002203, 0x00000079 };
assert(lex_utf8(s8) == 0);
assert(lex_utf32(s32) == 0);
return 0;
}
-137
View File
@@ -1,137 +0,0 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
// expect a null-terminated string
static int lex(const char *YYCURSOR)
{
int count = 0;
loop:
{
char yych;
unsigned int yystate = 0;
for (;;) {
switch (yystate) {
case 0:
yych = *YYCURSOR;
++YYCURSOR;
switch (yych) {
case 0x00:
yystate = 1;
continue;
case ' ':
yystate = 5;
continue;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
yystate = 8;
continue;
default:
yystate = 3;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
{ return count; }
case 3:
yystate = 4;
continue;
case 4:
{ return -1; }
case 5:
yych = *YYCURSOR;
yystate = 6;
continue;
case 6:
switch (yych) {
case ' ':
++YYCURSOR;
yystate = 5;
continue;
default:
yystate = 7;
continue;
}
case 7:
{ goto loop; }
case 8:
yych = *YYCURSOR;
yystate = 9;
continue;
case 9:
switch (yych) {
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
++YYCURSOR;
yystate = 8;
continue;
default:
yystate = 10;
continue;
}
case 10:
{ ++count; goto loop; }
}
}
}
}
int main()
{
assert(lex("") == 0);
assert(lex("one two three") == 3);
assert(lex("f0ur") == -1);
return 0;
}
-27
View File
@@ -1,27 +0,0 @@
// re2c $INPUT -o $OUTPUT --loop-switch -i
#include <assert.h>
// expect a null-terminated string
static int lex(const char *YYCURSOR)
{
int count = 0;
loop:
/*!re2c
re2c:define:YYCTYPE = char;
re2c:yyfill:enable = 0;
* { return -1; }
[\x00] { return count; }
[a-z]+ { ++count; goto loop; }
[ ]+ { goto loop; }
*/
}
int main()
{
assert(lex("") == 0);
assert(lex("one two three") == 3);
assert(lex("f0ur") == -1);
return 0;
}
-298
View File
@@ -1,298 +0,0 @@
/* Generated by re2c */
// re2c $INPUT -o $OUTPUT -f --loop-switch -i
#include <assert.h>
#include <stdio.h>
#include <string.h>
#define DEBUG 1
#define LOG(...) if (DEBUG) fprintf(stderr, __VA_ARGS__);
#define BUFSIZE 10
typedef struct {
FILE *file;
char buf[BUFSIZE + 1], *lim, *cur, *mar, *tok;
unsigned yyaccept;
int state;
} Input;
static void init(Input *in, FILE *f)
{
in->file = f;
in->cur = in->mar = in->tok = in->lim = in->buf + BUFSIZE;
in->lim[0] = 0; // append sentinel symbol
in->yyaccept = 0;
in->state = -1;
}
typedef enum {END, READY, WAITING, BAD_PACKET, BIG_PACKET} Status;
static Status fill(Input *in)
{
const size_t shift = in->tok - in->buf;
const size_t free = BUFSIZE - (in->lim - in->tok);
if (free < 1) return BIG_PACKET;
memmove(in->buf, in->tok, BUFSIZE - shift);
in->lim -= shift;
in->cur -= shift;
in->mar -= shift;
in->tok -= shift;
const size_t read = fread(in->lim, 1, free, in->file);
in->lim += read;
in->lim[0] = 0; // append sentinel symbol
return READY;
}
static Status lex(Input *in, unsigned int *recv)
{
char yych;
loop:
int yystate = in->state;
for (;;) {
switch (yystate) {
case -1:
case 0:
yych = *in->cur;
switch (yych) {
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
++in->cur;
yystate = 3;
continue;
default:
if (in->lim <= in->cur) {
in->state = 10;
return WAITING;
}
++in->cur;
yystate = 1;
continue;
}
case 1:
yystate = 2;
continue;
case 2:
in->state = 0;
{ return BAD_PACKET; }
case 3:
in->mar = in->cur;
yych = *in->cur;
switch (yych) {
case ';':
++in->cur;
yystate = 4;
continue;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
++in->cur;
yystate = 6;
continue;
default:
if (in->lim <= in->cur) {
in->state = 11;
return WAITING;
}
yystate = 2;
continue;
}
case 4:
yystate = 5;
continue;
case 5:
in->state = 0;
{ *recv = *recv + 1; in->tok = in->cur; goto loop; }
case 6:
yych = *in->cur;
yystate = 7;
continue;
case 7:
switch (yych) {
case ';':
++in->cur;
yystate = 4;
continue;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
++in->cur;
yystate = 6;
continue;
default:
if (in->lim <= in->cur) {
in->state = 12;
return WAITING;
}
yystate = 8;
continue;
}
case 8:
in->cur = in->mar;
yystate = 2;
continue;
case 9:
in->state = 0;
{ return END; }
case 10:
if (in->lim <= in->cur) {
yystate = 9;
continue;
}
yystate = 0;
continue;
case 11:
if (in->lim <= in->cur) {
yystate = 2;
continue;
}
yystate = 3;
continue;
case 12:
if (in->lim <= in->cur) {
yystate = 8;
continue;
}
yystate = 6;
continue;
}
}
}
void test(const char **packets, Status status)
{
const char *fname = "pipe";
FILE *fw = fopen(fname, "w");
FILE *fr = fopen(fname, "r");
setvbuf(fw, NULL, _IONBF, 0);
setvbuf(fr, NULL, _IONBF, 0);
Input in;
init(&in, fr);
Status st;
unsigned int send = 0, recv = 0;
for (;;) {
st = lex(&in, &recv);
if (st == END) {
LOG("done: got %u packets\n", recv);
break;
} else if (st == WAITING) {
LOG("waiting...\n");
if (*packets) {
LOG("sent packet %u\n", send);
fprintf(fw, "%s", *packets++);
++send;
}
st = fill(&in);
LOG("queue: '%s'\n", in.buf);
if (st == BIG_PACKET) {
LOG("error: packet too big\n");
break;
}
assert(st == READY);
} else {
assert(st == BAD_PACKET);
LOG("error: ill-formed packet\n");
break;
}
}
LOG("\n");
assert(st == status);
if (st == END) assert(recv == send);
fclose(fw);
fclose(fr);
remove(fname);
}
int main()
{
const char *packets1[] = {0};
const char *packets2[] = {"zero;", "one;", "two;", "three;", "four;", 0};
const char *packets3[] = {"zer0;", 0};
const char *packets4[] = {"goooooooooogle;", 0};
test(packets1, END);
test(packets2, END);
test(packets3, BAD_PACKET);
test(packets4, BIG_PACKET);
return 0;
}
@@ -1,132 +0,0 @@
// re2c $INPUT -o $OUTPUT -f --loop-switch -i
#include <assert.h>
#include <stdio.h>
#include <string.h>
#define DEBUG 1
#define LOG(...) if (DEBUG) fprintf(stderr, __VA_ARGS__);
#define BUFSIZE 10
typedef struct {
FILE *file;
char buf[BUFSIZE + 1], *lim, *cur, *mar, *tok;
unsigned yyaccept;
int state;
} Input;
static void init(Input *in, FILE *f)
{
in->file = f;
in->cur = in->mar = in->tok = in->lim = in->buf + BUFSIZE;
in->lim[0] = 0; // append sentinel symbol
in->yyaccept = 0;
in->state = -1;
}
typedef enum {END, READY, WAITING, BAD_PACKET, BIG_PACKET} Status;
static Status fill(Input *in)
{
const size_t shift = in->tok - in->buf;
const size_t free = BUFSIZE - (in->lim - in->tok);
if (free < 1) return BIG_PACKET;
memmove(in->buf, in->tok, BUFSIZE - shift);
in->lim -= shift;
in->cur -= shift;
in->mar -= shift;
in->tok -= shift;
const size_t read = fread(in->lim, 1, free, in->file);
in->lim += read;
in->lim[0] = 0; // append sentinel symbol
return READY;
}
static Status lex(Input *in, unsigned int *recv)
{
char yych;
loop:
/*!re2c
re2c:eof = 0;
re2c:api:style = free-form;
re2c:define:YYCTYPE = "char";
re2c:define:YYCURSOR = "in->cur";
re2c:define:YYMARKER = "in->mar";
re2c:define:YYLIMIT = "in->lim";
re2c:define:YYGETSTATE = "in->state";
re2c:define:YYSETSTATE = "in->state = @@;";
re2c:define:YYFILL = "return WAITING;";
packet = [a-z]+[;];
* { return BAD_PACKET; }
$ { return END; }
packet { *recv = *recv + 1; in->tok = in->cur; goto loop; }
*/
}
void test(const char **packets, Status status)
{
const char *fname = "pipe";
FILE *fw = fopen(fname, "w");
FILE *fr = fopen(fname, "r");
setvbuf(fw, NULL, _IONBF, 0);
setvbuf(fr, NULL, _IONBF, 0);
Input in;
init(&in, fr);
Status st;
unsigned int send = 0, recv = 0;
for (;;) {
st = lex(&in, &recv);
if (st == END) {
LOG("done: got %u packets\n", recv);
break;
} else if (st == WAITING) {
LOG("waiting...\n");
if (*packets) {
LOG("sent packet %u\n", send);
fprintf(fw, "%s", *packets++);
++send;
}
st = fill(&in);
LOG("queue: '%s'\n", in.buf);
if (st == BIG_PACKET) {
LOG("error: packet too big\n");
break;
}
assert(st == READY);
} else {
assert(st == BAD_PACKET);
LOG("error: ill-formed packet\n");
break;
}
}
LOG("\n");
assert(st == status);
if (st == END) assert(recv == send);
fclose(fw);
fclose(fr);
remove(fname);
}
int main()
{
const char *packets1[] = {0};
const char *packets2[] = {"zero;", "one;", "two;", "three;", "four;", 0};
const char *packets3[] = {"zer0;", 0};
const char *packets4[] = {"goooooooooogle;", 0};
test(packets1, END);
test(packets2, END);
test(packets3, BAD_PACKET);
test(packets4, BIG_PACKET);
return 0;
}
@@ -1 +0,0 @@
codegen/loop_switch/c/storable_state_error_getstate.re:3:16: error: `getstate:re2c` is incompatible with the --loop-switch option, as it requires cross-block transitions that are unsupported without the `goto` statement
@@ -1,3 +0,0 @@
// re2c $INPUT -o $OUTPUT -f --loop-switch
/*!getstate:re2c*/

Some files were not shown because too many files have changed in this diff Show More