DBN Language Parser Definitions
Use this skill for DBN SQL/PSQL parser grammar XML work, especially files named *_parser_elements.xml and the shared DTD at src/main/java/com/dbn/language/common/definition/language-parser-elements.dtd.
When a specification provides a syntax diagram or linked diagram-text definition, treat the diagram as the authoritative grammar source. Prefer it over reconstructing syntax from prose descriptions; use prose for semantics, restrictions, and examples.
When reading Oracle diagram text, distinguish diagram grouping from SQL punctuation before adding a PARENTHESES wrapper. Parentheses that merely group alternatives or a path in the railroad diagram are structural and must not become lexical SQL parentheses. Add a PARENTHESES wrapper only when the diagram shows literal ( and ) nodes in the token flow, or when the supplied syntax/example clearly requires those characters. Whitespace in extracted diagram text is only a secondary clue: spaced forms such as ( MOUNT ... ) often denote grouping, while tight forms such as (column, ...) often denote SQL syntax, but never rely on spacing alone. Confirm against the diagram image and verified examples; if the diagram is unreadable or ambiguous, do not infer the grammar—ask for the diagram text or an image.
Quick Workflow
- Inspect the target dialect XML and at least one equivalent construct in sibling dialects before editing.
- Read references/parser-elements.md when you need element semantics, allowed structures, validation rules, or examples.
- For dialect syntax work, use the official links in references/parser-elements.md
Specification References. - For token ids or lexer/token-list changes, inspect the
modules/dbn-devlanguage tooling before inventing names. - Keep XML changes declarative and local to the grammar construct requested. Do not refactor unrelated statement definitions while adding one clause or alternative.
- Do not maintain numeric parser-element ids by hand. When adding or restructuring definitions, omit
idattributes from the affected new/changed elements; the parser builder/reindexer assigns ids. Unchanged existing ids may remain until regeneration. - Keep dbn-dev token registries sorted, de-duplicated, and free of blank token entries.
- Keep parser XMLs pointed at the shared DTD:
<!DOCTYPE element-defs SYSTEM "../../../common/definition/language-parser-elements.dtd">
- If the XML uses a new tag, attribute, wrapper template, or child relationship, update
language-parser-elements.dtdin the same change. - Validate edited parser XMLs with
xmllint --noout --valid <files>when available.
Important Files
- SQL dialect grammars:
src/main/java/com/dbn/language/sql/dialect/*/*_sql_parser_elements.xml - PSQL dialect grammars:
src/main/java/com/dbn/language/psql/dialect/*/*_psql_parser_elements.xmland Oracleoracle_plsql_parser_elements.xml - Shared DTD:
src/main/java/com/dbn/language/common/definition/language-parser-elements.dtd - Parser extension DTD:
src/main/java/com/dbn/language/common/definition/language-parser-elements-ext.dtd - Language tooling module:
modules/dbn-dev/src/main/java/com/dbn/dev/language - Parser extension generator:
modules/dbn-dev/src/main/java/com/dbn/dev/language/LanguageSpecificationParserExtensionBuilder.java - Source token registries/lists for generated token ids:
modules/dbn-dev/src/main/resources/languageand the relevantdb_*_keywords/function/datatype/parameter registries - Parser token XMLs:
src/main/java/com/dbn/language/**/dialect/*/*_parser_tokens.xmlare generated artifacts. Do not add generated tokens directly there; update the maintainedmodules/dbn-devregistry/source list and let tooling regenerate the token XML. - Parser/highlighter flex sources:
src/main/java/com/dbn/language/**/dialect/*/*_parser.flexand*_highlighter.flexare partially generated: hand-written lexer rules outside marker blocks may be edited, but generatedMARKER_*blocks should be refreshed through tooling. - Parser extension XMLs:
src/main/java/com/dbn/language/**/dialect/*/*_parser_elements_ext.xml(generated ambiguity-resolution metadata) - Generated flex lexer Java files: generated outputs; do not edit directly
- Runtime element definitions:
src/main/java/com/dbn/language/common/element/util/ElementTypeDefinition.java - Core runtime model:
src/main/java/com/dbn/language/common/element/impl/*ElementType.java - Parser implementations:
src/main/java/com/dbn/language/common/element/parser/impl/*ElementTypeParser.java
Editing Guidance
- Prefer explicit child elements for complex grammar. Use
tokens="A,B,C"only for simple fixed token sequences or alternatives already following that style. one-ofchildren are alternatives; child-leveloptional="true"is not supported there and the runtime warns about it. Put optionality on theone-ofitself or wrap the optional alternative in a parentsequence.- Flatten redundant nested
one-ofalternatives when they represent the same alternatives at the same grammar position. Keep a nestedone-ofonly when it is part of a distinctsequence/subproduction or preserves a meaningful grouping boundary. iterationandwrappermust each contain exactly one child. Put repeated or wrapped multi-part constructs inside a single childsequence.- For deeply similar optional clause sequences that create parser ambiguity, preserve the established workaround of representing the sequence as an
iterationover aone-ofof the optional elements. Do not replace these intentional ambiguity workarounds with a plain optional sequence during unrelated grammar edits. - Use semantic identifier nodes (
object-def,object-ref,alias-def,alias-ref,variable-def,variable-ref) when the parsed token should participate in resolve, rename, structure, or object context behavior. - Prefer exactly one semantic
SUBJECTobject per statement: normally the object being created, altered, dropped, or otherwise acted upon. - Add
original-nameonly when the semantic name differs from the element or referenced definition name. Do not add redundantoriginal-nameattributes merely to repeat the ref-id name. - Preserve undefined statement or helper placeholders when the surrounding grammar expects them. Do not delete placeholders or replace them with guessed definitions unless that syntax is explicitly being defined.
- Use
element ref-id="..."to reuse a namedelement-def; use inlinesequence,one-of,iteration, orwrapperfor local grammar structure. - Name
element-defids as lowercase underscored versions of the specification term, for examplequery_specification,select_statement,group_by_clause. - Write
descriptionas the human-readable version of the element id/specification term. If the description includes SQL keywords from that grammar block, uppercase those keywords, for exampleSELECT statement,GROUP BY clause. - Mark statement structures that qualify as clauses with
attributes="CLAUSE", for examplefrom_clause,where_clause,group_by_clause, andhaving_clause. The attribute is intended for formatting behavior even where it is not yet actively used. custom="true"marks intentional helper definitions, usually repetitive structures defined once and reused from several grammar positions. They do not have to map directly to a SQL specification term, but should still be named and described clearly.- When several root statements share the same leading keyword, add an artificial
custom="true"grouping element such ascreate_statement,drop_statement,alter_statement,transaction_control_statement, oraccess_control_statementwith aone-ofof the concrete statement roots, then reference that group from the block/root statement list. - Add section comments for main statement roots in large grammar blocks, for example
<!-- ========= create table ========= -->, while keeping helper definitions under the nearest relevant section. - When alternatives are all identifier-name shapes, prefer one
qualified-identifierwith multiplevariantchildren over aone-ofof separate*_nameelements or individual identifier refs. This applies to object-type alternatives such asTABLEvsDOMAINand identifier-category alternatives such asobject-ref DATASETvsalias-ref DATASET. - Model schema-qualified objects with a
qualified-identifiervariant containing an optionalSCHEMAreference followed by the semantic object reference/definition. Audit every occurrence of the object, includingDROPsubjects,ONtargets, partition/inheritance parents, callback functions, and index references; do not assume only the primary statement subject needs qualification. qualified-identifierfalls back toCHR_DOTas its separator. Omit a redundantseparator="CHR_DOT"attribute unless a construct genuinely requires a different separator.- Keep names unqualified when the dialect scopes them through a surrounding object, such as column names in table definitions or DML target clauses, constraint names, policy names, rule names, and trigger names. Query column references should use the existing dataset-alias and schema/table/column variants; leave broader expression qualification to the expression grammar.
- Treat
variant original-name="..."as definition-only metadata for documenting specification-name deviations; do not add Java/runtime behavior for it unless explicitly requested. - Use the generated parser-extension metadata for ambiguity resolution; keep the grammar tree declarative and unchanged by ambiguity handling.
- Keep overlapping alternatives as raw grammar children; generated extension look-ahead resolves them without rewriting the grammar tree.
- Treat
LanguageSpecificationParserExtensionBuilderas the current ambiguity model. It scans raw grammar trees, builds token look-ahead tries, and emitsone-of-extensionnodes into*_parser_elements_ext.xml. Runtime parsing then narrows candidates by deepest matching trie node before trying normal child parsers, keeping the grammar tree intact. - If a
one-ofambiguity is unresolved, first inspect the generated extension XML and the candidate token prefixes before changing grammar structure. Only edit parser element XML or extension tooling source; generated*_parser_elements_ext.xmlfiles should normally be refreshed by tooling. - When fixing a parser-definition gap, inspect the surrounding grammar construct and its sibling forms for related omissions, including alternate operators, optional clauses, delimiters, nesting, and lexer token-category collisions. Make the adjacent completeness fixes in the same pass when they are clearly part of the same syntax family.
- Preserve backward compatibility when refining an existing element. Existing branches may represent legacy Oracle syntax, so do not replace or remove them merely because the current specification shows a newer form. Add the documented modern branch alongside retained legacy branches; remove an existing alternative only when the user explicitly requests it or authoritative documentation confirms it is no longer supported and compatibility is intentionally being dropped.
- Use token id prefixes from
LanguageSpecificationLexerBuilder.TokenDefinition, not guesses:KW_keywords,FN_functions,DT_datatypes,PRM_parameters,EX_exceptions. Before introducing any token, search every relevant token registry/category. Never duplicate a word across keyword, function, datatype, or parameter registries: the lexer can match a word only once. If an existing token needs a different presentation at a grammar site, useflavorthere instead. Register genuinely new token keys in the maintained registry/source list before using them in parser element XML, and keep registries alphabetically sorted. Empty registries should generate no tokens; if tooling emitsPRM_,EX_, or empty lexer rules from blank files, fix blank-line handling in dbn-dev and let the developer run the tooling. Treattoken text="..." type-id="IDENTIFIER"as legacy/deprecated for known SQL words: register a real keyword or use the existing token id. Common shared tokens such asCHR_*,OPR_*,IDENTIFIER,STRING,NUMBER, and comments come from the shared/parser token XMLs. - If the same word can behave as different token categories, define it in the most common/generated family and use
flavorat parser-use sites to qualify the role, for example<token type-id="DT_INTERVAL" flavor="keyword" />. Do not duplicate the same word across registries: the lexer can match a word only once, so duplicate generated rules clash instead of producing context-sensitive token categories. - Treat
attributes,branch,branch-check,version,formatting-*, andoptional-wrappingas runtime behavior, not comments.
Expression Grammar Patterns
Expression grammar is usually the most fragile part of each SQL dialect because optional parentheses, broad operator chains, predicates, functions, subqueries, and lists all overlap. Keep the dialect close to the vendor production names, but use small custom="true" helpers where the parser needs a delimiter-safe shape.
- Prefer the vendor's expression tiers where they exist, such as
expr,boolean_primary,predicate,bit_expr, andsimple_expression. Add custom helper elements only for repeated parser conveniences or delimiter-sensitive sub-productions. - For binary operator chains where the head and repeated item are the same grammar unit, prefer a single separator-driven
iterationover that unit. Avoid a separate head plus tail iteration unless the operator token is inside the repeated child sequence; otherwise the second expression can be parsed as an adjacent expression without a real operator. - Broad operator lists are useful for parser resilience, but they can steal grammar delimiters. Use scoped helper expressions that omit only the problematic delimiter, for example a
between_exprthat excludesANDfor the lower bound, rather than weakening the globalexpr. - Model special expression atoms as simple-expression alternatives when that matches the specification shape: parameter markers such as
?, user/system/bind variables emitted by the lexer, row constructors,{identifier expr}, ODBC escapes, interval expressions, current temporal expressions, and quantified subquery operands such as{ALL | ANY} (subquery). - Put concrete callable/function alternatives before generic qualified identifiers. If a function token can also satisfy an identifier sequence, the generic branch can consume the name and leave the opening parenthesis orphaned.
- Use
optional-wrapping="PARENTHESES"on expression tiers and list elements that can legally be parenthesized. Prefer optional wrappers over duplicating parenthesized alternatives, unless parentheses introduce a distinct production such as a subquery, row/list constructor, or function argument list. - Add wrapping cautiously and locally. Changing the expression tree shape just to handle parentheses tends to break unrelated arithmetic, predicate, and function cases.
- Keep delimiter-sensitive constructs separate from generic expression chains:
BETWEEN ... AND ...,IN (expr_list | subquery),ANY/ALL (subquery), interval units afterINTERVAL, and expression lists insideINSERT,LOAD DATA, function calls, and row constructors. - When a statement embeds query expressions, check branch ordering around standalone query forms. For example, regular
INSERT ... VALUES (...)orREPLACE ... VALUES (...)alternatives should win before broader standaloneVALUESquery/table-value-constructor branches. - After expression changes, run a focused dialect corpus before broad validation. Include arithmetic precedence chains, nested parentheses, shift/bit operators, intervals,
BETWEEN,INlists,ANY/ALLsubqueries,CASE, built-in and qualified functions, window functions,SELECT ... INTO,INSERT ... VALUES, andLOAD DATA ... SETexpressions.
Parser Extension Metadata
The extension builder generates look-ahead metadata for ambiguous one-of branches. Keep overlapping alternatives as raw grammar children and inspect the generated extension XML when diagnosing candidate-selection problems. Do not encode ambiguity resolution through grammar rewrites or definition-specific checks.
Tooling Runs
- Treat generated parser token, flex, and extension artifacts as tooling outputs. Update their maintained source definitions and leave regeneration to the developer unless explicitly requested.
Structural Constraints
iterationmust have exactly one child element. The runtime throws for zero or multiple children.wrappermust have exactly one child element. The runtime throws for zero or multiple children.qualified-identifiercontains one or morevariantchildren; eachvariantcontains token/identifier leaf definitions.element-def,sequence, andone-ofcan contain multiple grammar children.- A single-child
one-ofis acceptable when it is intentionally reserving an alternatives slot, such as a statement list that will gain more statement kinds later. - When a repeated or wrapped grammar unit has several parts, introduce one child
sequenceand put the parts inside it.
Validation
Use direct validation after adding or changing a DOCTYPE-aware parser XML:
xmllint --noout --valid src/main/java/com/dbn/language/sql/dialect/oracle/oracle_sql_parser_elements.xml
For broad schema changes, validate all parser element XMLs:
xmllint --noout --valid $(rg --files -g '*_parser_elements.xml' src/main/java/com/dbn/language)