Overview
| Comment: | [doc] rename syntax.txt -> syntax.md |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk | doc |
| Files: | files | file ages | folders |
| SHA3-256: |
f39d6336671cbf232084877d80791e23 |
| User & Date: | olr on 2025-12-14 15:38:55 |
| Other Links: | manifest | tags |
Context
|
2025-12-14
| ||
| 21:46 | [fr] mise à jour des dictionnaires Leaf check-in: 6bd2351227 user: olr tags: trunk, fr | |
| 15:38 | [doc] rename syntax.txt -> syntax.md check-in: f39d633667 user: olr tags: trunk, doc | |
|
2025-12-13
| ||
| 20:50 | [fr][build] contrôle des entrées check-in: 605502dcf5 user: olr tags: trunk, fr, build | |
Changes
Renamed and modified doc/syntax.txt [5966d37107] to doc/syntax.md [249c794066].
|
| | < | < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Writing rules for Grammalecte Note: This documentation is a __draft__. Information may be obsolete or incomplete. ## FILES REQUIRED The rules file for your language must be named `rules.grx` in the folder `gc_lang/<lang>/`. The settings file must be named `config.ini`. These files are simple UTF-8 text files. ## PRINCIPLES Grammalecte is a bi-passes grammar checker engine. On the first pass, the engine checks the text paragraph by paragraph. On the second pass, the engine check the text sentence by sentence. You may alter how sentences are split by removing punctuation marks during the first pass. |
| ︙ | ︙ | |||
38 39 40 41 42 43 44 | * a list of actions A token rule is defined by: * rule name * [optional] priority number * one or several lists of tokens | | | | < | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
* a list of actions
A token rule is defined by:
* rule name
* [optional] priority number
* one or several lists of tokens
* a list of actions (an action is active only if the option defined by user or config is active)
Token rules must be defined within a graph.
Each graph is defined within the second pass with the command:
@@@@GRAPH: graph_name|graph_code
A graph ends when another graph is defined or when is found the command:
@@@@END_GRAPH
There is no limit to the number of actions and the type of actions a rule can
launch. Each action has its own condition to be triggered.
There are several kinds of actions:
* Error warning, with a message, and optionally suggestions, and optionally an URL
* Text transformation, modifying internally the checked text
* Disambiguation action
* [second pass only] Tagging token
* [second pass only] Immunity rules
On the first pass, you can only write regex rules.
On the second pass, you can write regex rules and token rules. All token rules must be written within a graph.
## REGEX RULE SYNTAX
__LCR/option(rulename)!priority__
pattern
<<- condition ->> error_suggestions && message_error|URL
<<- condition ~>> text_rewriting
<<- condition =>> commands_for_disambiguation
...
|
| ︙ | ︙ | |||
108 109 110 111 112 113 114 | > `i` case insensitive > `s` case sensitive > `u` uppercase allowed for lowercase characters | | | < | < < < | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
> `i` case insensitive
> `s` case sensitive
> `u` uppercase allowed for lowercase characters
> > i.e.: "Word" becomes "W[oO][rR][dD]"
Examples: `[i]`, `<s]`, `[u>`, `<s>`
User option activating/disactivating is possible with an option name placed
just after the LCR flags, i.e.:
__[i]/option1(rulename1)__
__[u]/option2(rulename2)__
__[s>/option3(rulename3)__
__<u>(rulename4)__
__<i>(rulename5)__
Each rule name must be unique.
Example. Recognize and suggest missing hyphen and rewrite internally the text
with the hyphen:
__[s](rulename)__
foo bar
<<- ->> foo-bar && Missing hyphen.
<<- ~>> foo-bar
### Simple-line or multi-line rules
Rules can be break to multiple lines by leading spaces.
You should use 4 spaces.
Examples:
__<s>(rulename)__ pattern <<- condition ->> replacement && message
__<s>(rulename)__
pattern
<<- condition ->> replacement
&& message
<<- condition ->> suggestion && message
<<- condition ~>> text_rewriting
<<- =>> disambiguation
### Whitespaces at the border of patterns or suggestions
Example: Recognize double or more spaces and suggests a single space:
__<s>(rulename)__ " +" <<- ->> " " && Remove extra space(s).
Characters `"` protect spaces in the pattern and in the replacement text.
### Pattern groups and back references
It is usually useful to retrieve parts of the matched pattern. We simply use
parenthesis in pattern to get groups with back references.
Example. Suggest a word with correct quotation marks:
\"(\w+)\" <<- ->> “\1” && Correct quotation marks.
Example. Suggest the missing space after the signs `!`, `?` or `.`:
\b([?!.])([A-Z]+) <<- ->> \1 \2 && Missing space?
Example. Back reference in messages.
(fooo) bar <<- ->> foo && “\1” should be:
### Group positioning codes for JavaScript:
There is no way in JavaScript to know where a captured group starts and ends. To avoid misplacement, regex rules may specify group positioning codes which indicate to the grammar checker where is the position of the captured groups.
A group positioning code always begins by `@@`. If there is several codes, they are separated by a comma `,`.
|
| ︙ | ︙ | |||
197 198 199 200 201 202 203 |
** something somewhere after previous group
Examples:
([A-ZÉÈÂÎ][\w-]+) [A-ZÉÈÂ]([.]) ([A-ZÉÈÂ][\w-]+) @@0,*,$
" ([?!;])" @@1
| < < | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
** something somewhere after previous group
Examples:
([A-ZÉÈÂÎ][\w-]+) [A-ZÉÈÂ]([.]) ([A-ZÉÈÂ][\w-]+) @@0,*,$
" ([?!;])" @@1
### Pattern matching
Repeating pattern matching of a single rule continues after the previous matching, so instead of general multiword patterns, like
(\w+) (\w+) <<- some_check(\1, \2) ->> \1, \2 && foo
use
(\w+) <<- some_check(\1, word(1)) ->> \1, && foo
## TOKEN RULES
Token rules must be defined within a graph.
### Token rules syntax
__rulename!priority__
list_of_tokens
|
| ︙ | ︙ | |||
246 247 248 249 250 251 252 | Tokens can be defined in several ways: * Value (the text of the token). Examples: `word`, `<start>`, `<end>`, `,`. * Lemma: `>lemma`. * Regex: `~pattern`, `~pattern¬antipattern`. * Regex on morphologies: `@pattern`, `@pattern¬antipattern`. * Tags: `/tag`. | | | | | < | < | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
Tokens can be defined in several ways:
* Value (the text of the token). Examples: `word`, `<start>`, `<end>`, `,`.
* Lemma: `>lemma`.
* Regex: `~pattern`, `~pattern¬antipattern`.
* Regex on morphologies: `@pattern`, `@pattern¬antipattern`.
* Tags: `/tag`.
* Metatags: `*METATAG`. Examples: `*WORD`, `*NUM`, `*SIGN`, etc.
* Jump over token: `<>`
Selection of tokens: `[value1|value2|>lemma|~pattern|@pattern|*META|/tag|…]`
Conditional token: `?token¿`
Conditional selection of token: `?[token1|token2|…]¿`
### Token references
Positive references are defined by a positive integer (> 0). Examples: `\1`, `\2`, `\3`, etc.
If there is at least one token set between parenthesis, these numbers refer to tokens between parenthesis, ignoring all others.
If there is no token between parenthesis, these numbers refer to tokens found in order defined by the rule triggered.
Negative references are defined by a negative integer (< 0). Examples: `\-1`, `\-2`, `\-3`, etc.
These numbers refer to the tokens beginning by the last one found by the rule triggered.
Examples:
tokens: alpha beta gamma delta epsilon
positive refs: 1 2 3 4 5
negative refs: -5 -4 -3 -2 -1
tokens: alpha (beta) gamma (delta) epsilon
positive refs: 1 2
negative refs: -5 -4 -3 -2 -1
tokens: alpha (beta) ?gamma¿ (delta) epsilon
positive refs: 1 2
negative refs: (-5/-4) (-4/-3) (-3/none) -2 -1
## CONDITIONS
Conditions are Python expressions, they must return a value, which will be
evaluated as boolean. You can use the usual Python syntax and libraries.
With regex rules, you can call pattern subgroups via `\1`, `\2`… `\0` is the full pattern.
Example:
these (\w+)
<<- \1 == "man" -1>> men && Man is a singular noun.
You can also apply functions to subgroups like: `\1.startswith("a")` or `\3.islower()` or `re.search("pattern", \2)`.
With token rules, you can also call each token with their reference, like `\1`, `\2`... or `\-1`, `\-2`...
Example:
foo [really|often|sometimes] bar
<<- ->> \1 \-1 && We say “foo bar”.
### Functions for regex rules
`word(n)`
> Catches the nth next word after the pattern (separated only by white spaces).
> Returns None if no word caught
|
| ︙ | ︙ | |||
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | > Returns True if <tag> is found any token after the nth tag. ### Functions for regex and token rules `__also__` > Returns True if the previous condition returned True. > Example: `<<- __also__ and condition2 ->>` `__else__` > Returns False if the previous condition returned False. > Example: `<<- __else__ and condition2 ->>` `option(option_name)` > Returns True if <option_name> is activated else False Note: the analysis is done on the preprocessed text. | > > | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | > Returns True if <tag> is found any token after the nth tag. ### Functions for regex and token rules `__also__` > Returns True if the previous condition returned True. > Example: `<<- __also__ ->>` > Example: `<<- __also__ and condition2 ->>` `__else__` > Returns False if the previous condition returned False. > Example: `<<- __else__ ->>` > Example: `<<- __else__ and condition2 ->>` `option(option_name)` > Returns True if <option_name> is activated else False Note: the analysis is done on the preprocessed text. |
| ︙ | ︙ | |||
397 398 399 400 401 402 403 |
colour <<- sCountry == "US" ->> color && Use American English spelling.
`sContext`
> The name of the application running (Python, Writer…)
| < | | | | | | < | < < | 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 |
colour <<- sCountry == "US" ->> color && Use American English spelling.
`sContext`
> The name of the application running (Python, Writer…)
## ACTIONS
There are 5 kinds of actions:
1. Suggestions. The grammar checker suggests corrections.
2. Text processor. A internal process to modify the text internally. This is used to simplify grammar checking.
* text rewriting
* text deletion
* token rewriting
* token merging
* token deletion
3. Disambiguation. Select, exclude or define morphologies of tokens.
4. Tagging. Add information on token.
5. Immunity. Prevent suggestions to be triggered.
### Positioning
Positioning is valid for suggestions, text processing, tagging and immunity.
By default, rules apply on the full text triggered. You can shorten the
effect of rules by specifying a back reference group of the pattern or token references.
Instead of writing `->>`, write `-n>>` n being the number of a back reference
group. Actually, `->>` is similar to `-0>>`.
Example:
(ying) and yang <<- -1>> yin && Did you mean:
__[s]__ (Mr.) [A-Z]\w+ <<- ~1>> Mr
**Comparison**
Rule A:
ying and yang <<- ->> yin and yang && Did you mean:
Rule B:
(ying) and yang <<- -1>> yin && Did you mean:
With the rule A, the full pattern is underlined:
ying and yang
^^^^^^^^^^^^^
With the rule B, only the first group is underlined:
ying and yang
^^^^
### Errors and suggestions
The command to suggest something is: `->>`.
#### Multiple suggestions
|
| ︙ | ︙ | |||
490 491 492 493 494 495 496 |
Suggestions started by an equal sign are Python string expressions extended with possible back references and named definitions:
Example:
<<- ->> ='"' + \1.upper() + '"' && With uppercase letters and quotation marks
<<- ~>> =\1.upper()
| < | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
Suggestions started by an equal sign are Python string expressions extended with possible back references and named definitions:
Example:
<<- ->> ='"' + \1.upper() + '"' && With uppercase letters and quotation marks
<<- ~>> =\1.upper()
### Text rewriting
**WARNING**: The replacing text must be shorter than the replaced text or have the same length. Breaking this rule will misplace following error reports.
You have to ensure yourself the rules comply with this constraint, the text processor won’t do it for you.
The command for text rewriting is: `~>>`.
|
| ︙ | ︙ | |||
525 526 527 528 529 530 531 |
You can use positioning with text rewriting actions.
Mr(. [A-Z]\w+) <<- ~1>> *
You can also call Python expressions.
__[s]__ Mr. ([a-z]\w+) <<- ~1>> =\1.upper()
| < | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 |
You can use positioning with text rewriting actions.
Mr(. [A-Z]\w+) <<- ~1>> *
You can also call Python expressions.
__[s]__ Mr. ([a-z]\w+) <<- ~1>> =\1.upper()
The text processor is useful to simplify texts and write simpler checking
rules.
For example, sentences with the same grammar mistake:
These “cats” are blacks.
|
| ︙ | ︙ | |||
581 582 583 584 585 586 587 |
This is useful if at first pass you write rules to check successive whitespaces.
@ are automatically removed at the second pass.
You can also replace any text as you wish.
Mister <<- ~>> Mr
(Mrs?)[.] <<- ~>> \1
| < | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 |
This is useful if at first pass you write rules to check successive whitespaces.
@ are automatically removed at the second pass.
You can also replace any text as you wish.
Mister <<- ~>> Mr
(Mrs?)[.] <<- ~>> \1
### Disambiguation
When the grammar checker analyses a token with `morph()`, before requesting the POS tags to the dictionary, it checks if there is a stored marker for the position of the token. If a marker is found, it uses the stored data and don’t make request to the dictionary.
The command for disambiguation is: `=>>`. No positioning allowed.
|
| ︙ | ︙ | |||
641 642 643 644 645 646 647 | **Only for token rules**. A immunity rule set a flag on token(s) who are not supposed to be considered as an error. If any other rules find an error, it will be ignored. If an error has already been found, it will be removed. Example: `!2>>` means no error can be set on the second token. Example: `!>>` means all tokens will be considered as correct. The immunity rules are useful to create simple antipattern that will simplify writing of other rules. | < | | 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 | **Only for token rules**. A immunity rule set a flag on token(s) who are not supposed to be considered as an error. If any other rules find an error, it will be ignored. If an error has already been found, it will be removed. Example: `!2>>` means no error can be set on the second token. Example: `!>>` means all tokens will be considered as correct. The immunity rules are useful to create simple antipattern that will simplify writing of other rules. ## OTHER COMMANDS ### Comments Lines beginning with `#` are comments. ### End of parsing |
| ︙ | ︙ | |||
668 669 670 671 672 673 674 |
Usage: `{name}` will be replaced by its definition
Example:
DEF: word_3_letters \w\w\w+
DEF: uppercase_token ~^[A-Z]+$
DEF: month_token [January|February|March|April|May|June|July|August|September|October|November|december]
| | | | 651 652 653 654 655 656 657 658 659 660 661 662 |
Usage: `{name}` will be replaced by its definition
Example:
DEF: word_3_letters \w\w\w+
DEF: uppercase_token ~^[A-Z]+$
DEF: month_token [January|February|March|April|May|June|July|August|September|October|November|december]
({word_3_letters}) (\w+) <<- condition ->> suggestion && message|URL
{uppercase_token} {month_token}
<<- condition ->> message && message|URL
|