Rules definition language

For defining expert system rules there is prepared language. This language should be universal enough for defining all your rules needs. If something missing in the language, please let me know through GIT issue in the repository.

Language is processed with parser and lexer based on antlr4, which gives you many advantages like:

  • Syntax controlling
  • Error messages with bad rules format
  • No need to write own Python parser
  • Create expression tree for easy evaluation of each rule

So when you try to write some rules with bad syntax, you don’t need to check it by yourself, parser will tell you about it. Language is described with grammar. In the grammar you should find out, what you can write. Grammar definition is written in atnrl4 language.

Grammar

grammar Rules;

/* Lexical rules */

// Language symbols definition
IF   : 'IF';
THEN : 'THEN';
WITH : 'WITH';

AND : 'AND' ;
OR : 'OR';

TRUE: 'TRUE';
FALSE: 'FALSE';

// Assign operator
ASSIGN : ':=';

// Comparison Operators
GE : '>=';
GT : '>';
LE : '<=';
LT : '<';
EQ : '==';
NE : '!=';

// Parenthese for operator order definition
LPAREN: '(';
RPAREN : ')';

// Parenthese for uncertainty
LSPAREN : '[';
RSPAREN : ']';

// Data holder mark
DHM : '*';

// Float number
DECIMAL : '-'?[0-9]+('.'[0-9]+)? ;

// Identifier (Characters, undescrope and number)
IDENTIFIER : [a-zA-Z_][a-zA-Z_0-9]* ;

// Each rule ending with semicolon
SEMI : ';' ;

// Hashtag comments
COMMENT : '#' .+? ('\n'|EOF) -> skip ;

// Skip processing white spaces
WS : [ \r\t\u000C\n]+ -> skip ;


/* Grammar rules */

rules_set : single_rule* EOF;

// Single rule format
single_rule: IF condition THEN conclusion SEMI | IF condition THEN conclusion WITH DECIMAL SEMI;

condition: left_logical_expr;
conclusion: right_logical_expr;

// Condition format
left_logical_expr
 : left_logical_expr AND left_logical_expr  # LogicalExpressionAnd
 | left_logical_expr OR left_logical_expr   # LogicalExpressionOr
 | function_expr                            # ComparisonExpression
 | function_expr LSPAREN DECIMAL RSPAREN    # ComparisonExpression
 | LPAREN left_logical_expr RPAREN          # LogicalExpressionInParen
 ;

// One condition expression format
function_expr
            : IDENTIFIER DHM? args
            | IDENTIFIER DHM? args comp_operator DECIMAL
            | IDENTIFIER DHM?
            | IDENTIFIER DHM? comp_operator DECIMAL
            | IDENTIFIER DHM? comp_operator IDENTIFIER
            | IDENTIFIER DHM? args comp_operator IDENTIFIER
            | (TRUE | FALSE);

args : arg args | arg;
arg : DECIMAL | IDENTIFIER;
comp_operator : GT | GE | LT | LE | EQ | NE;

// Conclusion format
right_logical_expr
 : right_logical_expr AND right_logical_expr    # RLogicalExpressionAnd
 | LPAREN right_logical_expr RPAREN             # RLogicalExpressionInParen
 | r_function_expr                              # RLogicalExpression
 ;

// One conclusion expression format
r_function_expr
              : IDENTIFIER
              | IDENTIFIER args
              | IDENTIFIER args ASSIGN DECIMAL
              | IDENTIFIER args ASSIGN IDENTIFIER
              | IDENTIFIER ASSIGN DECIMAL
              | IDENTIFIER ASSIGN IDENTIFIER;

Examples

Here you can find some examples, about what can be written in the language. It is make no sense to write all possibilities, because there are infinity number of possibilities. It is recommended to look at grammar definition and lear what is possible by that. Here you can find some inspiration. All examples are correct so you can copy them to rule file and execute inference, but you probably don’t get any output, because of missing action definition.

Rule with no condition

IF TRUE THEN build_base_random;

Rule with simple condition

IF player_dont_have_base THEN build_base_random;

Parametrized expressions

IF player_dont_have_base THEN build_base 2 2;

Expression with comparision

IF base_count == 0 THEN build_base 2 2;

Expression with comparision and arguments

IF object_count base == 0 THEN build_base 2 2;

Expression with data holder mark and arguments

IF free_position* mountain THAT build_archer free_position;

Logical operators in condition

IF object_count base == 0 AND terrain 2 2 == forest THEN build base 2 2;
IF object_count archer < 2 OR object_count knight < 2 THEN spawn_archer 1 3;

Logical operators in conclusion

IF object_count archer < 2 THEN spawn_archer 1 3 AND spawn_archer 5 5;

Parentheses for logical operators order

IF player_have_base AND ( object_count archer < 2 OR object_count knight < 2 ) THEN spawn_archer 1 3;

Defining value in conclusion

IF object_count archer > 10 THEN strength := 10;
IF object_count archer > 10 THEN strength := high;

Probability of whole rule

IF object_count archer > 10 THEN strength := 10 WITH 0.50;

Probability of condition expressions

IF object_count archer > 10 [0.25] AND object_count knight > 5 [0.8] THEN strength := 10;