From 91ab6ca99d4d72e1ac4485b22fa427197306c8a7 Mon Sep 17 00:00:00 2001 From: igniting <1438071+igniting@users.noreply.github.com> Date: Wed, 5 Aug 2026 11:27:38 +0000 Subject: [PATCH] Establish R0 compiler foundation --- .gitignore | 25 +- Makefile | 122 ++++-- README.md | 60 ++- absyn.c | 11 +- absyn.h | 9 +- ci/Containerfile | 23 + ci/toolchain.lock | 34 ++ compile.c | 80 ++++ compile.h | 36 ++ docs/grammar-coverage.csv | 521 ++++++++++++++++++++++ docs/mips-target.md | 129 ++++++ docs/supported-subset.md | 98 +++++ driver.c | 91 ++++ errormsg.c | 83 ++-- errormsg.h | 16 +- lexer.l | 29 +- parser.y | 129 ++---- runtime/linux_o32.S | 47 ++ runtime/linux_o32.h | 24 + runtime/mipsel-linux.ld | 72 +++ runtime/start.S | 40 ++ symbol.c | 120 +++-- symbol.h | 47 +- table.c | 163 ++++--- table.h | 37 +- tests/abi/six_args_callee.c | 5 + tests/abi/six_args_caller.S | 62 +++ tests/elf/r0-smoke.expected | 9 + tests/fixtures/r0/runtime/smoke.S | 34 ++ tests/fixtures/r0/runtime/text_only.S | 28 ++ tests/run_tests.py | 411 +++++++++++++++++ tests/unit/test_grammar_inventory.py | 151 +++++++ tools/check_coverage.py | 191 ++++++++ tools/inventory_grammar.py | 606 ++++++++++++++++++++++++++ type.c | 2 +- util.c | 226 ++++++---- util.h | 23 +- 37 files changed, 3315 insertions(+), 479 deletions(-) create mode 100644 ci/Containerfile create mode 100644 ci/toolchain.lock create mode 100644 compile.c create mode 100644 compile.h create mode 100644 docs/grammar-coverage.csv create mode 100644 docs/mips-target.md create mode 100644 docs/supported-subset.md create mode 100644 driver.c create mode 100644 runtime/linux_o32.S create mode 100644 runtime/linux_o32.h create mode 100644 runtime/mipsel-linux.ld create mode 100644 runtime/start.S create mode 100644 tests/abi/six_args_callee.c create mode 100644 tests/abi/six_args_caller.S create mode 100644 tests/elf/r0-smoke.expected create mode 100644 tests/fixtures/r0/runtime/smoke.S create mode 100644 tests/fixtures/r0/runtime/text_only.S create mode 100644 tests/run_tests.py create mode 100644 tests/unit/test_grammar_inventory.py create mode 100644 tools/check_coverage.py create mode 100755 tools/inventory_grammar.py diff --git a/.gitignore b/.gitignore index 4a1dd40..f5aef4f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,26 @@ -.* -*~ +# Generated host frontend and build products +/build/ + +# Python bytecode caches +__pycache__/ +*.py[cod] + +# Legacy generated frontend files lex.yy.c lex y.tab.c y.tab.h y.output -# except for .gitignore -!.gitignore +final +*.o +*.d + +# Compiler artifacts and dumps +*.adi +*.elf +*.s +*.S.tmp +*.ast +*.sem +*.ir +*.asm diff --git a/Makefile b/Makefile index 5a95b9b..25d35d1 100644 --- a/Makefile +++ b/Makefile @@ -1,41 +1,103 @@ -final: y.tab.o lex.yy.o errormsg.o util.o absyn.o symbol.o table.o prabsyn.o type.o - cc -g y.tab.o lex.yy.o errormsg.o util.o absyn.o symbol.o table.o prabsyn.o type.o -o final -lm +CC ?= cc +FLEX ?= flex +BISON ?= bison +PYTHON ?= python3 -y.tab.o: y.tab.c - cc -g -c y.tab.c +BUILD_DIR := build +BIN_DIR := $(BUILD_DIR)/bin +GEN_DIR := $(BUILD_DIR)/generated +OBJ_DIR := $(BUILD_DIR)/obj +ADAC := $(BIN_DIR)/adac -y.tab.c: parser.y - yacc --debug -vd parser.y +CPPFLAGS := -D_POSIX_C_SOURCE=200809L -I. -I$(GEN_DIR) +CFLAGS := -std=c11 -g -O0 -Wall -Wextra -Wpedantic -Werror +LDLIBS := -lm -y.tab.h: y.tab.c - echo "y.tab.h was created at the same time as y.tab.c" +PARSER_C := $(GEN_DIR)/parser.c +PARSER_H := $(GEN_DIR)/parser.h +PARSER_REPORT := $(GEN_DIR)/parser.output +LEXER_C := $(GEN_DIR)/lexer.c -errormsg.o: errormsg.c errormsg.h util.h - cc -g -c errormsg.c +HOST_SOURCES := driver.c compile.c errormsg.c util.c absyn.c symbol.c table.c prabsyn.c type.c +HOST_OBJECTS := $(HOST_SOURCES:%.c=$(OBJ_DIR)/%.o) +GENERATED_OBJECTS := $(OBJ_DIR)/parser.o $(OBJ_DIR)/lexer.o +OBJECTS := $(HOST_OBJECTS) $(GENERATED_OBJECTS) -lex.yy.o: lex.yy.c y.tab.h errormsg.h util.h - cc -g -c lex.yy.c +.PHONY: all strict clean test host-tools coverage contract -lex.yy.c: lexer.l - lex lexer.l +# Build only: validation is deliberately reserved for `make strict`. +all: $(ADAC) -util.o: util.c util.h - cc -g -c util.c +strict: host-tools all coverage contract -absyn.o: absyn.c absyn.h - cc -g -c absyn.c +$(ADAC): $(OBJECTS) | $(BIN_DIR) + $(CC) $(CFLAGS) $(OBJECTS) $(LDLIBS) -o $@ -prabsyn.o: prabsyn.c prabsyn.h - cc -g -c prabsyn.c - -symbol.o: symbol.c symbol.h - cc -g -c symbol.c +$(PARSER_C) $(PARSER_H) $(PARSER_REPORT) &: parser.y | $(GEN_DIR) + $(BISON) --defines=$(PARSER_H) --output=$(PARSER_C) --report=all --report-file=$(PARSER_REPORT) parser.y -table.o: table.c table.h - cc -g -c table.c +$(LEXER_C): lexer.l $(PARSER_H) | $(GEN_DIR) + $(FLEX) --outfile=$@ lexer.l -type.o: type.c type.h - cc -g -c type.c - -clean: - rm -f final *.o lex.yy.c y.tab.c y.tab.h y.output +$(OBJ_DIR)/%.o: %.c | $(OBJ_DIR) + @mkdir -p $(@D) + $(CC) $(CPPFLAGS) $(CFLAGS) -MMD -MP -c $< -o $@ + +$(OBJ_DIR)/parser.o: $(PARSER_C) | $(OBJ_DIR) + @mkdir -p $(@D) + $(CC) $(CPPFLAGS) $(CFLAGS) -Wno-unused-function -MMD -MP -c $< -o $@ + +$(OBJ_DIR)/lexer.o: $(LEXER_C) | $(OBJ_DIR) + @mkdir -p $(@D) + $(CC) $(CPPFLAGS) $(CFLAGS) -Wno-unused-function -MMD -MP -c $< -o $@ + +$(BIN_DIR) $(GEN_DIR) $(OBJ_DIR): + mkdir -p $@ + +host-tools: + @command -v $(CC) >/dev/null || { echo "missing host C compiler: $(CC)" >&2; exit 1; } + @command -v $(FLEX) >/dev/null || { echo "missing flex: $(FLEX)" >&2; exit 1; } + @command -v $(BISON) >/dev/null || { echo "missing bison: $(BISON)" >&2; exit 1; } + @command -v $(PYTHON) >/dev/null || { echo "missing Python: $(PYTHON)" >&2; exit 1; } + @$(FLEX) --version | grep -F 'flex 2.6.4' >/dev/null || { echo "expected flex 2.6.4" >&2; exit 1; } + @$(BISON) --version | head -n 1 | grep -F '3.8.2' >/dev/null || { echo "expected bison 3.8.2" >&2; exit 1; } + +coverage: + $(PYTHON) tools/inventory_grammar.py --check-baseline + $(PYTHON) tools/check_coverage.py + +contract: + $(PYTHON) tests/run_tests.py + +clean: + rm -rf $(BUILD_DIR) + +test: $(ADAC) + @set -eu; \ + workdir=$$(mktemp -d "$${TMPDIR:-/tmp}/adac-host-test.XXXXXX"); \ + trap 'rm -rf "$$workdir"' EXIT HUP INT TERM; \ + printf 'procedure Empty is\nbegin\n null;\nend Empty;\n' > "$$workdir/empty.adb"; \ + printf 'procedure Token_Test is\n type T is null record;\n V : Integer := 16#fF#;\nbegin\n for I in reverse 1 .. 1 loop\n null;\n end loop;\nend Token_Test;\n' > "$$workdir/token.adb"; \ + $(ADAC) --help > "$$workdir/help"; \ + grep -F 'usage: adac ' "$$workdir/help" >/dev/null; \ + $(ADAC) check "$$workdir/empty.adb"; \ + $(ADAC) check "$$workdir/token.adb"; \ + printf 'private procedure Private_Unit is\nbegin\n null;\nend Private_Unit;\n' > "$$workdir/private.adb"; \ + $(ADAC) check --emit-ast "$$workdir/private.adb" > "$$workdir/private.ast"; \ + grep -F 'stringExp(private)' "$$workdir/private.ast" >/dev/null; \ + $(ADAC) check --emit-ast --emit-sem --emit-ir --emit-asm "$$workdir/empty.adb" > "$$workdir/dumps"; \ + grep -F 'semantic dump unavailable in R0' "$$workdir/dumps" >/dev/null; \ + if $(ADAC) compile -o "$$workdir/out.o" "$$workdir/empty.adb" > "$$workdir/compile.out" 2> "$$workdir/compile.err"; then exit 1; fi; \ + grep -F 'unsupported-in-release: compile phase is not available in R0' "$$workdir/compile.err" >/dev/null; \ + test ! -e "$$workdir/out.o"; \ + printf 'procedure Bad is begin\n' > "$$workdir/bad.adb"; \ + if $(ADAC) check "$$workdir/bad.adb" > "$$workdir/bad.out" 2> "$$workdir/bad.err"; then exit 1; fi; \ + grep -F "$$workdir/bad.adb:2:1: error: syntax error" "$$workdir/bad.err" >/dev/null; \ + printf 'procedure Broken is\n @\nbegin\n null;\nend Broken;\n' > "$$workdir/line-column.adb"; \ + if $(ADAC) check "$$workdir/line-column.adb" > "$$workdir/line-column.out" 2> "$$workdir/line-column.err"; then exit 1; fi; \ + grep -F "$$workdir/line-column.adb:2:3: error: Illegal token" "$$workdir/line-column.err" >/dev/null; \ + if $(ADAC) check "$$workdir/missing.adb" > "$$workdir/missing.out" 2> "$$workdir/missing.err"; then exit 1; fi; \ + grep -F 'No such file or directory' "$$workdir/missing.err" >/dev/null; \ + $(ADAC) check "$$workdir/empty.adb" + +-include $(OBJECTS:.o=.d) diff --git a/README.md b/README.md index 0cf3cd4..a50f6a2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,56 @@ -ada-compiler -============ -Course Project for CS335. -*This project is no longer maintained.* +# Ada compiler restoration + +This repository is being restored as a staged Ada compiler targeting static +Linux MIPS32r2 executables. R0 provides a deterministic host frontend build and +an honest command-line foundation; target code generation and semantic analysis +are release-owned work that is not yet available. + +## Host prerequisites + +- C11 compiler +- GNU Make +- Flex 2.6.4 +- Bison 3.8.2 + +Build the host driver with: + +```sh +make strict +``` + +Generated lexer/parser files, objects, dependency files, and the executable are +contained under `build/`; source files are never regenerated in place. + +## CLI + +```text +adac check [--emit-ast] [--emit-sem] [--emit-ir] [--emit-asm] SOURCE +adac compile [--unit-dir DIR] [-o PATH] SOURCE +adac build [--unit-dir DIR] [-o PATH] SOURCE +``` + +Use `build/bin/adac --help` for the full option list. + +- `check` parses the source and returns a nonzero status for input or syntax + diagnostics. +- `compile` and `build` parse successfully but return a stable + `unsupported-in-release` diagnostic in R0. They intentionally leave no output + artifacts. +- `--emit-ast` dumps the current frontend AST. Semantic, IR, and assembly dumps + explicitly report their R0-unavailable status rather than pretending to + produce later-phase output. +- Based-literal digits are case-insensitive (`16#fF#` is accepted); spelling is + otherwise preserved by the lexer for later syntax diagnostics and dumps. + +## Validation + +```sh +make strict +make test +``` + +`make strict` validates host tools, the grammar-coverage baseline and manifest, +and the direct Linux/MIPS ELF/QEMU/ABI contract. `make test` runs the focused +host CLI smoke coverage: help, valid input, malformed input, missing input, +unsupported phases, dump flags, and repeated invocations. `make all` is +build-only. diff --git a/absyn.c b/absyn.c index 6e2bdce..9e11348 100644 --- a/absyn.c +++ b/absyn.c @@ -2,7 +2,6 @@ * absyn.c - Abstract Syntax Functions. Most functions create an instance of an * abstract syntax rule. */ -#include #include "util.h" #include "symbol.h" /* symbol table data structures */ #include "absyn.h" /* abstract syntax data structures */ @@ -58,13 +57,11 @@ A_exp A_NumberExp(A_pos pos, string s) return p; } -A_exp A_StringExp(A_pos pos, S_table table, string s) +A_exp A_StringExp(A_pos pos, string s) {A_exp p = checked_malloc(sizeof(*p)); p->kind=A_stringExp; p->pos=pos; - A_ty t=S_look(table,S_Symbol(s)); - if(t==NULL) p->dec_type=S_Symbol(s); - else p->dec_type=t->dec_type; + p->dec_type=S_Symbol(s); p->u.stringg=s; return p; } @@ -456,7 +453,7 @@ A_dec A_VarDec(A_pos pos, S_symbol var, S_symbol typ, A_exp init) p->u.var.var=var; p->u.var.typ=typ; p->u.var.init=init; - p->u.var.escape=TRUE; + p->u.var.escape=true; return p; } @@ -532,7 +529,7 @@ A_field A_Field(A_pos pos, S_symbol name, S_symbol typ) p->pos=pos; p->name=name; p->typ=typ; - p->escape=TRUE; + p->escape=true; return p; } diff --git a/absyn.h b/absyn.h index b8efefc..0c6ec67 100644 --- a/absyn.h +++ b/absyn.h @@ -5,6 +5,11 @@ * Linked list types end with "..list" */ +#ifndef ADA_ABSYN_H +#define ADA_ABSYN_H + +#include "symbol.h" + /* Type Definitions */ typedef int A_pos; @@ -155,7 +160,7 @@ A_var A_SubscriptVar(A_pos pos, A_var var, A_exp exp); A_exp A_VarExp(A_pos pos, A_var var); A_exp A_NilExp(A_pos pos); A_exp A_NumberExp(A_pos pos, string number); -A_exp A_StringExp(A_pos pos, S_table table, string s); +A_exp A_StringExp(A_pos pos, string s); A_exp A_CallExp(A_pos pos, S_symbol func, A_expList args); A_exp A_OpExp(A_pos pos, A_oper oper, A_exp left, A_exp right); A_exp A_UnaryOpExp(A_pos pos, A_unaryOper oper, A_exp exp); @@ -217,3 +222,5 @@ A_namety A_Namety(S_symbol name, A_ty ty); A_nametyList A_NametyList(A_namety head, A_nametyList tail); A_efield A_Efield(S_symbol name, A_exp exp); A_efieldList A_EfieldList(A_efield head, A_efieldList tail); + +#endif diff --git a/ci/Containerfile b/ci/Containerfile new file mode 100644 index 0000000..d437d65 --- /dev/null +++ b/ci/Containerfile @@ -0,0 +1,23 @@ +# syntax=docker/dockerfile:1 +FROM ubuntu:24.04 + +ARG DEBIAN_FRONTEND=noninteractive + +# Keep the target development libc deliberately absent. The runtime is linked +# with ld directly, so accidentally introducing a CRT, libc, or libgcc object +# becomes a link failure rather than a host-dependent success. +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + bison=2:3.8.2+dfsg-1build2 \ + flex=2.6.4-8.2build1 \ + gcc=4:13.2.0-7ubuntu1 \ + make=4.3-4.1build2 \ + gcc-13-mipsel-linux-gnu=13.3.0-6ubuntu2~24.04cross1 \ + binutils-mipsel-linux-gnu=2.42-2ubuntu1cross5 \ + qemu-user=1:8.2.2+ds-0ubuntu1.17 \ + linux-libc-dev-mipsel-cross=6.8.0-25.25cross2 \ + gnat-13=13.3.0-6ubuntu2~24.04.1 \ + python3 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /work diff --git a/ci/toolchain.lock b/ci/toolchain.lock new file mode 100644 index 0000000..70b9edc --- /dev/null +++ b/ci/toolchain.lock @@ -0,0 +1,34 @@ +# R0 Linux/mipsel toolchain lock +# +# Distribution: Ubuntu 24.04 (Noble) +# This lock intentionally does not contain libc6-dev-mipsel-cross. The +# compiler-owned runtime must remain freestanding and link without target CRT, +# libc, or libgcc objects. + +HOST_CC=gcc +HOST_CC_PACKAGE=gcc=4:13.2.0-7ubuntu1 +MAKE_PACKAGE=make=4.3-4.1build2 +FLEX_PACKAGE=flex=2.6.4-8.2build1 +BISON_PACKAGE=bison=2:3.8.2+dfsg-1build2 +GNAT_PACKAGE=gnat-13=13.3.0-6ubuntu2~24.04.1 +PYTHON_PACKAGE=python3 + +TARGET_TRIPLE=mipsel-linux-gnu +TARGET_CC=mipsel-linux-gnu-gcc-13 +TARGET_CC_PACKAGE=gcc-13-mipsel-linux-gnu=13.3.0-6ubuntu2~24.04cross1 +TARGET_BINUTILS_PACKAGE=binutils-mipsel-linux-gnu=2.42-2ubuntu1cross5 +TARGET_AS=mipsel-linux-gnu-as +TARGET_LD=mipsel-linux-gnu-ld +TARGET_NM=mipsel-linux-gnu-nm +TARGET_READELF=mipsel-linux-gnu-readelf +TARGET_OBJDUMP=mipsel-linux-gnu-objdump +QEMU=qemu-mipsel +QEMU_PACKAGE=qemu-user=1:8.2.2+ds-0ubuntu1.17 +TARGET_LINUX_HEADERS_PACKAGE=linux-libc-dev-mipsel-cross=6.8.0-25.25cross2 +TARGET_UNISTD=/usr/mipsel-linux-gnu/include/asm/unistd.h + +# These are individual argument lists rather than implicit compiler defaults. +TARGET_AS_FLAGS=-EL -32 -mips32r2 -mhard-float -mfp32 -mnan=legacy +TARGET_CFLAGS=-march=mips32r2 -mabi=32 -EL -mhard-float -mfp32 -mnan=legacy -fno-pic -mno-abicalls -G0 -ffreestanding -fno-stack-protector -fno-builtin -Wall -Wextra -Werror +TARGET_LD_FLAGS=-m elf32ltsmip -EL -static -T runtime/mipsel-linux.ld -e _start --orphan-handling=error +EXPECTED_E_FLAGS=0x70001001 diff --git a/compile.c b/compile.c new file mode 100644 index 0000000..7595d15 --- /dev/null +++ b/compile.c @@ -0,0 +1,80 @@ +#include +#include +#include + +#include "absyn.h" +#include "compile.h" +#include "errormsg.h" +#include "prabsyn.h" + +extern FILE *yyin; +extern int yyparse(A_exp *root); +extern void yyrestart(FILE *input_file); +extern void lexer_reset(void); + +const char *Comp_phase_name(Comp_phase phase) +{ + switch (phase) { + case COMP_PHASE_CHECK: + return "check"; + case COMP_PHASE_COMPILE: + return "compile"; + case COMP_PHASE_BUILD: + return "build"; + } + return "unknown"; +} + +static Comp_result unsupported(Comp_phase phase, FILE *diagnostics) +{ + fprintf(diagnostics, + "adac: unsupported-in-release: %s phase is not available in R0\n", + Comp_phase_name(phase)); + return COMP_RESULT_UNSUPPORTED; +} + +Comp_result Comp_run(const Comp_options *options, FILE *diagnostics) +{ + int parse_status; + A_exp parser_root = NULL; + + if (options == NULL || options->input_path == NULL) { + return COMP_RESULT_INTERNAL; + } + + yyin = fopen(options->input_path, "r"); + if (yyin == NULL) { + fprintf(diagnostics, "adac: %s: %s\n", options->input_path, strerror(errno)); + return COMP_RESULT_INPUT; + } + + EM_reset(options->input_path); + lexer_reset(); + yyrestart(yyin); + parse_status = yyparse(&parser_root); + fclose(yyin); + yyin = NULL; + + if (parse_status != 0 || EM_anyErrors || parser_root == NULL) { + return COMP_RESULT_DIAGNOSTIC; + } + + if (options->emit_ast) { + pr_exp(stdout, parser_root, 0); + fputc('\n', stdout); + } + if (options->emit_sem) { + fputs("semantic dump unavailable in R0\n", stdout); + } + if (options->emit_ir) { + fputs("IR dump unavailable in R0\n", stdout); + } + if (options->emit_asm) { + fputs("assembly dump unavailable in R0\n", stdout); + } + + if (options->phase == COMP_PHASE_CHECK) { + return COMP_RESULT_OK; + } + return unsupported(options->phase, diagnostics); +} diff --git a/compile.h b/compile.h new file mode 100644 index 0000000..b2cf206 --- /dev/null +++ b/compile.h @@ -0,0 +1,36 @@ +#ifndef ADA_COMPILE_H +#define ADA_COMPILE_H + +#include +#include + +typedef enum { + COMP_PHASE_CHECK, + COMP_PHASE_COMPILE, + COMP_PHASE_BUILD +} Comp_phase; + +typedef struct { + Comp_phase phase; + const char *input_path; + const char *unit_dir; + const char *output_path; + bool emit_ast; + bool emit_sem; + bool emit_ir; + bool emit_asm; +} Comp_options; + +typedef enum { + COMP_RESULT_OK = 0, + COMP_RESULT_USAGE = 64, + COMP_RESULT_INPUT = 66, + COMP_RESULT_DIAGNOSTIC = 1, + COMP_RESULT_UNSUPPORTED = 2, + COMP_RESULT_INTERNAL = 70 +} Comp_result; + +Comp_result Comp_run(const Comp_options *options, FILE *diagnostics); +const char *Comp_phase_name(Comp_phase phase); + +#endif diff --git a/docs/grammar-coverage.csv b/docs/grammar-coverage.csv new file mode 100644 index 0000000..aebe521 --- /dev/null +++ b/docs/grammar-coverage.csv @@ -0,0 +1,521 @@ +# Generated by tools/inventory_grammar.py --write-manifest; do not edit by hand. +row_type,nonterminal,alternative,production,ast_node,semantic_owner,ir_runtime_owner,closing_release,current_state,tests,source,classification,outcome,notes +grammar,goal_symbol,1,goal_symbol : compilation,A_SeqExp,Sem_program (planned),release-owned (planned),R0,inventory-only,inventory: parser.y,,,, +grammar,pragma,1,pragma : PRAGMA IDENTIFIER ';',A_Pragma,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,pragma,2,pragma : PRAGMA simple_name '(' pragma_arg_s ')' ';',A_Pragmalist,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,pragma_arg_s,1,pragma_arg_s : pragma_arg,A_ExpList,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,pragma_arg_s,2,"pragma_arg_s : pragma_arg_s ',' pragma_arg",A_ExpList,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,pragma_arg,1,pragma_arg : expression,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,pragma_arg,2,pragma_arg : simple_name RIGHT_SHAFT expression,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,pragma_s,1,pragma_s : %empty,A_ExpList,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,pragma_s,2,pragma_s : pragma_s pragma,A_ExpList,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,decl,1,decl : object_decl,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl,2,decl : number_decl,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl,3,decl : type_decl,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl,4,decl : subtype_decl,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,decl,5,decl : subprog_decl,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl,6,decl : pkg_decl,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,decl,7,decl : task_decl,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,decl,8,decl : prot_decl,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,decl,9,decl : exception_decl,syntax-only,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,decl,10,decl : rename_decl,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,decl,11,decl : generic_decl,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,decl,12,decl : body_stub,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,decl,13,decl : error ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,object_decl,1,object_decl : def_id_s ':' object_qualifier_opt object_subtype_def init_opt ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,def_id_s,1,def_id_s : def_id,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,def_id_s,2,"def_id_s : def_id_s ',' def_id",A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,def_id,1,def_id : IDENTIFIER,A_StringExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,object_qualifier_opt,1,object_qualifier_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,object_qualifier_opt,2,object_qualifier_opt : ALIASED,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,object_qualifier_opt,3,object_qualifier_opt : CONSTANT,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,object_qualifier_opt,4,object_qualifier_opt : ALIASED CONSTANT,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,object_subtype_def,1,object_subtype_def : subtype_ind,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,object_subtype_def,2,object_subtype_def : array_type,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,init_opt,1,init_opt : %empty,A_NilExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,init_opt,2,init_opt : IS_ASSIGNED expression,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,number_decl,1,number_decl : def_id_s ':' CONSTANT IS_ASSIGNED expression ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,type_decl,1,type_decl : TYPE IDENTIFIER discrim_part_opt type_completion ';',syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,discrim_part_opt,1,discrim_part_opt : %empty,A_ExpList,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,discrim_part_opt,2,discrim_part_opt : discrim_part,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,discrim_part_opt,3,discrim_part_opt : '(' BOX ')',A_ExpList,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,type_completion,1,type_completion : %empty,A_NilExp,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,type_completion,2,type_completion : IS type_def,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,type_def,1,type_def : enumeration_type,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,type_def,2,type_def : integer_type,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,type_def,3,type_def : real_type,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,type_def,4,type_def : array_type,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,type_def,5,type_def : record_type,A_NotImplemented,Sem_program (planned),release-owned (planned),R3,parser-placeholder,inventory: parser.y,,,, +grammar,type_def,6,type_def : access_type,A_NotImplemented,Sem_program (planned),release-owned (planned),R3,parser-placeholder,inventory: parser.y,,,, +grammar,type_def,7,type_def : derived_type,A_NotImplemented,Sem_program (planned),release-owned (planned),R2,parser-placeholder,inventory: parser.y,,,, +grammar,type_def,8,type_def : private_type,A_NotImplemented,Sem_program (planned),release-owned (planned),R3,parser-placeholder,inventory: parser.y,,,, +grammar,subtype_decl,1,subtype_decl : SUBTYPE IDENTIFIER IS subtype_ind ';',syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,subtype_ind,1,subtype_ind : name constraint,A_NameConstr,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,subtype_ind,2,subtype_ind : name,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,constraint,1,constraint : range_constraint,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,constraint,2,constraint : decimal_digits_constraint,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,decimal_digits_constraint,1,decimal_digits_constraint : DIGITS expression range_constr_opt,A_DecimalConstr,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,derived_type,1,derived_type : NEW subtype_ind,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,derived_type,2,derived_type : NEW subtype_ind WITH PRIVATE,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,derived_type,3,derived_type : NEW subtype_ind WITH record_def,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,derived_type,4,derived_type : ABSTRACT NEW subtype_ind WITH PRIVATE,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,derived_type,5,derived_type : ABSTRACT NEW subtype_ind WITH record_def,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,range_constraint,1,range_constraint : RANGE range,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,range,1,range : simple_expression DOT_DOT simple_expression,A_OpExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,range,2,range : name TICK RANGE,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,range,3,range : name TICK RANGE '(' expression ')',syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,enumeration_type,1,enumeration_type : '(' enum_id_s ')',A_EnumExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,enum_id_s,1,enum_id_s : enum_id,A_ExpList,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,enum_id_s,2,"enum_id_s : enum_id_s ',' enum_id",A_ExpList,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,enum_id,1,enum_id : IDENTIFIER,A_StringExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,enum_id,2,enum_id : CHARACTER,A_StringExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,integer_type,1,integer_type : range_spec,A_IntdefExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,integer_type,2,integer_type : MOD expression,A_IntdefExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,range_spec,1,range_spec : range_constraint,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,range_spec_opt,1,range_spec_opt : %empty,A_NilExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,range_spec_opt,2,range_spec_opt : range_spec,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,real_type,1,real_type : float_type,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,real_type,2,real_type : fixed_type,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,float_type,1,float_type : DIGITS expression range_spec_opt,A_FloatdefExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,fixed_type,1,fixed_type : DELTA expression range_spec,A_FixeddefExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,fixed_type,2,fixed_type : DELTA expression DIGITS expression range_spec_opt,A_FixeddefdigitExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,array_type,1,array_type : unconstr_array_type,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,array_type,2,array_type : constr_array_type,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,unconstr_array_type,1,unconstr_array_type : ARRAY '(' index_s ')' OF component_subtype_def,A_UnconarraydefExp,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,constr_array_type,1,constr_array_type : ARRAY iter_index_constraint OF component_subtype_def,A_ConarraydefExp,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,component_subtype_def,1,component_subtype_def : aliased_opt subtype_ind,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,aliased_opt,1,aliased_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,aliased_opt,2,aliased_opt : ALIASED,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,index_s,1,index_s : index,A_ExpList,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,index_s,2,"index_s : index_s ',' index",A_ExpList,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,index,1,index : name RANGE BOX,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,iter_index_constraint,1,iter_index_constraint : '(' iter_discrete_range_s ')',syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,iter_discrete_range_s,1,iter_discrete_range_s : discrete_range,A_ExpList,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,iter_discrete_range_s,2,"iter_discrete_range_s : iter_discrete_range_s ',' discrete_range",A_ExpList,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,discrete_range,1,discrete_range : name range_constr_opt,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,discrete_range,2,discrete_range : range,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,range_constr_opt,1,range_constr_opt : %empty,A_NilExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,range_constr_opt,2,range_constr_opt : range_constraint,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,record_type,1,record_type : tagged_opt limited_opt record_def,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,record_def,1,record_def : RECORD pragma_s comp_list END RECORD,A_RecorddefExp,Sem_program (planned),release-owned (planned),R7,parser-placeholder,inventory: parser.y,,,, +grammar,record_def,2,record_def : NuLL RECORD,A_NullrecorddefExp,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,tagged_opt,1,tagged_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,tagged_opt,2,tagged_opt : TAGGED,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,tagged_opt,3,tagged_opt : ABSTRACT TAGGED,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,comp_list,1,comp_list : comp_decl_s variant_part_opt,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,comp_list,2,comp_list : variant_part pragma_s,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,comp_list,3,comp_list : NuLL ';' pragma_s,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,comp_decl_s,1,comp_decl_s : comp_decl,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,comp_decl_s,2,comp_decl_s : comp_decl_s pragma_s comp_decl,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,variant_part_opt,1,variant_part_opt : pragma_s,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,variant_part_opt,2,variant_part_opt : pragma_s variant_part pragma_s,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,comp_decl,1,comp_decl : def_id_s ':' component_subtype_def init_opt ';',syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,comp_decl,2,comp_decl : error ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,discrim_part,1,discrim_part : '(' discrim_spec_s ')',syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,discrim_spec_s,1,discrim_spec_s : discrim_spec,A_ExpList,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,discrim_spec_s,2,discrim_spec_s : discrim_spec_s ';' discrim_spec,A_ExpList,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,discrim_spec,1,discrim_spec : def_id_s ':' access_opt mark init_opt,A_NotImplemented,Sem_program (planned),release-owned (planned),R3,parser-placeholder,inventory: parser.y,,,, +grammar,discrim_spec,2,discrim_spec : error,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,access_opt,1,access_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,access_opt,2,access_opt : ACCESS,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,variant_part,1,variant_part : CASE simple_name IS pragma_s variant_s END CASE ';',syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,variant_s,1,variant_s : variant,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,variant_s,2,variant_s : variant_s variant,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,variant,1,variant : WHEN choice_s RIGHT_SHAFT pragma_s comp_list,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,choice_s,1,choice_s : choice,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,choice_s,2,choice_s : choice_s '|' choice,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,choice,1,choice : expression,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,choice,2,choice : discrete_with_range,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,choice,3,choice : OTHERS,A_StringExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,discrete_with_range,1,discrete_with_range : name range_constraint,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,discrete_with_range,2,discrete_with_range : range,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,access_type,1,access_type : ACCESS subtype_ind,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,access_type,2,access_type : ACCESS CONSTANT subtype_ind,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,access_type,3,access_type : ACCESS ALL subtype_ind,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,access_type,4,access_type : ACCESS prot_opt PROCEDURE formal_part_opt,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,access_type,5,access_type : ACCESS prot_opt FUNCTION formal_part_opt RETURN mark,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_opt,1,prot_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_opt,2,prot_opt : PROTECTED,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,decl_part,1,decl_part : %empty,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl_part,2,decl_part : decl_item_or_body_s1,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl_item_s,1,decl_item_s : %empty,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl_item_s,2,decl_item_s : decl_item_s1,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl_item_s1,1,decl_item_s1 : decl_item,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl_item_s1,2,decl_item_s1 : decl_item_s1 decl_item,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl_item,1,decl_item : decl,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl_item,2,decl_item : use_clause,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,decl_item,3,decl_item : rep_spec,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,decl_item,4,decl_item : pragma,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,decl_item_or_body_s1,1,decl_item_or_body_s1 : decl_item_or_body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl_item_or_body_s1,2,decl_item_or_body_s1 : decl_item_or_body_s1 decl_item_or_body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl_item_or_body,1,decl_item_or_body : body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,decl_item_or_body,2,decl_item_or_body : decl_item,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,body,1,body : subprog_body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,body,2,body : pkg_body,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,body,3,body : task_body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,body,4,body : prot_body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,name,1,name : simple_name,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,name,2,name : indexed_comp,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,name,3,name : selected_comp,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,name,4,name : attribute,A_NotImplemented,Sem_program (planned),release-owned (planned),R2,parser-placeholder,inventory: parser.y,,,, +grammar,name,5,name : operator_symbol,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,mark,1,mark : simple_name,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,mark,2,mark : mark TICK attribute_id,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,mark,3,mark : mark '.' simple_name,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,simple_name,1,simple_name : IDENTIFIER,A_StringExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,compound_name,1,compound_name : simple_name,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,compound_name,2,compound_name : compound_name '.' simple_name,A_OpExp,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,c_name_list,1,c_name_list : compound_name,A_ExpList,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,c_name_list,2,"c_name_list : c_name_list ',' compound_name",A_ExpList,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,used_char,1,used_char : CHARACTER,A_StringExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,operator_symbol,1,operator_symbol : STRING,A_StringExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,indexed_comp,1,indexed_comp : name '(' value_s ')',A_FunctionUse,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,value_s,1,value_s : value,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,value_s,2,"value_s : value_s ',' value",A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,value,1,value : expression,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,value,2,value : comp_assoc,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,value,3,value : discrete_with_range,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,value,4,value : error,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,selected_comp,1,selected_comp : name '.' simple_name,A_OpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,selected_comp,2,selected_comp : name '.' used_char,A_OpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,selected_comp,3,selected_comp : name '.' operator_symbol,A_OpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,selected_comp,4,selected_comp : name '.' ALL,A_OpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,attribute,1,attribute : name TICK attribute_id,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,attribute_id,1,attribute_id : IDENTIFIER,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,attribute_id,2,attribute_id : DIGITS,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,attribute_id,3,attribute_id : DELTA,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,attribute_id,4,attribute_id : ACCESS,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,literal,1,literal : NUMBER,A_NumberExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,literal,2,literal : used_char,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,literal,3,literal : NuLL,A_NilExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,aggregate,1,aggregate : '(' comp_assoc ')',syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,aggregate,2,aggregate : '(' value_s_2 ')',syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,aggregate,3,aggregate : '(' expression WITH value_s ')',syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,aggregate,4,aggregate : '(' expression WITH NuLL RECORD ')',syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,aggregate,5,aggregate : '(' NuLL RECORD ')',syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,value_s_2,1,"value_s_2 : value ',' value",syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,value_s_2,2,"value_s_2 : value_s_2 ',' value",syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,comp_assoc,1,comp_assoc : choice_s RIGHT_SHAFT expression,A_CompAssoc,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,expression,1,expression : relation,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,expression,2,expression : expression logical relation,A_OpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,expression,3,expression : expression short_circuit relation,A_OpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,logical,1,logical : AND,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,logical,2,logical : OR,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,logical,3,logical : XOR,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,short_circuit,1,short_circuit : AND THEN,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,short_circuit,2,short_circuit : OR ELSE,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,relation,1,relation : simple_expression,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,relation,2,relation : simple_expression relational simple_expression,A_OpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,relation,3,relation : simple_expression membership range,A_OpExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,relation,4,relation : simple_expression membership name,A_OpExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,relational,1,relational : '=',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,relational,2,relational : NE,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,relational,3,relational : '<',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,relational,4,relational : LT_EQ,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,relational,5,relational : '>',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,relational,6,relational : GE,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,membership,1,membership : IN,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,membership,2,membership : NOT IN,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,simple_expression,1,simple_expression : unary term,A_UnaryOpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,simple_expression,2,simple_expression : term,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,simple_expression,3,simple_expression : simple_expression adding term,A_OpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,unary,1,unary : '+',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,unary,2,unary : '-',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,adding,1,adding : '+',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,adding,2,adding : '-',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,adding,3,adding : '&',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,term,1,term : factor,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,term,2,term : term multiplying factor,A_OpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,multiplying,1,multiplying : '*',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,multiplying,2,multiplying : '/',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,multiplying,3,multiplying : MOD,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,multiplying,4,multiplying : REM,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,factor,1,factor : primary,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,factor,2,factor : NOT primary,A_UnaryOpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,factor,3,factor : ABS primary,A_UnaryOpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,factor,4,factor : primary EXPON primary,A_OpExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,primary,1,primary : literal,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,primary,2,primary : name,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,primary,3,primary : allocator,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,primary,4,primary : qualified,syntax-only,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,primary,5,primary : parenthesized_primary,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,parenthesized_primary,1,parenthesized_primary : aggregate,A_NotImplemented,Sem_program (planned),release-owned (planned),R3,parser-placeholder,inventory: parser.y,,,, +grammar,parenthesized_primary,2,parenthesized_primary : '(' expression ')',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,qualified,1,qualified : name TICK parenthesized_primary,A_OpExp,Sem_program (planned),release-owned (planned),R2,inventory-only,inventory: parser.y,,,, +grammar,allocator,1,allocator : NEW name,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,allocator,2,allocator : NEW qualified,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,statement_s,1,statement_s : statement,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,statement_s,2,statement_s : statement_s statement,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,statement,1,statement : unlabeled,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,statement,2,statement : label statement,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,unlabeled,1,unlabeled : simple_stmt,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,unlabeled,2,unlabeled : compound_stmt,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,unlabeled,3,unlabeled : pragma,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,simple_stmt,1,simple_stmt : null_stmt,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,simple_stmt,2,simple_stmt : assign_stmt,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,simple_stmt,3,simple_stmt : exit_stmt,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,simple_stmt,4,simple_stmt : return_stmt,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,simple_stmt,5,simple_stmt : goto_stmt,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,simple_stmt,6,simple_stmt : procedure_call,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,simple_stmt,7,simple_stmt : delay_stmt,A_NotImplemented,Sem_program (planned),release-owned (planned),R6,parser-placeholder,inventory: parser.y,,,, +grammar,simple_stmt,8,simple_stmt : abort_stmt,A_NotImplemented,Sem_program (planned),release-owned (planned),R6,parser-placeholder,inventory: parser.y,,,, +grammar,simple_stmt,9,simple_stmt : raise_stmt,syntax-only,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,simple_stmt,10,simple_stmt : code_stmt,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,simple_stmt,11,simple_stmt : requeue_stmt,A_NotImplemented,Sem_program (planned),release-owned (planned),R6,parser-placeholder,inventory: parser.y,,,, +grammar,simple_stmt,12,simple_stmt : error ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,compound_stmt,1,compound_stmt : if_stmt,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,compound_stmt,2,compound_stmt : case_stmt,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,compound_stmt,3,compound_stmt : loop_stmt,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,compound_stmt,4,compound_stmt : block,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,compound_stmt,5,compound_stmt : accept_stmt,A_NotImplemented,Sem_program (planned),release-owned (planned),R6,parser-placeholder,inventory: parser.y,,,, +grammar,compound_stmt,6,compound_stmt : select_stmt,A_NotImplemented,Sem_program (planned),release-owned (planned),R6,parser-placeholder,inventory: parser.y,,,, +grammar,label,1,label : LT_LT IDENTIFIER GT_GT,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,null_stmt,1,null_stmt : NuLL ';',A_NilExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,assign_stmt,1,assign_stmt : name IS_ASSIGNED expression ';',A_AssignExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,if_stmt,1,if_stmt : IF cond_clause_s else_opt END IF ';',A_IfExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,cond_clause_s,1,cond_clause_s : cond_clause,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,cond_clause_s,2,cond_clause_s : cond_clause_s ELSIF cond_clause,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,cond_clause,1,cond_clause : cond_part statement_s,A_CondExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,cond_part,1,cond_part : condition THEN,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,condition,1,condition : expression,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,else_opt,1,else_opt : %empty,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,else_opt,2,else_opt : ELSE statement_s,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,case_stmt,1,case_stmt : case_hdr pragma_s alternative_s END CASE ';',A_Case,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,case_hdr,1,case_hdr : CASE expression IS,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,alternative_s,1,alternative_s : %empty,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,alternative_s,2,alternative_s : alternative_s alternative,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,alternative,1,alternative : WHEN choice_s RIGHT_SHAFT statement_s,A_Alternative,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,loop_stmt,1,loop_stmt : label_opt iteration basic_loop id_opt ';',A_LoopExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,label_opt,1,label_opt : %empty,A_NilExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,label_opt,2,label_opt : IDENTIFIER ':',A_StringExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,iteration,1,iteration : %empty,A_NilExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,iteration,2,iteration : WHILE condition,A_WhileExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,iteration,3,iteration : iter_part reverse_opt discrete_range,A_ForExp,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,iter_part,1,iter_part : FOR IDENTIFIER IN,A_StringExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,reverse_opt,1,reverse_opt : %empty,A_NilExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,reverse_opt,2,reverse_opt : REVERSE,A_StringExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,basic_loop,1,basic_loop : LOOP statement_s END LOOP,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,id_opt,1,id_opt : %empty,A_NilExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,id_opt,2,id_opt : designator,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,block,1,block : label_opt block_decl block_body END id_opt ';',A_SeqExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,block_decl,1,block_decl : %empty,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,block_decl,2,block_decl : DECLARE decl_part,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,block_body,1,block_body : BegiN handled_stmt_s,syntax-only,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,handled_stmt_s,1,handled_stmt_s : statement_s except_handler_part_opt,syntax-only,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,except_handler_part_opt,1,except_handler_part_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,except_handler_part_opt,2,except_handler_part_opt : except_handler_part,syntax-only,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,exit_stmt,1,exit_stmt : EXIT name_opt when_opt ';',A_ExitExp,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,name_opt,1,name_opt : %empty,A_NilExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,name_opt,2,name_opt : name,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,when_opt,1,when_opt : %empty,A_NilExp,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,when_opt,2,when_opt : WHEN condition,syntax-only,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,return_stmt,1,return_stmt : RETURN ';',A_ReturnExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,return_stmt,2,return_stmt : RETURN expression ';',A_ReturnExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,goto_stmt,1,goto_stmt : GOTO name ';',A_GotoExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,subprog_decl,1,subprog_decl : subprog_spec ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,subprog_decl,2,subprog_decl : generic_subp_inst ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,subprog_decl,3,subprog_decl : subprog_spec_is_push ABSTRACT ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,subprog_spec,1,subprog_spec : PROCEDURE compound_name formal_part_opt,A_SubprogSpec,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,subprog_spec,2,subprog_spec : FUNCTION designator formal_part_opt RETURN name,A_NotImplemented,Sem_program (planned),release-owned (planned),R1,parser-placeholder,inventory: parser.y,,,, +grammar,subprog_spec,3,subprog_spec : FUNCTION designator,A_NotImplemented,Sem_program (planned),release-owned (planned),R1,parser-placeholder,inventory: parser.y,,,, +grammar,designator,1,designator : compound_name,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,designator,2,designator : STRING,A_StringExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,formal_part_opt,1,formal_part_opt : %empty,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,formal_part_opt,2,formal_part_opt : formal_part,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,formal_part,1,formal_part : '(' param_s ')',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,param_s,1,param_s : param,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,param_s,2,param_s : param_s ';' param,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,param,1,param : def_id_s ':' mode mark init_opt,A_NotImplemented,Sem_program (planned),release-owned (planned),R1,parser-placeholder,inventory: parser.y,,,, +grammar,param,2,param : error,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,mode,1,mode : %empty,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,mode,2,mode : IN,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,mode,3,mode : OUT,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,mode,4,mode : IN OUT,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,mode,5,mode : ACCESS,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,subprog_spec_is_push,1,subprog_spec_is_push : subprog_spec IS,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,subprog_body,1,subprog_body : subprog_spec_is_push decl_part block_body END id_opt ';',A_SeqExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,procedure_call,1,procedure_call : name ';',A_Procedure,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,pkg_decl,1,pkg_decl : pkg_spec ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,pkg_decl,2,pkg_decl : generic_pkg_inst ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,pkg_spec,1,pkg_spec : PACKAGE compound_name IS decl_item_s private_part END c_id_opt,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,private_part,1,private_part : %empty,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,private_part,2,private_part : PRIVATE decl_item_s,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,c_id_opt,1,c_id_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,c_id_opt,2,c_id_opt : compound_name,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,pkg_body,1,pkg_body : PACKAGE BODY compound_name IS decl_part body_opt END c_id_opt ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,body_opt,1,body_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,body_opt,2,body_opt : block_body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,private_type,1,private_type : tagged_opt limited_opt PRIVATE,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,limited_opt,1,limited_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,limited_opt,2,limited_opt : LIMITED,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,use_clause,1,use_clause : USE name_s ';',A_Useclause,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,use_clause,2,use_clause : USE TYPE name_s ';',A_Useclause,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,name_s,1,name_s : name,A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,name_s,2,"name_s : name_s ',' name",A_ExpList,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,rename_decl,1,rename_decl : def_id_s ':' object_qualifier_opt subtype_ind renames ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,rename_decl,2,rename_decl : def_id_s ':' EXCEPTION renames ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,rename_decl,3,rename_decl : rename_unit,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,rename_unit,1,rename_unit : PACKAGE compound_name renames ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,rename_unit,2,rename_unit : subprog_spec renames ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,rename_unit,3,rename_unit : generic_formal_part PACKAGE compound_name renames ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,rename_unit,4,rename_unit : generic_formal_part subprog_spec renames ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,renames,1,renames : RENAMES name,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,task_decl,1,task_decl : task_spec ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,task_spec,1,task_spec : TASK simple_name task_def,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,task_spec,2,task_spec : TASK TYPE simple_name discrim_part_opt task_def,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,task_def,1,task_def : %empty,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,task_def,2,task_def : IS entry_decl_s rep_spec_s task_private_opt END id_opt,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,task_private_opt,1,task_private_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,task_private_opt,2,task_private_opt : PRIVATE entry_decl_s rep_spec_s,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,task_body,1,task_body : TASK BODY simple_name IS decl_part block_body END id_opt ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,prot_decl,1,prot_decl : prot_spec ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_spec,1,prot_spec : PROTECTED IDENTIFIER prot_def,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_spec,2,prot_spec : PROTECTED TYPE simple_name discrim_part_opt prot_def,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_def,1,prot_def : IS prot_op_decl_s prot_private_opt END id_opt,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_private_opt,1,prot_private_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_private_opt,2,prot_private_opt : PRIVATE prot_elem_decl_s,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_op_decl_s,1,prot_op_decl_s : %empty,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_op_decl_s,2,prot_op_decl_s : prot_op_decl_s prot_op_decl,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_op_decl,1,prot_op_decl : entry_decl,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_op_decl,2,prot_op_decl : subprog_spec ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_op_decl,3,prot_op_decl : rep_spec,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,prot_op_decl,4,prot_op_decl : pragma,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,prot_elem_decl_s,1,prot_elem_decl_s : %empty,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_elem_decl_s,2,prot_elem_decl_s : prot_elem_decl_s prot_elem_decl,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_elem_decl,1,prot_elem_decl : prot_op_decl,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_elem_decl,2,prot_elem_decl : comp_decl,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,prot_body,1,prot_body : PROTECTED BODY simple_name IS prot_op_body_s END id_opt ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,prot_op_body_s,1,prot_op_body_s : pragma_s,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,prot_op_body_s,2,prot_op_body_s : prot_op_body_s prot_op_body pragma_s,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,prot_op_body,1,prot_op_body : entry_body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,prot_op_body,2,prot_op_body : subprog_body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,prot_op_body,3,prot_op_body : subprog_spec ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,entry_decl_s,1,entry_decl_s : pragma_s,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,entry_decl_s,2,entry_decl_s : entry_decl_s entry_decl pragma_s,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,entry_decl,1,entry_decl : ENTRY IDENTIFIER formal_part_opt ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,entry_decl,2,entry_decl : ENTRY IDENTIFIER '(' discrete_range ')' formal_part_opt ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,entry_body,1,entry_body : ENTRY IDENTIFIER formal_part_opt WHEN condition entry_body_part,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,entry_body,2,entry_body : ENTRY IDENTIFIER '(' iter_part discrete_range ')' formal_part_opt WHEN condition entry_body_part,syntax-only,Sem_program (planned),release-owned (planned),R3,inventory-only,inventory: parser.y,,,, +grammar,entry_body_part,1,entry_body_part : ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,entry_body_part,2,entry_body_part : IS decl_part block_body END id_opt ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,rep_spec_s,1,rep_spec_s : %empty,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,rep_spec_s,2,rep_spec_s : rep_spec_s rep_spec pragma_s,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,entry_call,1,entry_call : procedure_call,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,accept_stmt,1,accept_stmt : accept_hdr ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,accept_stmt,2,accept_stmt : accept_hdr DO handled_stmt_s END id_opt ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,accept_hdr,1,accept_hdr : ACCEPT entry_name formal_part_opt,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,entry_name,1,entry_name : simple_name,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,entry_name,2,entry_name : entry_name '(' expression ')',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,delay_stmt,1,delay_stmt : DELAY expression ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,delay_stmt,2,delay_stmt : DELAY UNTIL expression ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,select_stmt,1,select_stmt : select_wait,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,select_stmt,2,select_stmt : async_select,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,select_stmt,3,select_stmt : timed_entry_call,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,select_stmt,4,select_stmt : cond_entry_call,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,select_wait,1,select_wait : SELECT guarded_select_alt or_select else_opt END SELECT ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,guarded_select_alt,1,guarded_select_alt : select_alt,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,guarded_select_alt,2,guarded_select_alt : WHEN condition RIGHT_SHAFT select_alt,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,or_select,1,or_select : %empty,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,or_select,2,or_select : or_select OR guarded_select_alt,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,select_alt,1,select_alt : accept_stmt stmts_opt,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,select_alt,2,select_alt : delay_stmt stmts_opt,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,select_alt,3,select_alt : TERMINATE ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,delay_or_entry_alt,1,delay_or_entry_alt : delay_stmt stmts_opt,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,delay_or_entry_alt,2,delay_or_entry_alt : entry_call stmts_opt,syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,async_select,1,async_select : SELECT delay_or_entry_alt THEN ABORT statement_s END SELECT ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,timed_entry_call,1,timed_entry_call : SELECT entry_call stmts_opt OR delay_stmt stmts_opt END SELECT ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,cond_entry_call,1,cond_entry_call : SELECT entry_call stmts_opt ELSE statement_s END SELECT ';',syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,stmts_opt,1,stmts_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,stmts_opt,2,stmts_opt : statement_s,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,abort_stmt,1,abort_stmt : ABORT name_s ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,compilation,1,compilation : %empty,A_ExpList,Sem_program (planned),release-owned (planned),R0,inventory-only,inventory: parser.y,,,, +grammar,compilation,2,compilation : compilation comp_unit,A_ExpList,Sem_program (planned),release-owned (planned),R0,inventory-only,inventory: parser.y,,,, +grammar,compilation,3,compilation : pragma pragma_s,A_ExpList,Sem_program (planned),release-owned (planned),R7,parser-placeholder,inventory: parser.y,,,, +grammar,comp_unit,1,comp_unit : context_spec private_opt unit pragma_s,A_CompUnit,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,comp_unit,2,comp_unit : private_opt unit pragma_s,A_CompUnit,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,private_opt,1,private_opt : %empty,A_NilExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,private_opt,2,private_opt : PRIVATE,A_StringExp,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,context_spec,1,context_spec : with_clause use_clause_opt,A_ExpList,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,context_spec,2,context_spec : context_spec with_clause use_clause_opt,A_ExpList,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,context_spec,3,context_spec : context_spec pragma,A_ExpList,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,with_clause,1,with_clause : WITH c_name_list ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,use_clause_opt,1,use_clause_opt : %empty,A_ExpList,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,use_clause_opt,2,use_clause_opt : use_clause_opt use_clause,A_ExpList,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,unit,1,unit : pkg_decl,A_NotImplemented,Sem_program (planned),release-owned (planned),R4,parser-placeholder,inventory: parser.y,,,, +grammar,unit,2,unit : pkg_body,A_NotImplemented,Sem_program (planned),release-owned (planned),R4,parser-placeholder,inventory: parser.y,,,, +grammar,unit,3,unit : subprog_decl,A_NotImplemented,Sem_program (planned),release-owned (planned),R1,parser-placeholder,inventory: parser.y,,,, +grammar,unit,4,unit : subprog_body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,unit,5,unit : subunit,A_NotImplemented,Sem_program (planned),release-owned (planned),R4,parser-placeholder,inventory: parser.y,,,, +grammar,unit,6,unit : generic_decl,A_NotImplemented,Sem_program (planned),release-owned (planned),R4,parser-placeholder,inventory: parser.y,,,, +grammar,unit,7,unit : rename_unit,A_NotImplemented,Sem_program (planned),release-owned (planned),R1,parser-placeholder,inventory: parser.y,,,, +grammar,subunit,1,subunit : SEPARATE '(' compound_name ')' subunit_body,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,subunit_body,1,subunit_body : subprog_body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,subunit_body,2,subunit_body : pkg_body,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,subunit_body,3,subunit_body : task_body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,subunit_body,4,subunit_body : prot_body,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,body_stub,1,body_stub : TASK BODY simple_name IS SEPARATE ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,body_stub,2,body_stub : PACKAGE BODY compound_name IS SEPARATE ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,body_stub,3,body_stub : subprog_spec IS SEPARATE ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,body_stub,4,body_stub : PROTECTED BODY simple_name IS SEPARATE ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,exception_decl,1,exception_decl : def_id_s ':' EXCEPTION ';',syntax-only,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,except_handler_part,1,except_handler_part : EXCEPTION exception_handler,syntax-only,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,except_handler_part,2,except_handler_part : except_handler_part exception_handler,syntax-only,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,exception_handler,1,exception_handler : WHEN except_choice_s RIGHT_SHAFT statement_s,syntax-only,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,exception_handler,2,exception_handler : WHEN IDENTIFIER ':' except_choice_s RIGHT_SHAFT statement_s,syntax-only,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,except_choice_s,1,except_choice_s : except_choice,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,except_choice_s,2,except_choice_s : except_choice_s '|' except_choice,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,except_choice,1,except_choice : name,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,except_choice,2,except_choice : OTHERS,syntax-only,Sem_program (planned),release-owned (planned),R1,inventory-only,inventory: parser.y,,,, +grammar,raise_stmt,1,raise_stmt : RAISE name_opt ';',A_RaiseExp,Sem_program (planned),release-owned (planned),R5,inventory-only,inventory: parser.y,,,, +grammar,requeue_stmt,1,requeue_stmt : REQUEUE name ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,requeue_stmt,2,requeue_stmt : REQUEUE name WITH ABORT ';',syntax-only,Sem_program (planned),release-owned (planned),R6,inventory-only,inventory: parser.y,,,, +grammar,generic_decl,1,generic_decl : generic_formal_part subprog_spec ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_decl,2,generic_decl : generic_formal_part pkg_spec ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_formal_part,1,generic_formal_part : GENERIC,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_formal_part,2,generic_formal_part : generic_formal_part generic_formal,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_formal,1,generic_formal : param ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_formal,2,generic_formal : TYPE simple_name generic_discrim_part_opt IS generic_type_def ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_formal,3,generic_formal : WITH PROCEDURE simple_name formal_part_opt subp_default ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_formal,4,generic_formal : WITH FUNCTION designator formal_part_opt RETURN name subp_default ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_formal,5,generic_formal : WITH PACKAGE simple_name IS NEW name '(' BOX ')' ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_formal,6,generic_formal : WITH PACKAGE simple_name IS NEW name ';',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_formal,7,generic_formal : use_clause,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_discrim_part_opt,1,generic_discrim_part_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_discrim_part_opt,2,generic_discrim_part_opt : discrim_part,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_discrim_part_opt,3,generic_discrim_part_opt : '(' BOX ')',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,subp_default,1,subp_default : %empty,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,subp_default,2,subp_default : IS name,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,subp_default,3,subp_default : IS BOX,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_type_def,1,generic_type_def : '(' BOX ')',syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_type_def,2,generic_type_def : RANGE BOX,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_type_def,3,generic_type_def : MOD BOX,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_type_def,4,generic_type_def : DELTA BOX,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_type_def,5,generic_type_def : DELTA BOX DIGITS BOX,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_type_def,6,generic_type_def : DIGITS BOX,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_type_def,7,generic_type_def : array_type,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_type_def,8,generic_type_def : access_type,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_type_def,9,generic_type_def : private_type,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_type_def,10,generic_type_def : generic_derived_type,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_derived_type,1,generic_derived_type : NEW subtype_ind,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_derived_type,2,generic_derived_type : NEW subtype_ind WITH PRIVATE,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_derived_type,3,generic_derived_type : ABSTRACT NEW subtype_ind WITH PRIVATE,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_subp_inst,1,generic_subp_inst : subprog_spec IS generic_inst,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_pkg_inst,1,generic_pkg_inst : PACKAGE compound_name IS generic_inst,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,generic_inst,1,generic_inst : NEW name,syntax-only,Sem_program (planned),release-owned (planned),R4,inventory-only,inventory: parser.y,,,, +grammar,rep_spec,1,rep_spec : attrib_def,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,rep_spec,2,rep_spec : record_type_spec,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,rep_spec,3,rep_spec : address_spec,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,attrib_def,1,attrib_def : FOR mark USE expression ';',syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,record_type_spec,1,record_type_spec : FOR mark USE RECORD align_opt comp_loc_s END RECORD ';',syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,align_opt,1,align_opt : %empty,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,align_opt,2,align_opt : AT MOD expression ';',syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,comp_loc_s,1,comp_loc_s : %empty,syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,comp_loc_s,2,comp_loc_s : comp_loc_s mark AT expression RANGE range ';',syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,address_spec,1,address_spec : FOR mark USE AT expression ';',syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +grammar,code_stmt,1,code_stmt : qualified ';',syntax-only,Sem_program (planned),release-owned (planned),R7,inventory-only,inventory: parser.y,,,, +corpus,,,,,,,R2,planned,tests/subr.adb,tests/subr.adb,executable,execute,"derived types, range subtype, conversions, First/Last" +corpus,,,,,,,R2,planned,tests/numbers.adb,tests/numbers.adb,executable,execute,Float; based integer and real literals; Integer(F) +corpus,,,,,,,R3,planned,tests/calc.adb,tests/calc.adb,executable,execute,String/Character concatenation +corpus,,,,,,,R3; re-verify R5,planned,tests/gnatioex.adb,tests/gnatioex.adb,executable,execute,"String, Get_Line, slice, concatenation; full I/O re-verification" +corpus,,,,,,,R4,planned,tests/i_stack.ads,tests/i_stack.ads,interface artifact only,interface-artifact,package private-part completion +corpus,,,,,,,R4,planned,tests/hello.adb,tests/hello.adb,expected-diagnostic,diagnostic,missing with Ada.Numerics; never an execution fixture diff --git a/docs/mips-target.md b/docs/mips-target.md new file mode 100644 index 0000000..44c3e58 --- /dev/null +++ b/docs/mips-target.md @@ -0,0 +1,129 @@ +# Linux/MIPS target contract + +R0 targets one executable platform only: static, non-PIE **ELF32** for +`mipsel-linux-gnu`, run directly with `qemu-mipsel`. + +## Fixed target and artifact requirements + +| Property | Required value | +| --- | --- | +| ISA | MIPS32 Release 2 | +| Endianness | little-endian | +| ABI | System V MIPS o32 | +| Floating point | hard-float, FP32 registers, legacy NaN encoding | +| ELF type | `ET_EXEC` | +| Entry point | `_start` | +| MIPS `e_flags` | exactly `0x70001001` | +| Linking | static, direct `mipsel-linux-gnu-ld` link, no PIE | +| Runtime libraries | compiler-owned freestanding objects only; no CRT, libc, or libgcc | +| Emulator invocation | `qemu-mipsel PROGRAM`, without `-L` or a target sysroot | + +The legacy-NaN requirement is observable in `e_flags`: the required +`0x...1001` differs from `0x...1401` produced for `-mnan=2008`. It cannot be +proved by `readelf -A` alone. + +The assembler command is: + +```sh +mipsel-linux-gnu-as -EL -32 -mips32r2 -mhard-float -mfp32 -mnan=legacy \ + -o file.o file.S +``` + +Cross-GCC objects used by ABI fixtures use the exact driver +`mipsel-linux-gnu-gcc-13`, never an unversioned cross compiler: + +```sh +mipsel-linux-gnu-gcc-13 -march=mips32r2 -mabi=32 -EL -mhard-float -mfp32 \ + -mnan=legacy -fno-pic -mno-abicalls -G0 -ffreestanding \ + -fno-stack-protector -fno-builtin -Wall -Wextra -Werror -c file.c +``` + +All assembly and cross-GCC objects participating in an ABI probe must have +header flags exactly `0x70001001`; otherwise the probe is invalid. + +Link explicitly, in a known object order: + +```sh +mipsel-linux-gnu-ld -m elf32ltsmip -EL -static \ + -T runtime/mipsel-linux.ld -e _start --orphan-handling=error \ + -o program start.o runtime.o main.o +``` + +`runtime/mipsel-linux.ld` leaves `PT_LOAD` creation to GNU `ld`: `.text`, +read-only data, and required MIPS ABI metadata map into an `R E` load; when +allocated writable data exists, `.data`/`.bss` map into a distinct `RW` load. +A text-only executable has no writable `PT_LOAD` at all. The script must not +declare an empty data program header: that creates a zero-sized `vaddr=0` RW +load that plain `qemu-mipsel` rejects. + +No `PT_LOAD` may have both `W` and `E`. Every allocated writable section, if +any, must map to a non-executable `RW` load. The link command passes +`--orphan-handling=error`; R0 explicitly places `.text`/`.rodata`/`.rdata`, +`.data`/`.sdata`/`.lit4`/`.lit8`, `.bss`/`.sbss`, MIPS `.reginfo` and +`.MIPS.abiflags`, and known non-allocated metadata. New sections require an +explicit linker-script permission and placement decision rather than becoming +an orphan. Final artifacts have no `PT_INTERP`, `DT_NEEDED`, dynamic section, +or undefined symbols. + +## o32 call ABI + +- `$a0` through `$a3` carry the first four integer/pointer argument words. + Every caller reserves the mandatory 16-byte argument home area. +- Further argument words begin at `16($sp)`, then `20($sp)`, and follow the + psABI alignment and padding rules. +- `$sp` is 8-byte aligned at every call site. +- A 64-bit scalar is 8-byte aligned and can skip a register: `(int, long + long)` uses `$a0`, then `$a2`/`$a3`. +- Hard-float uses `$f12` and `$f14` only for the first two parameters and only + while all preceding parameters are floating-point. A float after an integer + instead uses its GPR/stack word location. +- Integer, pointer, enumeration, and Boolean results use `$v0`/`$v1`. Float + uses `$f0`; double uses `$f0`/`$f1`. +- `$s0`–`$s7`, `$fp`/`$s8`, a stored `$ra`, and `$f20`–`$f31` are callee-saved. + `$t*`, `$a*`, `$v*`, `$at`, `$f0`–`$f19`, HI, and LO are volatile. +- `$gp` is unused: all target C compilation uses `-fno-pic -mno-abicalls -G0`. + Generated objects must not contain `$gp`-relative relocations. + +The direct R0 ABI test compiles `tests/abi/six_args_callee.c` with +`mipsel-linux-gnu-gcc-13` and calls it from +`tests/abi/six_args_caller.S`. The caller proves the fifth and sixth words +are at `16($sp)` and `20($sp)` by passing `11, 12, 13, 14, 15, 16`; the callee +returns 81 and the fixture converts that to process status 0. + +## Linux o32 syscall boundary + +The syscall convention is not the call ABI. `runtime/linux_o32.S` is the only +place raw Linux syscalls are emitted. + +- `$v0` contains the syscall number. +- Arguments 1–4 use `$a0`–`$a3`; arguments 5–7 use `16($sp)`, `20($sp)`, and + `24($sp)`. +- On return, `$a3 != 0` signals failure and `$v0` holds a positive errno. + `$a3` is also argument 4, so wrappers read it only after `syscall`. +- o32's base is 4000. The R0 checked constants are `exit=4001`, `read=4003`, + and `write=4004`, checked against target `asm/unistd_o32.h` by the test + runner when the target Linux headers are installed. +- Runtime read/write wrappers normalize a failure to `-errno`; `exit` does not + return. + +`runtime/start.S` decodes `argc`, `argv`, and `envp` from the initial Linux +stack, calls elaboration, invokes the R0 no-argument main, finalizes, and +exits through `linux_o32_exit`. + +## Direct contract test + +Run independently of the project Makefile: + +```sh +python3 tests/run_tests.py +``` + +It validates the pinned `ci/toolchain.lock`, assembles text-only and +writable-data hand-written smoke programs, statically links them with the +runtime, asserts exact ELF header/attribute/segment/dynamic-symbol policy, and +runs both under plain `qemu-mipsel`. The text-only fixture proves that no +empty RW `PT_LOAD` is emitted; the writable fixture proves allocated writable +sections map to a non-executable `RW` load. When the exact cross-GCC driver +is available, it also performs the six-argument ABI probe. Use `--skip-abi` +only when the probe is intentionally unavailable; normal CI must run both +checks. diff --git a/docs/supported-subset.md b/docs/supported-subset.md new file mode 100644 index 0000000..d103341 --- /dev/null +++ b/docs/supported-subset.md @@ -0,0 +1,98 @@ +# Supported subset and grammar inventory + +## Current release state: R0 foundation + +The checked-out `vorflux/restore-compiler-r0` branch is at the R0 restoration +foundation. The manifest records *ownership*, not a claim that a production is +implemented. Grammar rows currently have one of these states: + +- `inventory-only`: extracted syntax with its planned release owner; +- `parser-placeholder`: an action still contains `A_NotImplemented` and must be + removed by the owning release. + +No tracked historical corpus source closes at R0. R0 acceptance uses dedicated +empty/null-main fixtures. Future-release constructs must eventually produce an +explicit release-owned diagnostic rather than be silently accepted. + +## Reproducible grammar inventory + +`tools/inventory_grammar.py` reads `parser.y` directly, invokes Bison only to +measure conflicts, and writes `docs/grammar-coverage.csv`. Do not hand-edit the +CSV; regenerate it after an intentional grammar change: + +```sh +python3 tools/inventory_grammar.py --check-baseline --write-manifest +python3 tools/check_coverage.py +``` + +The checked-out parser's source baseline is: + +| Metric | Baseline | +| --- | ---: | +| Source nonterminals | 233 | +| Source alternatives | 513 | +| Shift/reduce conflicts | 0 | +| Reduce/reduce conflicts | 0 | +| Empty source alternatives | 44 | +| `A_NotImplemented` actions | 23 | + +The source-level values intentionally count what is actually in this checkout. +The 513-alternative baseline is deterministic: the extractor finds 513 +source-level RHS alternatives in `parser.y`, and an independent GNU Bison 3.8.2 +`--report=all` run reports exactly 513 numbered grammar rules after excluding +Bison's rule 0 (`$accept`). It also reports 44 empty alternatives. The parser +contains no generated `$@` mid-rule rules in this branch, so no adjustment is +needed between the two measurements. + +The approved plan's 512/39 figures therefore do not describe the checked-out +`parser.y`: the current grammar deterministically contains 513 source +alternatives and 44 empty alternatives. The inventory deliberately baselines +the reproducible source truth rather than silently dropping an alternative to +fit stale plan figures. + +The inventory invokes Bison directly on `parser.y` in a temporary output +directory. Bison failures remain hard inventory failures; the inventory does +not patch or otherwise alter the grammar it measures. + +`--check-baseline` exits nonzero for any count drift. The coverage validator +also requires every extracted production to appear once and only once, and each +tracked `tests/*.adb` or `tests/*.ads` source to have exactly one authoritative +corpus row. + +## Release ownership and inventory scope + +Each production row has an explicit direct feature owner. The manifest generator +then closes an alternative no earlier than every nonterminal it references. This +makes wrapper alternatives honest: for example, `decl : pkg_decl` closes at R4, +`decl : exception_decl` at R5, and `decl : task_decl` at R6. This propagation is +validated while generating the manifest and again while checking it. + +Token spelling is not used as a release heuristic. In particular, +`multiplying : MOD` remains an R1 arithmetic operator; the distinct +`integer_type : MOD expression` is R2 modular-type syntax. + +The authoritative historical corpus is deliberately limited to top-level +tracked `tests/*.adb` and `tests/*.ads` paths. Release fixtures below +`tests/fixtures/` are not historical corpus rows and cannot affect this report. + +## Backend status + +`assem.c` is outside this inventory workstream and remains the historical, +unrestored backend. It is not represented as R0 support and is not modified by +these tools; its planned complete replacement is the R0 backend task described +in the approved restoration plan. + +## Historical corpus ownership + +| Source | Classification | Closing release | Expected outcome | +| --- | --- | --- | --- | +| `tests/subr.adb` | executable | R2 | execute | +| `tests/numbers.adb` | executable | R2 | execute | +| `tests/calc.adb` | executable | R3 | execute | +| `tests/gnatioex.adb` | executable | R3; re-verify R5 | execute | +| `tests/i_stack.ads` | interface artifact only | R4 | deterministic interface artifact | +| `tests/hello.adb` | expected-diagnostic | R4 | stable missing-`with`/undefined-name diagnostic, nonzero exit | + +`hello.adb` is not an executable fixture: it references `Ada.Numerics.Pi` with +only `with Text_IO;`. `gnatioex.adb` closes for its string/slice behavior at R3 +and is re-verified for complete I/O behavior at R5. diff --git a/driver.c b/driver.c new file mode 100644 index 0000000..034b7c9 --- /dev/null +++ b/driver.c @@ -0,0 +1,91 @@ +#include +#include + +#include "compile.h" + +static void usage(FILE *stream) +{ + fputs("usage: adac [options] SOURCE\n" + "\n" + "options:\n" + " -o PATH requested output path (reserved for later releases)\n" + " --unit-dir DIR requested unit directory (reserved for later releases)\n" + " --emit-ast print the parsed AST\n" + " --emit-sem print R0 semantic dump status\n" + " --emit-ir print R0 IR dump status\n" + " --emit-asm print R0 assembly dump status\n" + " -h, --help show this help\n", + stream); +} + +static int parse_phase(const char *argument, Comp_phase *phase) +{ + if (strcmp(argument, "check") == 0) { + *phase = COMP_PHASE_CHECK; + return 1; + } + if (strcmp(argument, "compile") == 0) { + *phase = COMP_PHASE_COMPILE; + return 1; + } + if (strcmp(argument, "build") == 0) { + *phase = COMP_PHASE_BUILD; + return 1; + } + return 0; +} + +int main(int argc, char **argv) +{ + Comp_options options = {0}; + int index; + + if (argc == 2 && (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0)) { + usage(stdout); + return COMP_RESULT_OK; + } + if (argc < 3 || !parse_phase(argv[1], &options.phase)) { + usage(stderr); + return COMP_RESULT_USAGE; + } + + for (index = 2; index < argc; ++index) { + const char *argument = argv[index]; + + if (strcmp(argument, "--emit-ast") == 0) { + options.emit_ast = true; + } else if (strcmp(argument, "--emit-sem") == 0) { + options.emit_sem = true; + } else if (strcmp(argument, "--emit-ir") == 0) { + options.emit_ir = true; + } else if (strcmp(argument, "--emit-asm") == 0) { + options.emit_asm = true; + } else if (strcmp(argument, "-o") == 0) { + if (++index == argc || options.output_path != NULL) { + usage(stderr); + return COMP_RESULT_USAGE; + } + options.output_path = argv[index]; + } else if (strcmp(argument, "--unit-dir") == 0) { + if (++index == argc || options.unit_dir != NULL) { + usage(stderr); + return COMP_RESULT_USAGE; + } + options.unit_dir = argv[index]; + } else if (argument[0] == '-') { + fprintf(stderr, "adac: unknown option: %s\n", argument); + return COMP_RESULT_USAGE; + } else if (options.input_path == NULL) { + options.input_path = argument; + } else { + fputs("adac: exactly one source path is required\n", stderr); + return COMP_RESULT_USAGE; + } + } + + if (options.input_path == NULL) { + usage(stderr); + return COMP_RESULT_USAGE; + } + return Comp_run(&options, stderr); +} diff --git a/errormsg.c b/errormsg.c index a9e0dbc..271f80f 100644 --- a/errormsg.c +++ b/errormsg.c @@ -1,65 +1,46 @@ -/* - * errormsg.c - functions used in all phases of the compiler to give - * error messages about the program. - * - */ +/* Source-positioned diagnostics for the host frontend. */ +#include #include #include -#include -#include "util.h" -#include "errormsg.h" - - -bool anyErrors= FALSE; - -static string fileName = ""; - -static int lineNum = 1; - -int EM_tokPos=0; - -extern FILE *yyin; -typedef struct intList {int i; struct intList *rest;} *IntList; +#include "errormsg.h" -static IntList intList(int i, IntList rest) -{IntList l= checked_malloc(sizeof *l); - l->i=i; l->rest=rest; - return l; -} +bool EM_anyErrors = false; +int EM_tokPos = 0; -static IntList linePos=NULL; +static const char *file_name = ""; +static int line_number = 1; +static int line_start = 0; void EM_newline(void) -{lineNum++; - linePos = intList(EM_tokPos, linePos); +{ + ++line_number; + /* EM_tokPos is the newline byte's zero-based position. */ + line_start = EM_tokPos + 1; } -void EM_error(int pos, char *message,...) -{va_list ap; - IntList lines = linePos; - int num=lineNum; - - - anyErrors=TRUE; - while (lines && lines->i >= pos) - {lines=lines->rest; num--;} - - if (fileName) fprintf(stderr,"%s:",fileName); - if (lines) fprintf(stderr,"%d.%d: ", num, pos-lines->i); - va_start(ap,message); - vfprintf(stderr, message, ap); - va_end(ap); - fprintf(stderr,"\n"); - +void EM_error(int position, const char *format, ...) +{ + va_list arguments; + int column = position - line_start + 1; + + if (column < 1) { + column = 1; + } + EM_anyErrors = true; + fprintf(stderr, "%s:%d:%d: error: ", file_name, line_number, column); + va_start(arguments, format); + vfprintf(stderr, format, arguments); + va_end(arguments); + fputc('\n', stderr); } -void EM_reset(string fname) +void EM_reset(const char *filename) { - anyErrors=FALSE; fileName=fname; lineNum=1; - linePos=intList(0,NULL); - yyin = fopen(fname,"r"); - if (!yyin) {EM_error(0,"cannot open"); exit(1);} + EM_anyErrors = false; + EM_tokPos = 0; + line_number = 1; + line_start = 0; + file_name = filename != NULL ? filename : ""; } - diff --git a/errormsg.h b/errormsg.h index 864b95d..f71c5e3 100644 --- a/errormsg.h +++ b/errormsg.h @@ -1,9 +1,15 @@ -extern bool EM_anyErrors; +#ifndef ADA_ERRORMSG_H +#define ADA_ERRORMSG_H -void EM_newline(void); +#include + +#include "util.h" +extern bool EM_anyErrors; extern int EM_tokPos; -void EM_error(int, string,...); -void EM_impossible(string,...); -void EM_reset(string filename); +void EM_newline(void); +void EM_error(int position, const char *format, ...); +void EM_reset(const char *filename); + +#endif diff --git a/lexer.l b/lexer.l index 2ddfa8e..aa1e836 100644 --- a/lexer.l +++ b/lexer.l @@ -5,13 +5,13 @@ #include "symbol.h" #include "absyn.h" #include "errormsg.h" -#include "y.tab.h" +#include "parser.h" -int charPos=1; +int charPos = 0; int yywrap(void) { - charPos=1; + charPos = 0; return 1; } @@ -25,7 +25,7 @@ void adjust(void) LETTER [A-Za-z] DIGIT [0-9] -EXTENDED_DIGIT [0-9A-F] +EXTENDED_DIGIT [0-9A-Fa-f] IDENTIFIER {LETTER}(_?({LETTER}|{DIGIT}))* @@ -88,7 +88,7 @@ COMMENT --[^\n]* (?i:OUT) { adjust(); return(OUT);} (?i:PACKAGE) { adjust(); return(PACKAGE);} (?i:PRAGMA) { adjust(); return(PRAGMA);} -(?i:PRIVATE) { adjust(); return(PRIVATE);} +(?i:PRIVATE) { adjust(); yylval.sval = String(yytext); return(PRIVATE);} (?i:PROCEDURE) { adjust(); return(PROCEDURE);} (?i:PROTECTED) { adjust(); return(PROTECTED);} (?i:RAISE) { adjust(); return(RAISE);} @@ -98,7 +98,7 @@ COMMENT --[^\n]* (?i:RENAMES) { adjust(); return(RENAMES);} (?i:REQUEUE) { adjust(); return(REQUEUE);} (?i:RETURN) { adjust(); return(RETURN);} -(?i:REVERSE) { adjust(); return(REVERSE);} +(?i:REVERSE) { adjust(); yylval.sval = String(yytext); return(REVERSE);} (?i:SELECT) { adjust(); return(SELECT);} (?i:SEPARATE) { adjust(); return(SEPARATE);} (?i:SUBTYPE) { adjust(); return(SUBTYPE);} @@ -106,7 +106,7 @@ COMMENT --[^\n]* (?i:TASK) { adjust(); return(TASK);} (?i:TERMINATE) { adjust(); return(TERMINATE);} (?i:THEN) { adjust(); return(THEN);} -(?i:TYPE) { adjust(); return(TYPE);} +(?i:TYPE) { adjust(); yylval.sval = String(yytext); return(TYPE);} (?i:UNTIL) { adjust(); return(UNTIL);} (?i:USE) { adjust(); return(USE);} (?i:WHEN) { adjust(); return(WHEN);} @@ -139,12 +139,17 @@ COMMENT --[^\n]* "<<" { adjust(); return(LT_LT);} ">>" { adjust(); return(GT_GT);} "<>" { adjust(); return(BOX);} -{IDENTIFIER} { adjust(); yylval.sval = toStrUpper(yytext); return(IDENTIFIER);} -{NUMBER} { adjust(); yylval.sval = toStrUpper(yytext); return(NUMBER);} -{CHARACTER} { adjust(); yylval.sval = toStrUpper(yytext); return(CHARACTER);} -{STRING} { adjust(); yylval.sval = toStrUpper(yytext); return(STRING);} +{IDENTIFIER} { adjust(); yylval.sval = String(yytext); return(IDENTIFIER);} +{NUMBER} { adjust(); yylval.sval = String(yytext); return(NUMBER);} +{CHARACTER} { adjust(); yylval.sval = String(yytext); return(CHARACTER);} +{STRING} { adjust(); yylval.sval = String(yytext); return(STRING);} {COMMENT} { adjust(); continue;} [ \t] { adjust(); continue;} -[\n] { EM_newline(); continue;} +[\n] { adjust(); EM_newline(); continue;} . { adjust(); EM_error(EM_tokPos,"Illegal token");} %% + +void lexer_reset(void) +{ + charPos = 0; +} diff --git a/parser.y b/parser.y index b4ab7ca..5620e34 100644 --- a/parser.y +++ b/parser.y @@ -3,25 +3,19 @@ #include #include "util.h" #include "errormsg.h" -#include "table.h" -#include "symbol.h" #include "absyn.h" -#include "prabsyn.h" int yylex(void); /* function prototype */ -A_exp absyn_root; - -int yydebug = 0; - -S_table table; - -void yyerror(char *s) +void yyerror(A_exp *root, const char *s) { + (void)root; EM_error(EM_tokPos, "%s", s); } %} +%parse-param { A_exp *root } + %union { int pos; int ival; @@ -45,7 +39,7 @@ void yyerror(char *s) literal name allocator qualified parenthesized_primary statement simple_stmt compound_stmt unlabeled null_stmt condition range range_constraint simple_name pragma assign_stmt exit_stmt - return_stmt goto_stmt raise_stmt + return_stmt goto_stmt raise_stmt object_decl number_decl type_decl code_stmt if_stmt case_stmt loop_stmt block pragma_arg comp_unit compound_name unit subprog_body case_hdr cond_part cond_clause subtype_ind when_opt @@ -56,6 +50,7 @@ void yyerror(char *s) indexed_comp value comp_assoc private_opt use_clause subprog_spec param decimal_digits_constraint object_subtype_def constraint init_opt unconstr_array_type constr_array_type array_type range_constr_opt + subprog_spec_is_push discrim_spec type_completion type_def enumeration_type integer_type float_type real_type fixed_type record_def def_id %type logical short_circuit relational adding multiplying membership @@ -66,9 +61,9 @@ void yyerror(char *s) body_stub *******************************************************************************/ %type object_qualifier_opt -%token LT_EQ EXPON NE GE AND OR XOR MOD REM TICK DOT_DOT -%token NOT ABS -%token IDENTIFIER CHARACTER STRING NuLL REVERSE PRIVATE TYPE NUMBER +%token IDENTIFIER CHARACTER STRING REVERSE PRIVATE TYPE NUMBER +%token LT_EQ EXPON NE GE AND OR XOR MOD REM TICK DOT_DOT +%token NOT ABS NuLL %token LT_LT %token BOX @@ -140,7 +135,7 @@ void yyerror(char *s) %% goal_symbol : compilation - {absyn_root = A_SeqExp(EM_tokPos,$1);} + {*root = A_SeqExp(EM_tokPos,$1);} ; pragma : PRAGMA IDENTIFIER ';' @@ -184,21 +179,7 @@ decl : object_decl ; object_decl : def_id_s ':' object_qualifier_opt object_subtype_def init_opt ';' - { - A_expList e = $1; - while(e!=NULL) - { - if(S_look(table,S_Symbol(e->head->u.stringg))!=NULL) - { - EM_error(EM_tokPos,"Re-declaration of %s",e->head->u.stringg); - } - else - { - S_enter(table,S_Symbol(e->head->u.stringg),A_ObjectTy(EM_tokPos,$3,$4,$5)); - } - e = e->tail; - } - } + { $$ = $4; } ; def_id_s : def_id @@ -208,7 +189,7 @@ def_id_s : def_id ; def_id : IDENTIFIER - {$$ = A_StringExp(EM_tokPos,table,$1);} + {$$ = A_StringExp(EM_tokPos,$1);} ; object_qualifier_opt : @@ -234,34 +215,11 @@ init_opt : ; number_decl : def_id_s ':' CONSTANT IS_ASSIGNED expression ';' - { - A_expList e = $1; - while(e!=NULL) - { - if(S_look(table,S_Symbol(e->head->u.stringg))!=NULL) - { - EM_error(EM_tokPos,"Re-declaration of %s",e->head->u.stringg); - } - else - { - S_enter(table,S_Symbol(e->head->u.stringg),A_NumTy(EM_tokPos,$5)); - } - e = e->tail; - } - } + { $$ = $5; } ; type_decl : TYPE IDENTIFIER discrim_part_opt type_completion ';' - { - if(S_look(table,S_Symbol($2))!=NULL) - { - EM_error(EM_tokPos,"Re-declaration of %s",$2); - } - else - { - S_enter(table,S_Symbol($2),A_TypeDecTy(EM_tokPos,$3,$4)); - } - } + { $$ = $4; } ; discrim_part_opt : @@ -269,7 +227,7 @@ discrim_part_opt : | discrim_part {$$ = $1;} | '(' BOX ')' - {$$ = A_ExpList(A_StringExp(EM_tokPos,table,"BOX"),NULL);} + {$$ = A_ExpList(A_StringExp(EM_tokPos,"BOX"),NULL);} ; type_completion : @@ -344,9 +302,9 @@ enum_id_s : enum_id ; enum_id : IDENTIFIER - {$$ = A_StringExp(EM_tokPos,table,$1);} + {$$ = A_StringExp(EM_tokPos,$1);} | CHARACTER - {$$ = A_StringExp(EM_tokPos,table,$1);} + {$$ = A_StringExp(EM_tokPos,$1);} ; integer_type : range_spec @@ -508,7 +466,7 @@ choice : expression | discrete_with_range {$$ = $1;} | OTHERS - {$$ = A_StringExp(EM_tokPos,table,"OTHERS");} + {$$ = A_StringExp(EM_tokPos,"OTHERS");} ; discrete_with_range : name range_constraint @@ -578,7 +536,7 @@ mark : simple_name ; simple_name : IDENTIFIER - {$$ = A_StringExp(EM_tokPos,table,$1);} + {$$ = A_StringExp(EM_tokPos,$1);} ; compound_name : simple_name @@ -594,11 +552,11 @@ c_name_list : compound_name ; used_char : CHARACTER - { $$ = A_StringExp(EM_tokPos,table,$1);} + { $$ = A_StringExp(EM_tokPos,$1);} ; operator_symbol : STRING - { $$ = A_StringExp(EM_tokPos,table,$1);} + { $$ = A_StringExp(EM_tokPos,$1);} ; indexed_comp : name '(' value_s ')' @@ -628,7 +586,7 @@ selected_comp : name '.' simple_name | name '.' operator_symbol {$$ = A_OpExp(EM_tokPos,A_dotOp,$1,$3);} | name '.' ALL - {$$ = A_OpExp(EM_tokPos,A_dotOp,$1,A_StringExp(EM_tokPos,table,"ALL"));} + {$$ = A_OpExp(EM_tokPos,A_dotOp,$1,A_StringExp(EM_tokPos,"ALL"));} ; attribute : name TICK attribute_id @@ -680,9 +638,9 @@ logical : AND ; short_circuit : AND THEN - {$$ = $1;} + {$$ = A_andOp;} | OR ELSE - {$$ = $1;} + {$$ = A_orOp;} ; relation : simple_expression @@ -915,7 +873,7 @@ loop_stmt : label_opt iteration basic_loop id_opt ';' label_opt : {$$ = A_NilExp(EM_tokPos);} | IDENTIFIER ':' - {$$ = A_StringExp(EM_tokPos,table,$1);} + {$$ = A_StringExp(EM_tokPos,$1);} ; iteration : @@ -927,13 +885,13 @@ iteration : ; iter_part : FOR IDENTIFIER IN - {$$ = A_StringExp(EM_tokPos,table,$2);} + {$$ = A_StringExp(EM_tokPos,$2);} ; reverse_opt : {$$ = A_NilExp(EM_tokPos);} | REVERSE - {$$ = A_StringExp(EM_tokPos,table,$1);} + {$$ = A_StringExp(EM_tokPos,$1);} ; basic_loop : LOOP statement_s END LOOP @@ -946,20 +904,8 @@ id_opt : {$$ = $1;} ; -block : label_opt - {S_beginScope(table);S_enter(table,S_Symbol($1->u.stringg),$1);} - block_decl - block_body END - id_opt - { - if($1->kind == A_stringExp) - { - if(S_look(table,S_Symbol($6->u.stringg)) == NULL) - EM_error(EM_tokPos,"Wrong block id"); - } - } - ';' - {S_endScope(table);} +block : label_opt block_decl block_body END id_opt ';' + { $$ = A_SeqExp(EM_tokPos, $3); } ; block_decl : @@ -1020,7 +966,7 @@ subprog_spec : PROCEDURE compound_name formal_part_opt designator : compound_name {$$ = $1;} | STRING - {$$ = A_StringExp(EM_tokPos,table,$1);} + {$$ = A_StringExp(EM_tokPos,$1);} ; formal_part_opt : @@ -1053,10 +999,11 @@ mode : ; subprog_spec_is_push : subprog_spec IS + { $$ = $1; } ; subprog_body : subprog_spec_is_push decl_part block_body END id_opt ';' - {$$ = A_SeqExp(EM_tokPos,$3);} + { $$ = A_SeqExp(EM_tokPos,$3); } ; procedure_call : name ';' @@ -1097,7 +1044,7 @@ limited_opt : use_clause : USE name_s ';' {$$ = A_Useclause(EM_tokPos,A_NilExp(EM_tokPos),$2);} | USE TYPE name_s ';' - {$$ = A_Useclause(EM_tokPos,A_StringExp(EM_tokPos,table,$2),$3);} + {$$ = A_Useclause(EM_tokPos,A_StringExp(EM_tokPos,$2),$3);} ; name_s : name @@ -1286,7 +1233,7 @@ comp_unit : context_spec private_opt unit pragma_s private_opt : {$$ = A_NilExp(EM_tokPos);} | PRIVATE - {$$ = A_StringExp(EM_tokPos,table,$1);} + {$$ = A_StringExp(EM_tokPos,$1);} ; context_spec : with_clause use_clause_opt @@ -1446,11 +1393,3 @@ code_stmt : qualified ';' ; %% - -main() { - table = S_empty(); - yyparse(); - Ty_typeCheckExp(table,absyn_root); - //pr_exp(stdout,absyn_root,1); - return 0; -} diff --git a/runtime/linux_o32.S b/runtime/linux_o32.S new file mode 100644 index 0000000..5969d41 --- /dev/null +++ b/runtime/linux_o32.S @@ -0,0 +1,47 @@ +/* Linux/MIPS o32 syscall boundary. Do not open-code syscalls elsewhere. */ + + .set noreorder + .text + + .globl linux_o32_read + .ent linux_o32_read +linux_o32_read: + li $v0, 4003 + syscall + bne $a3, $zero, 1f + nop + jr $ra + nop +1: + subu $v0, $zero, $v0 + jr $ra + nop + .end linux_o32_read + + .globl linux_o32_write + .ent linux_o32_write +linux_o32_write: + li $v0, 4004 + syscall + bne $a3, $zero, 1f + nop + jr $ra + nop +1: + subu $v0, $zero, $v0 + jr $ra + nop + .end linux_o32_write + + .globl linux_o32_exit + .ent linux_o32_exit +linux_o32_exit: + li $v0, 4001 + syscall + /* exit only returns when Linux reports an error; do not fall through. */ +1: + b 1b + nop + .end linux_o32_exit + + .set reorder diff --git a/runtime/linux_o32.h b/runtime/linux_o32.h new file mode 100644 index 0000000..49a7777 --- /dev/null +++ b/runtime/linux_o32.h @@ -0,0 +1,24 @@ +#ifndef ADA_RUNTIME_LINUX_O32_H +#define ADA_RUNTIME_LINUX_O32_H + +/* + * Linux MIPS o32 syscall numbers generated from asm/unistd.h. The o32 ABI + * selects the 4000 base; the checked-in values are verified by + * tests/run_tests.py against linux-libc-dev-mipsel-cross when it is present. + */ +#define ADA_LINUX_O32_SYSCALL_BASE 4000 +#define ADA_LINUX_O32_SYS_EXIT (ADA_LINUX_O32_SYSCALL_BASE + 1) +#define ADA_LINUX_O32_SYS_READ (ADA_LINUX_O32_SYSCALL_BASE + 3) +#define ADA_LINUX_O32_SYS_WRITE (ADA_LINUX_O32_SYSCALL_BASE + 4) + +/* + * Wrappers return a non-negative result on success and -errno on failure. + * linux_o32_exit does not return. These declarations deliberately use only + * C primitive types so freestanding runtime sources need no target libc + * headers. + */ +long linux_o32_read(int fd, void *buffer, unsigned long count); +long linux_o32_write(int fd, const void *buffer, unsigned long count); +void linux_o32_exit(int status) __attribute__((noreturn)); + +#endif diff --git a/runtime/mipsel-linux.ld b/runtime/mipsel-linux.ld new file mode 100644 index 0000000..8e4480d --- /dev/null +++ b/runtime/mipsel-linux.ld @@ -0,0 +1,72 @@ +/* Static, non-PIE Linux/MIPS o32 layout. */ +OUTPUT_FORMAT("elf32-tradlittlemips") +OUTPUT_ARCH(mips) +ENTRY(_start) + +/* + * Do not declare PHDRS here. GNU ld then omits the RW PT_LOAD entirely when + * there are no writable allocated output sections. An explicit empty data + * PHDR produces a zero-sized vaddr=0 RW load that qemu-mipsel rejects. + * + * The locked link command uses --orphan-handling=error. Every R0 allocated section + * is therefore listed below; a new section requires an explicit placement and + * permission decision instead of silently changing the image layout. + */ +SECTIONS +{ + . = 0x00400000; + + .text ALIGN(16) : + { + KEEP(*(.text._start)) + *(.init .init.*) + *(.text .text.*) + *(.fini .fini.*) + } + + .rodata ALIGN(16) : + { + *(.rodata .rodata.*) + *(.rdata .rdata.*) + *(.eh_frame .eh_frame.*) + *(.gcc_except_table .gcc_except_table.*) + } + + /* Required MIPS metadata sections remain mapped with read-only text. */ + .reginfo ALIGN(4) : { *(.reginfo) } + .MIPS.abiflags ALIGN(8) : { *(.MIPS.abiflags) } + + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .data ALIGN(16) : + { + *(.data .data.*) + *(.sdata .sdata.*) + *(.lit4) + *(.lit8) + *(.data.rel.ro .data.rel.ro.*) + } + + .bss ALIGN(16) (NOLOAD) : + { + __bss_start = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + *(COMMON) + __bss_end = .; + } + + __heap_start = ALIGN(16); + _end = .; + + /* Non-allocated metadata is retained or discarded explicitly. */ + .pdr 0 : { *(.pdr) } + .mdebug.abi32 0 : { *(.mdebug.abi32) } + .gnu.attributes 0 : { *(.gnu.attributes) } + /DISCARD/ : + { + *(.comment) + *(.note .note.*) + *(.note.GNU-stack) + } +} diff --git a/runtime/start.S b/runtime/start.S new file mode 100644 index 0000000..0cf5c7e --- /dev/null +++ b/runtime/start.S @@ -0,0 +1,40 @@ +/* Freestanding R0 process entry for static Linux/MIPS o32 executables. */ + + .set noreorder + .section .text._start, "ax", @progbits + .globl _start + .ent _start +_start: + /* Linux supplies argc, argv[], then envp[] on the initial process stack. */ + lw $a0, 0($sp) + addiu $a1, $sp, 4 + sll $t0, $a0, 2 + addu $a2, $a1, $t0 + addiu $a2, $a2, 4 + + /* Reserve the o32 16-byte argument home area and preserve process data. */ + addiu $sp, $sp, -32 + sw $a0, 16($sp) + sw $a1, 20($sp) + sw $a2, 24($sp) + + /* Runtime hooks use (argc, argv, envp); R0 fixtures supply no-op hooks. */ + jal __ada_elaborate + nop + + /* R0 main is a scalar, no-argument procedure that returns its status. */ + jal ada_main + nop + sw $v0, 16($sp) + + jal __ada_finalize + nop + + lw $a0, 16($sp) + jal linux_o32_exit + nop +1: + b 1b + nop + .end _start + .set reorder diff --git a/symbol.c b/symbol.c index f74f528..ab5a34d 100644 --- a/symbol.c +++ b/symbol.c @@ -1,74 +1,100 @@ -#include +#include +#include +#include #include -#include "util.h" + #include "symbol.h" -#include "table.h" -struct S_symbol_ {string name; S_symbol next;}; +#define SYMBOL_TABLE_SIZE 109U -static S_symbol mksymbol(string name, S_symbol next) -{S_symbol s=checked_malloc(sizeof(*s)); - s->name=name; s->next=next; - return s; -} +struct S_symbol_ { + string name; + S_symbol next; +}; -#define SIZE 109 /* should be prime */ +static S_symbol symbols[SYMBOL_TABLE_SIZE]; -static S_symbol hashtable[SIZE]; +static unsigned long hash_name(const char *name) +{ + unsigned long hash = 0; + const unsigned char *character; -static unsigned int hash(char *s0) -{unsigned int h=0; char *s; - for(s=s0; *s; s++) - h = h*65599 + *s; - return h; + for (character = (const unsigned char *)name; *character != '\0'; ++character) { + hash = hash * 65599UL + *character; + } + return hash; } - -static int streq(string a, string b) + +S_symbol S_Symbol(const char *name) { - return !strcmp(a,b); -} + string canonical_name; + size_t index; + S_symbol symbol; -S_symbol S_Symbol(string name) -{int index= hash(name) % SIZE; - S_symbol syms = hashtable[index], sym; - for(sym=syms; sym; sym=sym->next) - if (streq(sym->name,name)) return sym; - sym = mksymbol(name,syms); - hashtable[index]=sym; - return sym; + assert(name != NULL); + canonical_name = toStrUpper(name); + index = hash_name(canonical_name) % SYMBOL_TABLE_SIZE; + for (symbol = symbols[index]; symbol != NULL; symbol = symbol->next) { + if (strcmp(symbol->name, canonical_name) == 0) { + free(canonical_name); + return symbol; + } + } + + symbol = checked_malloc(sizeof(*symbol)); + symbol->name = canonical_name; + symbol->next = symbols[index]; + symbols[index] = symbol; + return symbol; } - -string S_name(S_symbol sym) + +string S_name(S_symbol symbol) { - return sym->name; + assert(symbol != NULL); + return symbol->name; } -S_table S_empty(void) -{ - return TAB_empty(); +S_table S_empty(void) +{ + return TAB_empty(); } -void S_enter(S_table t, S_symbol sym, void *value) { - TAB_enter(t,sym,value); +void S_enter(S_table table, S_symbol symbol, void *value) +{ + TAB_enter(table, symbol, value); } -void *S_look(S_table t, S_symbol sym) { - return TAB_look(t,sym); +void *S_look(S_table table, S_symbol symbol) +{ + return TAB_look(table, symbol); } -static struct S_symbol_ marksym = {"",0}; +static struct S_symbol_ mark_symbol = {"", NULL}; -void S_beginScope(S_table t) -{ S_enter(t,&marksym,NULL); +void S_beginScope(S_table table) +{ + S_enter(table, &mark_symbol, NULL); } -void S_endScope(S_table t) -{S_symbol s; - do s=TAB_pop(t); - while (s != &marksym); +void S_endScope(S_table table) +{ + S_symbol symbol; + + do { + symbol = TAB_pop(table); + } while (symbol != &mark_symbol); } -void S_dump(S_table t, void (*show)(S_symbol sym, void *binding)) { - TAB_dump(t, (void (*)(void *, void *)) show); +static S_show dump_show; + +static void bridge_dump_show(void *key, void *value) +{ + dump_show((S_symbol)key, value); } +void S_dump(S_table table, S_show show) +{ + dump_show = show; + TAB_dump(table, bridge_dump_show); + dump_show = NULL; +} diff --git a/symbol.h b/symbol.h index c870da4..c724ea4 100644 --- a/symbol.h +++ b/symbol.h @@ -1,37 +1,22 @@ -/* - * symbol.h - Symbols and symbol-tables - * - */ +#ifndef ADA_SYMBOL_H +#define ADA_SYMBOL_H -typedef struct S_symbol_ *S_symbol; - -/* Make a unique symbol from a given string. - * Different calls to S_Symbol("foo") will yield the same S_symbol - * value, even if the "foo" strings are at different locations. */ -S_symbol S_Symbol(string); +#include "table.h" +#include "util.h" -/* Extract the underlying string from a symbol */ -string S_name(S_symbol); +typedef struct S_symbol_ *S_symbol; +typedef TAB_table S_table; +typedef void (*S_show)(S_symbol symbol, void *binding); -/* S_table is a mapping from S_symbol->any, where "any" is represented - * here by void* */ -typedef struct TAB_table_ *S_table; +/* Ada identifiers are case-insensitive; symbols use canonical uppercase names. */ +S_symbol S_Symbol(const char *name); +string S_name(S_symbol symbol); -/* Make a new table */ S_table S_empty(void); +void S_enter(S_table table, S_symbol symbol, void *value); +void *S_look(S_table table, S_symbol symbol); +void S_beginScope(S_table table); +void S_endScope(S_table table); +void S_dump(S_table table, S_show show); -/* Enter a binding "sym->value" into "t", shadowing but not deleting - * any previous binding of "sym". */ -void S_enter(S_table t, S_symbol sym, void *value); - -/* Look up the most recent binding of "sym" in "t", or return NULL - * if sym is unbound. */ -void *S_look(S_table t, S_symbol sym); - -/* Start a new "scope" in "t". Scopes are nested. */ -void S_beginScope(S_table t); - -/* Remove any bindings entered since the current scope began, - and end the current scope. */ -void S_endScope(S_table t); - +#endif diff --git a/table.c b/table.c index bb06774..9411ab4 100644 --- a/table.c +++ b/table.c @@ -1,88 +1,117 @@ -/* - * table.c - Functions to manipulate generic tables. - * Copyright (c) 1997 Andrew W. Appel. - */ +/* Generic scoped hash table. */ + +#include +#include +#include -#include -#include "util.h" #include "table.h" +#include "util.h" -#define TABSIZE 127 +#define TABSIZE 127U typedef struct binder_ *binder; -struct binder_ {void *key; void *value; binder next; void *prevtop;}; + +struct binder_ { + void *key; + void *value; + binder next; + void *previous_top; +}; + struct TAB_table_ { - binder table[TABSIZE]; - void *top; + binder buckets[TABSIZE]; + void *top; }; +static size_t table_index(const void *key) +{ + return (size_t)((uintptr_t)key % TABSIZE); +} + +static binder Binder(void *key, void *value, binder next, void *previous_top) +{ + binder result = checked_malloc(sizeof(*result)); -static binder Binder(void *key, void *value, binder next, void *prevtop) -{binder b = checked_malloc(sizeof(*b)); - b->key = key; b->value=value; b->next=next; b->prevtop = prevtop; - return b; + result->key = key; + result->value = value; + result->next = next; + result->previous_top = previous_top; + return result; } TAB_table TAB_empty(void) -{ - TAB_table t = checked_malloc(sizeof(*t)); - int i; - t->top = NULL; - for (i = 0; i < TABSIZE; i++) - t->table[i] = NULL; - return t; +{ + TAB_table table = checked_malloc(sizeof(*table)); + size_t index; + + table->top = NULL; + for (index = 0; index < TABSIZE; ++index) { + table->buckets[index] = NULL; + } + return table; } -/* The cast from pointer to integer in the expression - * ((unsigned)key) % TABSIZE - * may lead to a warning message. However, the code is safe, - * and will still operate correctly. This line is just hashing - * a pointer value into an integer value, and no matter how the - * conversion is done, as long as it is done consistently, a - * reasonable and repeatable index into the table will result. - */ - -void TAB_enter(TAB_table t, void *key, void *value) -{int index; - assert(t && key); - index = ((unsigned)key) % TABSIZE; - t->table[index] = Binder(key, value,t->table[index], t->top); - t->top = key; +void TAB_enter(TAB_table table, void *key, void *value) +{ + size_t index; + + assert(table != NULL && key != NULL); + index = table_index(key); + table->buckets[index] = Binder(key, value, table->buckets[index], table->top); + table->top = key; } -void *TAB_look(TAB_table t, void *key) -{int index; - binder b; - assert(t && key); - index=((unsigned)key) % TABSIZE; - for(b=t->table[index]; b; b=b->next) - if (b->key==key) return b->value; - return NULL; +void *TAB_look(TAB_table table, void *key) +{ + binder entry; + + assert(table != NULL && key != NULL); + for (entry = table->buckets[table_index(key)]; entry != NULL; entry = entry->next) { + if (entry->key == key) { + return entry->value; + } + } + return NULL; } -void *TAB_pop(TAB_table t) { - void *k; binder b; int index; - assert (t); - k = t->top; - assert (k); - index = ((unsigned)k) % TABSIZE; - b = t->table[index]; - assert(b); - t->table[index] = b->next; - t->top=b->prevtop; - return b->key; +void *TAB_pop(TAB_table table) +{ + void *key; + size_t index; + binder entry; + + assert(table != NULL && table->top != NULL); + key = table->top; + index = table_index(key); + entry = table->buckets[index]; + assert(entry != NULL && entry->key == key); + table->buckets[index] = entry->next; + table->top = entry->previous_top; + free(entry); + return key; } -void TAB_dump(TAB_table t, void (*show)(void *key, void *value)) { - void *k = t->top; - int index = ((unsigned)k) % TABSIZE; - binder b = t->table[index]; - if (b==NULL) return; - t->table[index]=b->next; - t->top=b->prevtop; - show(b->key,b->value); - TAB_dump(t,show); - assert(t->top == b->prevtop && t->table[index]==b->next); - t->top=k; - t->table[index]=b; +void TAB_dump(TAB_table table, TAB_show show) +{ + void *key; + size_t index; + binder entry; + + assert(table != NULL && show != NULL); + if (table->top == NULL) { + return; + } + + key = table->top; + index = table_index(key); + entry = table->buckets[index]; + assert(entry != NULL && entry->key == key); + + table->buckets[index] = entry->next; + table->top = entry->previous_top; + show(entry->key, entry->value); + TAB_dump(table, show); + assert(table->top == entry->previous_top && table->buckets[index] == entry->next); + table->top = key; + table->buckets[index] = entry; } diff --git a/table.h b/table.h index 26fd700..0f8f13f 100644 --- a/table.h +++ b/table.h @@ -1,32 +1,15 @@ -/* - * table.h - generic hash table - * - * No algorithm should use these functions directly, because - * programming with void* is too error-prone. Instead, - * each module should make "wrapper" functions that take - * well-typed arguments and call the TAB_ functions. - */ +#ifndef ADA_TABLE_H +#define ADA_TABLE_H +/* Generic scoped table. Typed wrappers belong in individual modules. */ typedef struct TAB_table_ *TAB_table; -/* Make a new table mapping "keys" to "values". */ -TAB_table TAB_empty(void); - -/* Enter the mapping "key"->"value" into table "t", - * shadowing but not destroying any previous binding for "key". */ -void TAB_enter(TAB_table t, void *key, void *value); - -/* Look up the most recent binding for "key" in table "t" */ -void *TAB_look(TAB_table t, void *key); - -/* Pop the most recent binding and return its key. - * This may expose another binding for the same key, if there was one. */ -void *TAB_pop(TAB_table t); - - -/* Call "show" on every "key"->"value" pair in the table, - * including shadowed bindings, in order from the most - * recent binding of any key to the oldest binding in the table */ -void TAB_dump(TAB_table t, void (*show)(void *key, void *value)); +typedef void (*TAB_show)(void *key, void *value); +TAB_table TAB_empty(void); +void TAB_enter(TAB_table table, void *key, void *value); +void *TAB_look(TAB_table table, void *key); +void *TAB_pop(TAB_table table); +void TAB_dump(TAB_table table, TAB_show show); +#endif diff --git a/tests/abi/six_args_callee.c b/tests/abi/six_args_callee.c new file mode 100644 index 0000000..c9d0606 --- /dev/null +++ b/tests/abi/six_args_callee.c @@ -0,0 +1,5 @@ +/* Compiled by mipsel-linux-gnu-gcc-13; intentionally freestanding. */ +int abi_six_callee(int a, int b, int c, int d, int e, int f) +{ + return a + b + c + d + e + f; +} diff --git a/tests/abi/six_args_caller.S b/tests/abi/six_args_caller.S new file mode 100644 index 0000000..c40cab8 --- /dev/null +++ b/tests/abi/six_args_caller.S @@ -0,0 +1,62 @@ +/* Hand-written o32 caller: arguments five and six occupy 16($sp), 20($sp). */ + + .set noreorder + .text + + .globl abi_six_asm_caller + .ent abi_six_asm_caller +abi_six_asm_caller: + /* 16-byte home area, two stack arguments, and saved return address. */ + addiu $sp, $sp, -32 + sw $ra, 24($sp) + li $a0, 11 + li $a1, 12 + li $a2, 13 + li $a3, 14 + li $t0, 15 + sw $t0, 16($sp) + li $t0, 16 + sw $t0, 20($sp) + jal abi_six_callee + nop + lw $ra, 24($sp) + addiu $sp, $sp, 32 + jr $ra + nop + .end abi_six_asm_caller + + .globl __ada_elaborate + .ent __ada_elaborate +__ada_elaborate: + jr $ra + nop + .end __ada_elaborate + + .globl ada_main + .ent ada_main +ada_main: + addiu $sp, $sp, -24 + sw $ra, 16($sp) + jal abi_six_asm_caller + nop + lw $ra, 16($sp) + addiu $sp, $sp, 24 + addiu $v0, $v0, -81 + jr $ra + nop + .end ada_main + + .globl __ada_finalize + .ent __ada_finalize +__ada_finalize: + jr $ra + nop + .end __ada_finalize + + /* Keep the linker-script RW PT_LOAD nonempty for loader policy coverage. */ + .data + .globl abi_probe_writable +abi_probe_writable: + .word 0 + + .set reorder diff --git a/tests/elf/r0-smoke.expected b/tests/elf/r0-smoke.expected new file mode 100644 index 0000000..9e4f4d0 --- /dev/null +++ b/tests/elf/r0-smoke.expected @@ -0,0 +1,9 @@ +# Assertions consumed by tests/run_tests.py for the hand-written R0 smoke ELF. +ELF_CLASS=ELF32 +ELF_DATA=2's complement, little endian +ELF_TYPE=EXEC +ELF_MACHINE=MIPS R3000 +ELF_FLAGS=0x70001001 +ENTRY_SYMBOL=_start +LOAD_POLICY=no-writable-executable-load;writable-data-if-any-in-rw-load;text-only-no-rw-load +DYNAMIC_POLICY=no-interpreter;no-needed;no-undefined-symbols diff --git a/tests/fixtures/r0/runtime/smoke.S b/tests/fixtures/r0/runtime/smoke.S new file mode 100644 index 0000000..c990d57 --- /dev/null +++ b/tests/fixtures/r0/runtime/smoke.S @@ -0,0 +1,34 @@ +/* Minimal hand-written R0 application: no C runtime, libc, or libgcc. */ + + .set noreorder + .text + + .globl __ada_elaborate + .ent __ada_elaborate +__ada_elaborate: + jr $ra + nop + .end __ada_elaborate + + .globl ada_main + .ent ada_main +ada_main: + move $v0, $zero + jr $ra + nop + .end ada_main + + .globl __ada_finalize + .ent __ada_finalize +__ada_finalize: + jr $ra + nop + .end __ada_finalize + + /* Exercise the separate writable-load policy. */ + .data + .globl r0_smoke_writable +r0_smoke_writable: + .word 0 + + .set reorder diff --git a/tests/fixtures/r0/runtime/text_only.S b/tests/fixtures/r0/runtime/text_only.S new file mode 100644 index 0000000..405820c --- /dev/null +++ b/tests/fixtures/r0/runtime/text_only.S @@ -0,0 +1,28 @@ +/* Text-only R0 application. It must produce no RW PT_LOAD. */ + + .set noreorder + .text + + .globl __ada_elaborate + .ent __ada_elaborate +__ada_elaborate: + jr $ra + nop + .end __ada_elaborate + + .globl ada_main + .ent ada_main +ada_main: + move $v0, $zero + jr $ra + nop + .end ada_main + + .globl __ada_finalize + .ent __ada_finalize +__ada_finalize: + jr $ra + nop + .end __ada_finalize + + .set reorder diff --git a/tests/run_tests.py b/tests/run_tests.py new file mode 100644 index 0000000..3991a31 --- /dev/null +++ b/tests/run_tests.py @@ -0,0 +1,411 @@ +#!/usr/bin/env python3 +"""Direct R0 Linux/MIPS toolchain, ELF, QEMU, and ABI contract checks. + +This runner deliberately does not depend on the repository Makefile. It is +usable before compiler build integration and creates all generated artifacts in +a private temporary directory unless --build-dir is supplied. +""" + +from __future__ import annotations + +import argparse +from pathlib import Path +import re +import shlex +import shutil +import subprocess +import sys +import tempfile +from typing import Iterable + +ROOT = Path(__file__).resolve().parents[1] +RUNTIME = ROOT / "runtime" +FIXTURES = ROOT / "tests" / "fixtures" / "r0" / "runtime" +ABI = ROOT / "tests" / "abi" +LOCK_PATH = ROOT / "ci" / "toolchain.lock" + + +class ContractFailure(RuntimeError): + """A violated R0 artifact contract.""" + + +def command_text(command: Iterable[object]) -> str: + return " ".join(str(part) for part in command) + + +def run( + command: list[object], + *, + cwd: Path | None = None, + require_quiet: bool = False, + merge_stderr: bool = False, + expected_status: int = 0, + timeout: float | None = None, +) -> str: + command = [str(part) for part in command] + completed = subprocess.run( + command, + cwd=cwd or ROOT, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT if merge_stderr else subprocess.PIPE, + check=False, + timeout=timeout, + ) + stderr = "" if merge_stderr else completed.stderr + if completed.returncode != expected_status or (require_quiet and stderr): + detail = "command emitted unexpected stderr" if stderr else "unexpected exit status" + raise ContractFailure( + f"{detail} ({completed.returncode}, expected {expected_status}): {command_text(command)}\n" + f"stdout:\n{completed.stdout}\nstderr:\n{stderr}" + ) + return completed.stdout + + +def load_lock() -> dict[str, str]: + lock: dict[str, str] = {} + for line in LOCK_PATH.read_text(encoding="utf-8").splitlines(): + line = line.strip() + if line and not line.startswith("#"): + key, separator, value = line.partition("=") + if not separator or not key or not value: + raise ContractFailure(f"malformed toolchain lock entry: {line!r}") + lock[key] = value + required = { + "TARGET_CC", + "TARGET_AS", + "TARGET_LD", + "TARGET_NM", + "TARGET_READELF", + "QEMU", + "TARGET_UNISTD", + "TARGET_AS_FLAGS", + "TARGET_CFLAGS", + "TARGET_LD_FLAGS", + "EXPECTED_E_FLAGS", + } + missing = sorted(required - lock.keys()) + if missing: + raise ContractFailure(f"toolchain lock is missing required entries: {', '.join(missing)}") + return lock + + +def lock_flags(lock: dict[str, str], key: str) -> list[str]: + flags = shlex.split(lock[key]) + return [str(ROOT / flag) if flag.startswith("runtime/") else flag for flag in flags] + + +def require_tool(name: str) -> str: + tool = shutil.which(name) + if tool is None: + raise ContractFailure(f"required tool not found in PATH: {name}") + return tool + + +def tool_version(tool: str) -> str: + version = run([tool, "--version"], merge_stderr=True) + return version.splitlines()[0] if version else "unknown version" + + +def validate_package(lock: dict[str, str], key: str, *, required: bool) -> None: + package, separator, expected_version = lock[key].partition("=") + if not separator: + raise ContractFailure(f"{key} must use package=version form") + if shutil.which("dpkg-query") is None: + if required: + raise ContractFailure("dpkg-query is required to validate the Ubuntu toolchain lock") + return + completed = subprocess.run( + ["dpkg-query", "-W", "-f=${Version}", package], + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + check=False, + ) + if completed.returncode: + if required: + raise ContractFailure(f"locked package is not installed: {package}") + return + actual_version = completed.stdout.strip() + if actual_version != expected_version: + raise ContractFailure( + f"locked package {package} is {actual_version}, expected {expected_version}" + ) + + +def validate_lock_environment(lock: dict[str, str], *, has_cc: bool) -> None: + for key in ("TARGET_BINUTILS_PACKAGE", "QEMU_PACKAGE", "TARGET_LINUX_HEADERS_PACKAGE"): + validate_package(lock, key, required=True) + validate_package(lock, "TARGET_CC_PACKAGE", required=has_cc) + + +def assemble(tools: dict[str, str], flags: list[str], source: Path, output: Path) -> None: + run([tools["as"], *flags, "-o", output, source], require_quiet=True) + + +def link(tools: dict[str, str], flags: list[str], output: Path, objects: list[Path]) -> None: + run([tools["ld"], *flags, "-o", output, *objects], require_quiet=True) + + +def asserted_flag(header: str) -> str: + match = re.search(r"^\s*Flags:\s*(0x[0-9a-fA-F]+)", header, re.MULTILINE) + if match is None: + raise ContractFailure("readelf header did not contain MIPS e_flags") + return match.group(1).lower() + + +def load_segments(program_headers: str) -> tuple[dict[int, tuple[str, str]], dict[str, int]]: + segments: dict[int, tuple[str, str]] = {} + section_segments: dict[str, int] = {} + in_headers = False + in_mapping = False + segment_index = 0 + for line in program_headers.splitlines(): + if line.startswith("Program Headers:"): + in_headers = True + continue + if line.startswith(" Section to Segment mapping:"): + in_headers = False + in_mapping = True + continue + if in_headers: + fields = line.split() + if fields and fields[0] in {"ABIFLAGS", "DYNAMIC", "INTERP", "LOAD", "REGINFO"}: + segment_type = fields[0] + flags = " ".join(fields[6:-1]) if segment_type == "LOAD" else "" + segments[segment_index] = (segment_type, flags) + segment_index += 1 + elif in_mapping: + match = re.match(r"^\s*(\d+)\s+(.*)$", line) + if match: + for section in match.group(2).split(): + section_segments[section] = int(match.group(1)) + return segments, section_segments + + +def allocated_writable_sections(readelf: str, executable: Path) -> set[str]: + sections = run([readelf, "-SW", executable]) + writable: set[str] = set() + for line in sections.splitlines(): + match = re.match( + r"^\s*\[\s*\d+\]\s+(\S+)\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+([A-Z]*)\s+", + line, + ) + if match and "A" in match.group(2) and "W" in match.group(2): + writable.add(match.group(1)) + return writable + + +def assert_elf_contract( + tools: dict[str, str], executable: Path, expected_flags: str, *, expect_writable: bool +) -> None: + header = run([tools["readelf"], "-hW", executable]) + checks = { + "Class: ELF32": "ELF32 class", + "Data: 2's complement, little endian": "little-endian data", + "Type: EXEC (Executable file)": "ET_EXEC", + "Machine: MIPS R3000": "EM_MIPS", + } + for text, description in checks.items(): + if text not in header: + raise ContractFailure(f"ELF header lacks required {description}:\n{header}") + flags = asserted_flag(header) + if flags != expected_flags: + raise ContractFailure(f"ELF flags must be exactly {expected_flags}, got {flags}\n{header}") + + attributes = run([tools["readelf"], "-AW", executable]) + for text in ("ISA: MIPS32r2", "GPR size: 32", "CPR1 size: 32", "FP ABI: Hard float"): + if text not in attributes: + raise ContractFailure(f"missing ABI attribute {text!r}:\n{attributes}") + + program_headers = run([tools["readelf"], "-lW", executable]) + segments, section_segments = load_segments(program_headers) + loads = {index: flags for index, (segment_type, flags) in segments.items() if segment_type == "LOAD"} + if not loads: + raise ContractFailure(f"ELF has no PT_LOAD program headers:\n{program_headers}") + if any("W" in flags and "E" in flags for flags in loads.values()): + raise ContractFailure(f"a PT_LOAD is writable and executable:\n{program_headers}") + + writable_sections = allocated_writable_sections(tools["readelf"], executable) + if bool(writable_sections) != expect_writable: + state = "contains" if writable_sections else "does not contain" + raise ContractFailure(f"fixture {state} writable allocated sections: {sorted(writable_sections)}") + if writable_sections: + for section in writable_sections: + segment = section_segments.get(section) + if segment is None or segment not in loads: + raise ContractFailure(f"writable section {section} is not mapped by a PT_LOAD:\n{program_headers}") + flags = loads[segment] + if "W" not in flags or "E" in flags: + raise ContractFailure( + f"writable section {section} is not in a non-executable RW PT_LOAD:\n{program_headers}" + ) + elif any("W" in flags for flags in loads.values()): + raise ContractFailure(f"text-only ELF unexpectedly has a writable PT_LOAD:\n{program_headers}") + + dynamic = run([tools["readelf"], "-dW", executable]) + if "There is no dynamic section" not in dynamic: + if "NEEDED" in dynamic or "INTERP" in dynamic: + raise ContractFailure(f"static ELF unexpectedly uses a dynamic dependency:\n{dynamic}") + raise ContractFailure(f"static ELF unexpectedly has a dynamic section:\n{dynamic}") + if "INTERP" in program_headers: + raise ContractFailure(f"static ELF unexpectedly contains PT_INTERP:\n{program_headers}") + + symbols = run([tools["nm"], "-u", executable]) + if symbols.strip(): + raise ContractFailure(f"ELF has unresolved symbols:\n{symbols}") + defined = run([tools["nm"], "-n", executable]) + symbol = re.search(r"^([0-9a-fA-F]+)\s+\w\s+_start$", defined, re.MULTILINE) + entry = re.search(r"^\s*Entry point address:\s+0x([0-9a-fA-F]+)", header, re.MULTILINE) + if symbol is None or entry is None: + raise ContractFailure(f"ELF does not define _start as its entry point:\n{header}\n{defined}") + if int(symbol.group(1), 16) != int(entry.group(1), 16): + raise ContractFailure( + f"ELF entry 0x{entry.group(1)} does not resolve to _start at 0x{symbol.group(1)}" + ) + + +def assert_object_contract(readelf: str, objects: Iterable[Path], expected_flags: str) -> None: + for object_file in objects: + header = run([readelf, "-hW", object_file]) + flags = asserted_flag(header) + if flags != expected_flags: + raise ContractFailure( + f"object {object_file.name} flags must be {expected_flags}, got {flags}" + ) + relocations = run([readelf, "-rW", object_file]) + if re.search(r"\bR_MIPS_GPREL\w*\b|\b_gp\b", relocations): + raise ContractFailure( + f"{object_file.name} contains a forbidden $gp-relative relocation:\n{relocations}" + ) + + +def assert_qemu_exit(qemu: str, executable: Path) -> None: + output = run([qemu, executable], cwd=executable.parent, timeout=10, require_quiet=True) + if output: + raise ContractFailure(f"silent R0 fixture unexpectedly wrote stdout:\n{output}") + + +def assert_syscall_header(lock: dict[str, str]) -> None: + checked = (RUNTIME / "linux_o32.h").read_text(encoding="utf-8") + expected = { + "ADA_LINUX_O32_SYSCALL_BASE": "4000", + "ADA_LINUX_O32_SYS_EXIT": "(ADA_LINUX_O32_SYSCALL_BASE + 1)", + "ADA_LINUX_O32_SYS_READ": "(ADA_LINUX_O32_SYSCALL_BASE + 3)", + "ADA_LINUX_O32_SYS_WRITE": "(ADA_LINUX_O32_SYSCALL_BASE + 4)", + } + for macro, value in expected.items(): + if not re.search(rf"^#define\s+{macro}\s+{re.escape(value)}\s*$", checked, re.MULTILINE): + raise ContractFailure(f"runtime/linux_o32.h has unexpected {macro} value") + + unistd = Path(lock["TARGET_UNISTD"]) + target_header = unistd.parent / "unistd_o32.h" + if not unistd.is_file() or not target_header.is_file(): + raise ContractFailure(f"locked target syscall headers are unavailable below {unistd.parent}") + source = target_header.read_text(encoding="utf-8") + for name, offset in {"exit": 1, "read": 3, "write": 4}.items(): + match = re.search( + rf"^#define\s+__NR_{name}\s+\(__NR_Linux\s*\+\s*(\d+)\)", source, re.MULTILINE + ) + if match is None or int(match.group(1)) != offset: + raise ContractFailure(f"{target_header} does not define __NR_{name} as 4000 + {offset}") + + +def build_fixture( + work: Path, + tools: dict[str, str], + lock: dict[str, str], + name: str, + *, + expect_writable: bool, +) -> Path: + objects = [work / f"{name}_start.o", work / f"{name}_linux_o32.o", work / f"{name}.o"] + executable = work / f"{name}.elf" + as_flags = lock_flags(lock, "TARGET_AS_FLAGS") + assemble(tools, as_flags, RUNTIME / "start.S", objects[0]) + assemble(tools, as_flags, RUNTIME / "linux_o32.S", objects[1]) + assemble(tools, as_flags, FIXTURES / f"{name}.S", objects[2]) + assert_object_contract(tools["readelf"], objects, lock["EXPECTED_E_FLAGS"].lower()) + link(tools, lock_flags(lock, "TARGET_LD_FLAGS"), executable, objects) + assert_elf_contract( + tools, executable, lock["EXPECTED_E_FLAGS"].lower(), expect_writable=expect_writable + ) + assert_qemu_exit(tools["qemu"], executable) + return executable + + +def build_six_arg_probe(work: Path, tools: dict[str, str], lock: dict[str, str]) -> Path: + cc = require_tool(lock["TARGET_CC"]) + caller = work / "six_args_caller.o" + start = work / "abi_start.o" + wrappers = work / "abi_linux_o32.o" + callee = work / "six_args_callee.o" + objects = [start, wrappers, caller, callee] + executable = work / "six-args.elf" + as_flags = lock_flags(lock, "TARGET_AS_FLAGS") + assemble(tools, as_flags, ABI / "six_args_caller.S", caller) + assemble(tools, as_flags, RUNTIME / "start.S", start) + assemble(tools, as_flags, RUNTIME / "linux_o32.S", wrappers) + run([cc, *lock_flags(lock, "TARGET_CFLAGS"), "-c", ABI / "six_args_callee.c", "-o", callee], require_quiet=True) + assert_object_contract(tools["readelf"], objects, lock["EXPECTED_E_FLAGS"].lower()) + link(tools, lock_flags(lock, "TARGET_LD_FLAGS"), executable, objects) + assert_elf_contract(tools, executable, lock["EXPECTED_E_FLAGS"].lower(), expect_writable=True) + assert_qemu_exit(tools["qemu"], executable) + return executable + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--build-dir", type=Path, help="directory for retained generated artifacts") + parser.add_argument("--skip-abi", action="store_true", help="run ELF/QEMU fixture checks only") + args = parser.parse_args() + + try: + lock = load_lock() + cc = shutil.which(lock["TARGET_CC"]) + validate_lock_environment(lock, has_cc=cc is not None) + tools = { + "as": require_tool(lock["TARGET_AS"]), + "ld": require_tool(lock["TARGET_LD"]), + "readelf": require_tool(lock["TARGET_READELF"]), + "nm": require_tool(lock["TARGET_NM"]), + "qemu": require_tool(lock["QEMU"]), + } + for name, tool in tools.items(): + print(f"tool {name}: {tool_version(tool)}") + if cc is None: + print(f"tool cc: unavailable ({lock['TARGET_CC']}; ABI probe will be skipped)") + else: + print(f"tool cc: {tool_version(cc)}") + assert_syscall_header(lock) + + temporary: tempfile.TemporaryDirectory[str] | None = None + if args.build_dir: + work = args.build_dir.resolve() + work.mkdir(parents=True, exist_ok=True) + else: + temporary = tempfile.TemporaryDirectory(prefix="ada-r0-contract-") + work = Path(temporary.name) + try: + text_only = build_fixture(work, tools, lock, "text_only", expect_writable=False) + print(f"PASS R0 text-only ELF/QEMU smoke: {text_only}") + smoke = build_fixture(work, tools, lock, "smoke", expect_writable=True) + print(f"PASS R0 writable-data ELF/QEMU smoke: {smoke}") + if not args.skip_abi: + if cc is None: + print(f"SKIP R0 cross-GCC six-argument ABI probe: {lock['TARGET_CC']} unavailable") + else: + probe = build_six_arg_probe(work, tools, lock) + print(f"PASS R0 cross-GCC six-argument ABI probe: {probe}") + print("PASS R0 Linux/MIPS contract") + return 0 + finally: + if temporary is not None: + temporary.cleanup() + except (ContractFailure, subprocess.TimeoutExpired) as error: + print(f"FAIL R0 Linux/MIPS contract: {error}", file=sys.stderr) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/unit/test_grammar_inventory.py b/tests/unit/test_grammar_inventory.py new file mode 100644 index 0000000..7120998 --- /dev/null +++ b/tests/unit/test_grammar_inventory.py @@ -0,0 +1,151 @@ +"""Focused tests for the reproducible parser/corpus inventory tools.""" + +from __future__ import annotations + +import csv +import contextlib +import io +import shutil +import sys +import tempfile +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(ROOT / "tools")) + +import check_coverage # noqa: E402 +import inventory_grammar # noqa: E402 + + +class GrammarInventoryTests(unittest.TestCase): + def test_checked_out_parser_matches_the_count_baseline(self) -> None: + record = inventory_grammar.inventory(ROOT / "parser.y") + self.assertEqual([], inventory_grammar.baseline_drift(record)) + self.assertEqual(233, record["nonterminals"]) + self.assertEqual(513, record["alternatives"]) + self.assertEqual(44, record["empty_rules"]) + self.assertEqual(23, record["placeholder_actions"]) + self.assertEqual(0, record["shift_reduce_conflicts"]) + self.assertEqual(0, record["reduce_reduce_conflicts"]) + + def test_ambiguous_grammar_conflicts_are_measured_and_fail_baseline(self) -> None: + fixture = """%token WORD +%% +start: expression; +expression: expression expression | WORD; +%% +""" + with tempfile.TemporaryDirectory() as directory: + grammar = Path(directory) / "ambiguous.y" + grammar.write_text(fixture, encoding="utf-8") + self.assertEqual((1, 0), inventory_grammar.measure_conflicts(grammar)) + with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()): + self.assertEqual( + 1, + inventory_grammar.main(["--grammar", str(grammar), "--check-baseline"]), + ) + + def test_release_assignment_respects_wrappers_and_operator_ownership(self) -> None: + alternatives = inventory_grammar.parse_grammar(ROOT / "parser.y") + assignments = inventory_grammar.release_assignments(alternatives) + releases = { + (alternative.nonterminal, alternative.rhs): assignments[ + (alternative.nonterminal, alternative.ordinal) + ] + for alternative in alternatives + } + self.assertEqual("R4", releases[("decl", "pkg_decl")]) + self.assertEqual("R5", releases[("decl", "exception_decl")]) + self.assertEqual("R6", releases[("decl", "task_decl")]) + self.assertEqual("R1", releases[("multiplying", "MOD")]) + self.assertEqual( + [], inventory_grammar.release_dependency_errors(alternatives, assignments) + ) + + def test_top_level_corpus_filter_excludes_nested_release_fixtures(self) -> None: + self.assertEqual( + {"tests/top.adb", "tests/spec.ads"}, + check_coverage.top_level_corpus_sources([ + "tests/top.adb", + "tests/spec.ads", + "tests/fixtures/r0/positive/main.adb", + "tests/unit/helper.ads", + "docs/not-a-test.adb", + ]), + ) + + def test_tracked_corpus_discovery_matches_authoritative_sources(self) -> None: + self.assertEqual( + set(check_coverage.EXPECTED_CORPUS), + check_coverage.tracked_corpus_sources(ROOT / "tests"), + ) + + def test_duplicate_values_returns_each_duplicate_once(self) -> None: + self.assertEqual( + ["first", "second"], + check_coverage.duplicate_values(["second", "first", "second", "first"]), + ) + + def test_parse_grammar_handles_unterminated_rule_groups_and_actions(self) -> None: + fixture = """%token WORD +%% +start: list +list: + /* intentionally no semicolon before the next declaration */ + { $$ = 0; } +items: WORD { call('{'); } + | /* empty */ { $$ = 1; } +; +%% +""" + with tempfile.TemporaryDirectory() as directory: + grammar = Path(directory) / "fixture.y" + grammar.write_text(fixture, encoding="utf-8") + items = inventory_grammar.parse_grammar(grammar) + self.assertEqual( + [("start", 1, "list"), ("list", 1, ""), + ("items", 1, "WORD"), ("items", 2, "")], + [(item.nonterminal, item.ordinal, item.rhs) for item in items], + ) + + def test_coverage_rejects_a_wrapper_release_before_its_feature(self) -> None: + with tempfile.TemporaryDirectory() as directory: + manifest = Path(directory) / "coverage.csv" + shutil.copy(ROOT / "docs" / "grammar-coverage.csv", manifest) + lines = manifest.read_text(encoding="utf-8").splitlines(keepends=True) + for index, line in enumerate(lines): + if line.startswith("grammar,decl,6,decl : pkg_decl,"): + fields = next(csv.reader([line])) + fields[7] = "R1" + lines[index] = ",".join(fields) + "\n" + break + else: + self.fail("generated manifest lacks decl : pkg_decl") + manifest.write_text("".join(lines), encoding="utf-8") + errors = check_coverage.validate(manifest, ROOT / "parser.y", ROOT / "tests") + self.assertTrue(any("release ownership for ('decl', '6')" in error for error in errors)) + + def test_coverage_rejects_a_duplicate_and_bad_corpus_classification(self) -> None: + with tempfile.TemporaryDirectory() as directory: + temporary = Path(directory) + manifest = temporary / "coverage.csv" + shutil.copy(ROOT / "docs" / "grammar-coverage.csv", manifest) + with manifest.open("a", encoding="utf-8", newline="") as target: + writer = csv.DictWriter(target, fieldnames=inventory_grammar.CSV_FIELDS) + writer.writerow( + { + "row_type": "corpus", + "source": "tests/hello.adb", + "classification": "executable", + "closing_release": "R0", + "outcome": "execute", + } + ) + errors = check_coverage.validate(manifest, ROOT / "parser.y", ROOT / "tests") + self.assertTrue(any("duplicate corpus rows" in error for error in errors)) + self.assertTrue(any("classification for tests/hello.adb" in error for error in errors)) + + +if __name__ == "__main__": + unittest.main() diff --git a/tools/check_coverage.py b/tools/check_coverage.py new file mode 100644 index 0000000..e17e0df --- /dev/null +++ b/tools/check_coverage.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +"""Validate the generated grammar/corpus coverage manifest.""" + +from __future__ import annotations + +import argparse +import csv +from collections import Counter +import subprocess +import sys +from pathlib import Path +from typing import TypeVar + +import inventory_grammar + +REPOSITORY_ROOT = Path(__file__).resolve().parents[1] +DEFAULT_MANIFEST = REPOSITORY_ROOT / "docs" / "grammar-coverage.csv" +DEFAULT_CORPUS_DIRECTORY = REPOSITORY_ROOT / "tests" + +REQUIRED_FIELDS = set(inventory_grammar.CSV_FIELDS) +EXPECTED_CORPUS = { + "tests/subr.adb": ("executable", "R2", "execute"), + "tests/numbers.adb": ("executable", "R2", "execute"), + "tests/calc.adb": ("executable", "R3", "execute"), + "tests/gnatioex.adb": ("executable", "R3; re-verify R5", "execute"), + "tests/i_stack.ads": ("interface artifact only", "R4", "interface-artifact"), + "tests/hello.adb": ("expected-diagnostic", "R4", "diagnostic"), +} + +T = TypeVar("T") + + +def read_manifest(path: Path) -> list[dict[str, str]]: + with path.open(encoding="utf-8", newline="") as source: + lines = (line for line in source if not line.startswith("#")) + reader = csv.DictReader(lines) + if reader.fieldnames is None: + raise ValueError("manifest has no CSV header") + missing = REQUIRED_FIELDS.difference(reader.fieldnames) + if missing: + raise ValueError(f"manifest is missing columns: {', '.join(sorted(missing))}") + return list(reader) + + +def top_level_corpus_sources(paths: list[str]) -> set[str]: + """Keep only direct ``tests/*.adb`` and ``tests/*.ads`` corpus files.""" + + return { + source + for source in paths + if Path(source).parent == Path("tests") + and Path(source).suffix in {".adb", ".ads"} + } + + +def tracked_corpus_sources(corpus_directory: Path) -> set[str]: + """Return Ada corpus paths relative to the repository root. + + The default corpus directory is sourced from Git so ignored or untracked + fixtures never affect release coverage. The override supports isolated + validator tests without requiring a temporary Git repository. + """ + + if corpus_directory.resolve() == DEFAULT_CORPUS_DIRECTORY.resolve(): + result = subprocess.run( + [ + "git", + "-C", + str(REPOSITORY_ROOT), + "ls-files", + "-z", + "--", + "tests/*.adb", + "tests/*.ads", + ], + text=True, + capture_output=True, + check=False, + ) + if result.returncode: + detail = result.stderr.strip() or "unknown Git error" + raise RuntimeError(f"could not list tracked corpus files: {detail}") + return top_level_corpus_sources(result.stdout.split("\0")) + + return top_level_corpus_sources([ + str(path.relative_to(corpus_directory.parent)) + for suffix in ("*.adb", "*.ads") + for path in corpus_directory.glob(suffix) + if path.is_file() + ]) + + +def duplicate_values(values: list[T]) -> list[T]: + """Return each duplicate exactly once, in deterministic order.""" + + return sorted(value for value, count in Counter(values).items() if count > 1) + + +def validate(manifest: Path, grammar: Path, corpus_directory: Path) -> list[str]: + rows = read_manifest(manifest) + errors: list[str] = [] + grammar_rows = [row for row in rows if row["row_type"] == "grammar"] + corpus_rows = [row for row in rows if row["row_type"] == "corpus"] + extracted = inventory_grammar.parse_grammar(grammar) + assignments = { + (nonterminal, str(ordinal)): release + for (nonterminal, ordinal), release in inventory_grammar.release_assignments( + extracted + ).items() + } + expected_keys = {(item.nonterminal, str(item.ordinal)) for item in extracted} + found_keys = [(row["nonterminal"], row["alternative"]) for row in grammar_rows] + found_key_set = set(found_keys) + + duplicate_keys = duplicate_values(found_keys) + if duplicate_keys: + errors.append(f"duplicate grammar rows: {duplicate_keys}") + missing_keys = sorted(expected_keys.difference(found_key_set)) + unexpected_keys = sorted(found_key_set.difference(expected_keys)) + if missing_keys: + errors.append(f"missing grammar rows: {missing_keys}") + if unexpected_keys: + errors.append(f"unknown grammar rows: {unexpected_keys}") + if len(grammar_rows) != len(extracted): + errors.append( + f"grammar row count: expected {len(extracted)}, found {len(grammar_rows)}" + ) + + expected_productions = { + (item.nonterminal, str(item.ordinal)): item.production for item in extracted + } + for row in grammar_rows: + key = (row["nonterminal"], row["alternative"]) + if key in expected_productions and row["production"] != expected_productions[key]: + errors.append( + f"production drift for {key}: expected {expected_productions[key]!r}, " + f"found {row['production']!r}" + ) + if key in assignments and row["closing_release"] != assignments[key]: + errors.append( + f"release ownership for {key}: expected {assignments[key]}, " + f"found {row['closing_release']}" + ) + + tracked_sources = tracked_corpus_sources(corpus_directory) + manifest_sources = [row["source"] for row in corpus_rows] + source_set = set(manifest_sources) + duplicates = duplicate_values(manifest_sources) + if duplicates: + errors.append(f"duplicate corpus rows: {duplicates}") + missing_sources = sorted(tracked_sources.difference(source_set)) + unexpected_sources = sorted(source_set.difference(tracked_sources)) + if missing_sources: + errors.append(f"missing corpus rows: {missing_sources}") + if unexpected_sources: + errors.append(f"untracked corpus rows: {unexpected_sources}") + if source_set != set(EXPECTED_CORPUS): + errors.append("corpus source set differs from the authoritative plan classification") + for row in corpus_rows: + source = row["source"] + expected = EXPECTED_CORPUS.get(source) + found = (row["classification"], row["closing_release"], row["outcome"]) + if expected is not None and found != expected: + errors.append( + f"corpus classification for {source}: expected {expected}, found {found}" + ) + return errors + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--manifest", type=Path, default=DEFAULT_MANIFEST) + parser.add_argument("--grammar", type=Path, default=inventory_grammar.DEFAULT_GRAMMAR) + parser.add_argument("--corpus-directory", type=Path, default=DEFAULT_CORPUS_DIRECTORY) + args = parser.parse_args(argv) + try: + errors = validate(args.manifest, args.grammar, args.corpus_directory) + except (OSError, RuntimeError, ValueError, csv.Error) as error: + print(f"coverage error: {error}", file=sys.stderr) + return 2 + if errors: + print("coverage validation failed:", file=sys.stderr) + for error in errors: + print(f" {error}", file=sys.stderr) + return 1 + print("coverage validation passed") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/inventory_grammar.py b/tools/inventory_grammar.py new file mode 100755 index 0000000..c2a4857 --- /dev/null +++ b/tools/inventory_grammar.py @@ -0,0 +1,606 @@ +#!/usr/bin/env python3 +"""Extract and verify the checked-in Bison grammar inventory. + +The grammar manifest is deliberately derived from ``parser.y`` instead of being +hand-maintained. A checked-in baseline makes grammar changes explicit: adding +or removing a production, conflict, empty alternative, or legacy placeholder +requires updating this tool and the coverage manifest in the same review. +""" + +from __future__ import annotations + +import argparse +import csv +import hashlib +import json +import re +import subprocess +import sys +import tempfile +from dataclasses import dataclass +from pathlib import Path +from typing import Iterable + +REPOSITORY_ROOT = Path(__file__).resolve().parents[1] +DEFAULT_GRAMMAR = REPOSITORY_ROOT / "parser.y" +DEFAULT_MANIFEST = REPOSITORY_ROOT / "docs" / "grammar-coverage.csv" + +# Measured from parser.y on vorflux/restore-compiler-r0 with GNU Bison 3.8.2. +# Keep these values intentional: --check-baseline must reject accidental drift. +BASELINE = { + "nonterminals": 233, + "alternatives": 513, + "shift_reduce_conflicts": 0, + "reduce_reduce_conflicts": 0, + "empty_rules": 44, + "placeholder_actions": 23, +} + +CSV_FIELDS = ( + "row_type", + "nonterminal", + "alternative", + "production", + "ast_node", + "semantic_owner", + "ir_runtime_owner", + "closing_release", + "current_state", + "tests", + "source", + "classification", + "outcome", + "notes", +) + + +@dataclass(frozen=True) +class Alternative: + """One source-level Bison alternative, preserving semantic actions.""" + + nonterminal: str + ordinal: int + rhs: str + action: str + + @property + def production(self) -> str: + return f"{self.nonterminal} : {self.rhs or '%empty'}" + + @property + def is_empty(self) -> bool: + return not self.rhs + + @property + def has_placeholder(self) -> bool: + return "A_NotImplemented" in self.action + + +def _grammar_section(source: str) -> str: + """Return the text between the first two Bison ``%%`` separators.""" + + separators = list(re.finditer(r"(?m)^%%\s*$", source)) + if len(separators) < 2: + raise ValueError("parser.y must contain two standalone %% separators") + return source[separators[0].end() : separators[1].start()] + +def _skip_quoted(text: str, index: int) -> int: + quote = text[index] + index += 1 + while index < len(text): + if text[index] == "\\": + index += 2 + continue + if text[index] == quote: + return index + 1 + index += 1 + raise ValueError("unterminated quoted literal in grammar") + + +def _skip_comment(text: str, index: int) -> int: + if text.startswith("//", index): + end = text.find("\n", index + 2) + return len(text) if end == -1 else end + 1 + if text.startswith("/*", index): + end = text.find("*/", index + 2) + if end == -1: + raise ValueError("unterminated block comment in grammar") + return end + 2 + return index + + +def _split_top_level(text: str, separators: Iterable[str]) -> list[str]: + """Split Bison RHS text without treating actions/literals as delimiters.""" + + separator_set = set(separators) + parts: list[str] = [] + start = 0 + index = 0 + brace_depth = 0 + while index < len(text): + comment_end = _skip_comment(text, index) + if comment_end != index: + index = comment_end + continue + char = text[index] + if char in "'\"": + index = _skip_quoted(text, index) + continue + if char == "{": + brace_depth += 1 + elif char == "}": + brace_depth -= 1 + if brace_depth < 0: + raise ValueError("unbalanced action braces in grammar") + elif char in separator_set and brace_depth == 0: + parts.append(text[start:index]) + start = index + 1 + index += 1 + if brace_depth: + raise ValueError("unbalanced action braces in grammar") + parts.append(text[start:]) + return parts + + +def _strip_actions(text: str) -> tuple[str, str]: + """Separate an RHS's grammar symbols from all C semantic-action text.""" + + grammar: list[str] = [] + actions: list[str] = [] + index = 0 + brace_depth = 0 + action_start: int | None = None + while index < len(text): + comment_end = _skip_comment(text, index) + if comment_end != index: + if not brace_depth: + grammar.append(text[index:comment_end]) + index = comment_end + continue + char = text[index] + if char in "'\"": + end = _skip_quoted(text, index) + if not brace_depth: + grammar.append(text[index:end]) + index = end + continue + if char == "{": + if brace_depth == 0: + action_start = index + brace_depth = 1 + index += 1 + continue + brace_depth += 1 + index += 1 + continue + if char == "}": + if brace_depth == 0: + grammar.append(char) + index += 1 + continue + brace_depth -= 1 + if brace_depth == 0: + assert action_start is not None + actions.append(text[action_start : index + 1]) + action_start = None + index += 1 + continue + if not brace_depth: + grammar.append(char) + index += 1 + if brace_depth: + raise ValueError("unbalanced action braces in grammar") + return "".join(grammar), "".join(actions) + + +def _normalize(text: str) -> str: + without_comments = re.sub(r"/\*.*?\*/|//[^\n]*", " ", text, flags=re.DOTALL) + return " ".join(without_comments.split()) + + +def _parse_production_body(nonterminal: str, body: str) -> list[Alternative]: + alternatives: list[Alternative] = [] + for ordinal, raw_alternative in enumerate(_split_top_level(body, "|"), start=1): + rhs, action = _strip_actions(raw_alternative) + alternatives.append( + Alternative(nonterminal, ordinal, _normalize(rhs), _normalize(action)) + ) + return alternatives + + +def parse_grammar(path: Path) -> list[Alternative]: + """Parse Bison production declarations from *path* without generated files. + + Bison allows a production group to omit a terminating semicolon when the + next line starts a new ``nonterminal:`` declaration. The historical parser + uses that form in a few places, so group boundaries are identified by either + a top-level semicolon or the next declaration at the start of a line. + """ + + section = _grammar_section(path.read_text(encoding="utf-8")) + alternatives: list[Alternative] = [] + current_name: str | None = None + current_body: list[str] = [] + index = 0 + line_start = True + brace_depth = 0 + length = len(section) + + def finish_current() -> None: + nonlocal current_name, current_body + if current_name is None: + return + alternatives.extend(_parse_production_body(current_name, "".join(current_body))) + current_name = None + current_body = [] + + while index < length: + if brace_depth == 0 and line_start: + declaration = re.match( + r"[ \t]*([A-Za-z_][A-Za-z0-9_]*)[ \t]*:", section[index:] + ) + if declaration: + finish_current() + current_name = declaration.group(1) + index += declaration.end() + line_start = False + continue + comment_end = _skip_comment(section, index) + if comment_end != index: + if current_name is not None: + current_body.append(section[index:comment_end]) + line_start = section[index:comment_end].endswith("\n") + index = comment_end + continue + char = section[index] + if char in "'\"": + end = _skip_quoted(section, index) + if current_name is not None: + current_body.append(section[index:end]) + line_start = False + index = end + continue + if char == "{": + brace_depth += 1 + elif char == "}": + brace_depth -= 1 + if brace_depth < 0: + raise ValueError("unbalanced action braces in grammar") + elif char == ";" and brace_depth == 0: + finish_current() + index += 1 + line_start = False + continue + if current_name is None and not char.isspace(): + snippet = section[index : index + 60].splitlines()[0] + raise ValueError(f"expected nonterminal declaration near {snippet!r}") + if current_name is not None: + current_body.append(char) + line_start = char == "\n" + index += 1 + if brace_depth: + raise ValueError("unbalanced action braces in grammar") + finish_current() + return alternatives + +def _run_bison(grammar_path: Path, bison: str, report_mode: str) -> str: + """Run Bison in a temporary directory and return its state report.""" + + with tempfile.TemporaryDirectory(prefix="ada-grammar-inventory-") as directory: + workdir = Path(directory) + report = workdir / "parser.output" + result = subprocess.run( + [bison, "--no-lines", f"--report={report_mode}", f"--report-file={report}", + f"--output={workdir / 'parser.c'}", str(grammar_path)], + text=True, capture_output=True, check=False, + ) + if result.returncode: + detail = result.stderr.strip() or result.stdout.strip() + raise RuntimeError(f"Bison failed for {grammar_path}: {detail}") + return report.read_text(encoding="utf-8") if report.exists() else "" + + +def measure_conflicts(grammar_path: Path, bison: str = "bison") -> tuple[int, int]: + """Run Bison and return its shift/reduce and reduce/reduce conflict counts.""" + + report_text = _run_bison(grammar_path, bison, "state") + # Bison's state report emits, for example, + # ``State 7 conflicts: 1 shift/reduce``. Parse only those per-state + # summaries: stderr has a second aggregate summary and would double-count. + shift_reduce = 0 + reduce_reduce = 0 + for summary in re.findall(r"(?m)^State \d+ conflicts: (.+)$", report_text): + shift_reduce += sum( + int(value) + for value in re.findall(r"(\d+)\s+shift/reduce", summary) + ) + reduce_reduce += sum( + int(value) + for value in re.findall(r"(\d+)\s+reduce/reduce", summary) + ) + return shift_reduce, reduce_reduce + +def inventory(path: Path, bison: str = "bison") -> dict[str, object]: + alternatives = parse_grammar(path) + nonterminals = sorted({alternative.nonterminal for alternative in alternatives}) + conflicts = measure_conflicts(path, bison) + source_digest = hashlib.sha256(path.read_bytes()).hexdigest() + return { + "grammar": str(path), + "grammar_sha256": source_digest, + "nonterminals": len(nonterminals), + "alternatives": len(alternatives), + "shift_reduce_conflicts": conflicts[0], + "reduce_reduce_conflicts": conflicts[1], + "empty_rules": sum(alternative.is_empty for alternative in alternatives), + "placeholder_actions": sum( + alternative.has_placeholder for alternative in alternatives + ), + "productions": alternatives, + } + + +def baseline_drift(record: dict[str, object]) -> list[str]: + return [ + f"{name}: expected {expected}, found {record[name]}" + for name, expected in BASELINE.items() + if record[name] != expected + ] + + +RELEASE_ORDER = {f"R{number}": number for number in range(8)} + + +def _releases(owner: str, names: set[str]) -> dict[str, str]: + return {name: owner for name in names} + + +# Direct owners are explicit. A production's final closing release is the later +# of this owner and every referenced nonterminal's final owner (see below). +DIRECT_RELEASES = { + **_releases("R0", {"goal_symbol", "compilation", "comp_unit", "unit"}), + **_releases("R2", { + "subtype_decl", "subtype_ind", "derived_type", "integer_type", "real_type", + "float_type", "fixed_type", "decimal_digits_constraint", "range", + "range_spec", "range_spec_opt", "range_constr_opt", "enumeration_type", + "enum_id_s", "enum_id", "attribute", "qualified", "membership", + "modular_type_def", "constraint", "range_constraint", + }), + **_releases("R3", { + "array_type", "unconstr_array_type", "constr_array_type", + "component_subtype_def", "index_s", "index", "iter_index_constraint", + "iter_discrete_range_s", "discrete_range", "record_type", "record_def", + "component_list", "component_decl", "component_decl_s", "comp_assoc", + "comp_assoc_s", "aggregate", "allocator", "access_type", "access_def", + "access_opt", "aliased_opt", "tagged_opt", "private_type", "variant_part", + "variant_s", "variant", "discrim_part", "discrim_spec", "discrim_spec_s", + "discrim_part_opt", "type_completion", + }), + **_releases("R4", { + "pkg_decl", "pkg_spec", "pkg_body", "private_part", "body_stub", + "subunit", "context_spec", "with_clause", "use_clause", "use_clause_opt", + "c_name_list", "compound_name", "generic_decl", "generic_formal_part", + "generic_formal", "generic_discrim_part_opt", "generic_type_def", + "generic_derived_type", "generic_subp_inst", "generic_pkg_inst", + "generic_inst", "subp_default", "rename_decl", "subprog_rename", + "pkg_rename", "obj_rename", "exc_rename", "unit_rename", "c_id_opt", + }), + **_releases("R5", { + "raise_stmt", "exception_decl", "exception_handler", "except_handler_part", + "except_handler_part_opt", "handled_stmt_s", "handled_stmt", "when_opt", + }), + **_releases("R6", { + "task_decl", "task_type_decl", "task_def", "task_item_s", "task_item", + "task_private_opt", "entry_decl", "entry_index_spec", "entry_family", + "prot_decl", "prot_opt", "prot_def", "prot_op_decl_s", "prot_op_decl", + "prot_elem_decl_s", "prot_elem_decl", "prot_private_opt", "protected_op", + "accept_stmt", "entry_call_stmt", "select_stmt", "select_alt", "guard", + "delay_stmt", "abort_stmt", "requeue_stmt", "or_select", "triggering_stmt", + "abortable_part", "delay_or_entry_alt", + }), + **_releases("R7", { + "rep_spec", "rep_spec_s", "attrib_def", "record_type_spec", "address_spec", + "align_opt", "comp_loc_s", "code_stmt", "pragma", "pragma_s", "pragma_arg", + "pragma_arg_s", + }), +} + + +def direct_release_for(alternative: Alternative) -> str: + """Return an alternative's explicitly assigned feature owner. + + Unlisted scalar/procedural syntax is R1. Terminal spellings never decide an + owner: `multiplying : MOD` is R1, whereas `integer_type : MOD expression` + is R2 because `integer_type` is explicitly R2. + """ + + return DIRECT_RELEASES.get(alternative.nonterminal, "R1") + + +def _dependencies(alternative: Alternative, nonterminals: set[str]) -> set[str]: + return { + token + for token in re.findall(r"[A-Za-z_][A-Za-z0-9_]*", alternative.rhs) + if token in nonterminals and token != alternative.nonterminal + } + + +def _later_release(*releases: str) -> str: + return max(releases, key=RELEASE_ORDER.__getitem__) + + +def _feature_releases(alternatives: Iterable[Alternative]) -> dict[str, str]: + """Return each nonterminal's explicit feature owner. + + A nonterminal can have alternatives whose explicit owner differs; its + feature owner is the latest such direct assignment. This intentionally does + not recursively close a whole grammar family: a package wrapper remains R4 + even though later releases add declarations legal inside package bodies. + """ + + feature_releases: dict[str, str] = {} + for alternative in alternatives: + owner = direct_release_for(alternative) + previous = feature_releases.get(alternative.nonterminal, owner) + feature_releases[alternative.nonterminal] = _later_release(previous, owner) + return feature_releases + + +def release_assignments(alternatives: Iterable[Alternative]) -> dict[tuple[str, int], str]: + """Close alternatives no earlier than their direct referenced features.""" + + alternatives = list(alternatives) + nonterminals = {alternative.nonterminal for alternative in alternatives} + feature_releases = _feature_releases(alternatives) + assignments = { + (alternative.nonterminal, alternative.ordinal): _later_release( + direct_release_for(alternative), + *(feature_releases[dependency] + for dependency in _dependencies(alternative, nonterminals)), + ) + for alternative in alternatives + } + errors = release_dependency_errors(alternatives, assignments) + if errors: + raise ValueError("release assignment failed: " + "; ".join(errors)) + return assignments + + +def release_dependency_errors( + alternatives: Iterable[Alternative], assignments: dict[tuple[str, int], str] +) -> list[str]: + """Report rows that predate an explicitly referenced feature owner.""" + + alternatives = list(alternatives) + nonterminals = {alternative.nonterminal for alternative in alternatives} + feature_releases = _feature_releases(alternatives) + errors: list[str] = [] + for alternative in alternatives: + key = (alternative.nonterminal, alternative.ordinal) + release = assignments.get(key) + if release not in RELEASE_ORDER: + errors.append(f"{key} has unknown release {release!r}") + continue + for dependency in sorted(_dependencies(alternative, nonterminals)): + dependency_release = feature_releases[dependency] + if RELEASE_ORDER[release] < RELEASE_ORDER[dependency_release]: + errors.append( + f"{alternative.production} closes {release} before " + f"{dependency} ({dependency_release})" + ) + return errors + +def ast_node_for(alternative: Alternative) -> str: + match = re.search(r"\b(A_[A-Za-z0-9_]+)\s*\(", alternative.action) + return match.group(1) if match else "syntax-only" + + +def grammar_rows(alternatives: Iterable[Alternative]) -> list[dict[str, str]]: + alternatives = list(alternatives) + assignments = release_assignments(alternatives) + rows: list[dict[str, str]] = [] + for alternative in alternatives: + state = "parser-placeholder" if alternative.has_placeholder else "inventory-only" + rows.append( + { + "row_type": "grammar", + "nonterminal": alternative.nonterminal, + "alternative": str(alternative.ordinal), + "production": alternative.production, + "ast_node": ast_node_for(alternative), + "semantic_owner": "Sem_program (planned)", + "ir_runtime_owner": "release-owned (planned)", + "closing_release": assignments[(alternative.nonterminal, alternative.ordinal)], + "current_state": state, + "tests": "inventory: parser.y", + "source": "", + "classification": "", + "outcome": "", + "notes": "", + } + ) + return rows + + +def corpus_rows() -> list[dict[str, str]]: + """The plan's authoritative tracked-corpus ownership, reproduced verbatim.""" + + entries = ( + ("tests/subr.adb", "executable", "R2", "execute", "derived types, range subtype, conversions, First/Last"), + ("tests/numbers.adb", "executable", "R2", "execute", "Float; based integer and real literals; Integer(F)"), + ("tests/calc.adb", "executable", "R3", "execute", "String/Character concatenation"), + ("tests/gnatioex.adb", "executable", "R3; re-verify R5", "execute", "String, Get_Line, slice, concatenation; full I/O re-verification"), + ("tests/i_stack.ads", "interface artifact only", "R4", "interface-artifact", "package private-part completion"), + ("tests/hello.adb", "expected-diagnostic", "R4", "diagnostic", "missing with Ada.Numerics; never an execution fixture"), + ) + return [ + { + "row_type": "corpus", + "nonterminal": "", + "alternative": "", + "production": "", + "ast_node": "", + "semantic_owner": "", + "ir_runtime_owner": "", + "closing_release": release, + "current_state": "planned", + "tests": source, + "source": source, + "classification": classification, + "outcome": outcome, + "notes": note, + } + for source, classification, release, outcome, note in entries + ] + + +def write_manifest(path: Path, alternatives: list[Alternative]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", encoding="utf-8", newline="") as output: + output.write( + "# Generated by tools/inventory_grammar.py --write-manifest; do not edit by hand.\n" + ) + writer = csv.DictWriter(output, fieldnames=CSV_FIELDS) + writer.writeheader() + writer.writerows(grammar_rows(alternatives)) + writer.writerows(corpus_rows()) + + +def printable_inventory(record: dict[str, object]) -> dict[str, object]: + return {name: record[name] for name in (*BASELINE, "grammar_sha256")} + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--grammar", type=Path, default=DEFAULT_GRAMMAR) + parser.add_argument("--bison", default="bison") + parser.add_argument("--check-baseline", action="store_true") + parser.add_argument("--write-manifest", action="store_true") + parser.add_argument("--manifest", type=Path, default=DEFAULT_MANIFEST) + parser.add_argument("--json", action="store_true", help="print the measured inventory as JSON") + args = parser.parse_args(argv) + + try: + record = inventory(args.grammar, args.bison) + except (OSError, RuntimeError, ValueError) as error: + print(f"inventory error: {error}", file=sys.stderr) + return 2 + drift = baseline_drift(record) + if args.json: + print(json.dumps(printable_inventory(record), indent=2, sort_keys=True)) + else: + for name, value in printable_inventory(record).items(): + print(f"{name}: {value}") + if drift: + print("grammar baseline drift:", file=sys.stderr) + for message in drift: + print(f" {message}", file=sys.stderr) + return 1 + if args.write_manifest: + write_manifest(args.manifest, record["productions"]) # type: ignore[arg-type] + print(f"wrote {args.manifest}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/type.c b/type.c index 303115d..37a4c86 100644 --- a/type.c +++ b/type.c @@ -1,12 +1,12 @@ #include #include #include "util.h" +#include "errormsg.h" #include "symbol.h" /* symbol table data structures */ #include "absyn.h" /* abstract syntax data structures */ #include "type.h" /* function prototype */ void Ty_typeCheckExp(S_table table, A_exp v) { - A_ty type; switch (v->kind) { case A_varExp: //Not used diff --git a/util.c b/util.c index 4cde9bb..dce2634 100644 --- a/util.c +++ b/util.c @@ -1,109 +1,163 @@ -/* - * util.c - commonly used utility functions. - */ +/* Common utility helpers used by the host compiler. */ +#include +#include #include #include #include -#include + #include "util.h" -void *checked_malloc(int len) -{void *p = malloc(len); - if (!p) { - fprintf(stderr,"\nRan out of memory!\n"); - exit(1); - } - return p; + +void *checked_malloc(size_t size) +{ + void *result = malloc(size); + + if (result == NULL) { + fputs("adac: out of memory\n", stderr); + exit(EXIT_FAILURE); + } + return result; } -string String(char *s) -{string p = checked_malloc(strlen(s)+1); - strcpy(p,s); - return p; +string String(const char *source) +{ + size_t length = strlen(source) + 1U; + string copy = checked_malloc(length); + + memcpy(copy, source, length); + return copy; +} + +string toStrUpper(const char *source) +{ + string copy = String(source); + size_t i; + + for (i = 0; copy[i] != '\0'; ++i) { + copy[i] = (char)toupper((unsigned char)copy[i]); + } + return copy; } -string toStrUpper(string s) -{string p = String(s); - int i; - for(i=0;i= '0' && character <= '9') { + return character - '0'; + } + if (character >= 'A' && character <= 'Z') { + return character - 'A' + 10; + } + if (character >= 'a' && character <= 'z') { + return character - 'a' + 10; + } + return -1; } -static int converter(char c) +static int parse_base(const char *source, size_t *digits_start) { - if(c>='0' && c <= '9') return c-'0'; - else if(c>='A' && c<='Z') return c-'A'+10; - return -1; + const char *separator = strchr(source, '#'); + char *end = NULL; + long base; + + if (separator == NULL) { + *digits_start = 0; + return 10; + } + + base = strtol(source, &end, 10); + if (end != separator || base < 2 || base > 16) { + return 0; + } + *digits_start = (size_t)(separator - source + 1); + return (int)base; } -float FloatBaseConverter(string s) +float FloatBaseConverter(const char *source) { - string n = skip(s); - int i=0,len=0,dec=0,j,temp,store; - float ans=0.0; - int b = 0; - for(i=0;n[i] && n[i]!='#';i++) {b = b*10 + (n[i] - '0');} - if(!n[i]) b = 10; - for(i=0;n[i]!='.';i++); - temp = i; - j=1; - for(i=temp+1;n[i] && n[i]!='#';i++) - { - if(converter(n[i])>=b || converter(n[i])==-1) - { - return -1; - } - ans=ans+converter(n[i])/pow(b,j); - j++; - } - j=0; - for(i=temp-1;i>=0 && n[i]!='#';i--) - { - if(converter(n[i])>=b || converter(n[i])==-1) - { - return -1; - } - ans=ans+converter(n[i])*pow(b,j); - j++; - } - return ans; + string number = without_underscores(source); + size_t digits_start; + int base = parse_base(number, &digits_start); + size_t index; + bool fractional = false; + float factor = 1.0F; + float result = 0.0F; + + if (base == 0) { + free(number); + return -1.0F; + } + + for (index = digits_start; number[index] != '\0' && number[index] != '#'; ++index) { + int digit; + + if (number[index] == '.') { + if (fractional) { + free(number); + return -1.0F; + } + fractional = true; + continue; + } + digit = digit_value(number[index]); + if (digit < 0 || digit >= base) { + free(number); + return -1.0F; + } + if (fractional) { + factor /= (float)base; + result += (float)digit * factor; + } else { + result = result * (float)base + (float)digit; + } + } + + free(number); + return result; } -int IntBaseConverter(char* s) +int IntBaseConverter(const char *source) { - string n = skip(s); - int i=0,len=0,dec=0,j,temp,store; - int ans=0; - int b = 0; - for(i=0;n[i] && n[i]!='#';i++) b = b*10 + (n[i] - '0'); - if(!n[i]) b = 10; - len = strlen(n); - if(n[len-1]=='#') len--; - i = 0; - j=0; - for(i=len-1;i>=0 && n[i]!='#';i--) - { - if(converter(n[i])>=b || converter(n[i])==-1) - { - return -1; - } - ans=ans+converter(n[i])*pow(b,j); - j++; - } - return ans; + string number = without_underscores(source); + size_t digits_start; + int base = parse_base(number, &digits_start); + size_t index; + int result = 0; + + if (base == 0) { + free(number); + return -1; + } + + for (index = digits_start; number[index] != '\0' && number[index] != '#'; ++index) { + int digit = digit_value(number[index]); + + if (digit < 0 || digit >= base) { + free(number); + return -1; + } + result = result * base + digit; + } + + free(number); + return result; } diff --git a/util.h b/util.h index 6f400a9..329b30d 100644 --- a/util.h +++ b/util.h @@ -1,16 +1,17 @@ +#ifndef ADA_UTIL_H +#define ADA_UTIL_H + #include +#include +#include typedef char *string; -typedef char bool; -#define TRUE 1 -#define FALSE 0 +void *checked_malloc(size_t size); +string String(const char *source); +string toStrUpper(const char *source); +bool isInt(const char *source); +float FloatBaseConverter(const char *source); +int IntBaseConverter(const char *source); -void *checked_malloc(int); -string String(char *); -string toStrUpper(string); -static int converter(char c); -static string skip(string s); -bool isInt(string); -float FloatBaseConverter(string s); -int IntBaseConverter(string s); +#endif