diff --git a/README.md b/README.md index a881b00..777cc7e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,115 @@ A rule parser for MicroWorld ## Usage -FIXME +Main entry point is (parse-rule ), where string takes a form detailed +in **grammar**, below. If the rule is interpretted correctly the result will +be a Clojure anonymous function; if the rule is not interpretted, currently nil +is returned and there's no helpful error message. + +### Generated function and evaluation environment + +The generated function is a function of two arguments + +* **cell** a cell in a world as defined in mw-engine.world, q.v.; +* **world** the world of which that cell forms part. + +It returns a new cell, based on the cell passed. + +Actions of the rule will (can only) modify properties of the cell; there are two +properties which are special and SHOULD NOT be modified, namely the properties +**x** and **y**. Currently there is no policing that these properties are not +modified. + +### Grammar + +A rule comprises: + +* if *conditions* then *actions* + +#### Conditions + +where *conditions* is: + +* *condition* + +or +* *condition* and *conditions* + +A *condition* is one of: + +* *property* is *value* +* *property* is not *value* +* *property* is in *values* +* *property* is not in *values* +* *property* is more than *numeric-value* +* *property* is less than *numeric-value* +* *number* neighbours have *property* equal to *value* +* more than *number* neighbours have *property* equal to *value* +* fewer than *number* neighbours have *property* equal to *value* + +#### Actions + +Where *actions* is: + +* *action* + +or +* *action* and *actions* + +and *action* is: + +* *property* should be *value* + +#### Properties + +In the above, *property* is the name of any property of a cell. Any alpha-numeric +string of characters can form the name of a property. Actions should NOT refer +to the reserved properties **x** and **y**. + +#### Values in Conditions + +Values in conditions and actions are considered slightly differently. In a +condition, a value is one of + +* *symbolic-value* +* *numeric-value* + +The '...more than...' and '...less than...' conditions imply a *numeric-value*. +Thus "if altitude is more than fertility..." is interpreted as meaning "if the value +of the property of the current cell called 'altitude' is greater than the value +of the property of the current cell called 'fertility'", whereas the apparently +similar condition 'if altitude is fertility...' is interpreted as meaning +"if the value of the property of the current cell called 'altitude' is the symbol +'fertility'". + +Thus *symbolic-value* is any sequence of alphanumeric characters, whereas +*numeric-value* is one of: + +* *number* +* *property* + +and *number* is any sequence of the decimal digits 0...9, the minus character +'-' and the period character '.', provided that the minus character can only be +in the first position, and the period character can only appear once. + +#### Values in Actions + +A *value* in an action is one of + +* *symbolic-value* +* *arithmetic-value* +* *number* + +where *arithmetic-value* is: + +* *property* *operator* *numeric-value* + +and *operator* is one of the simple arithmetic operators '+', '-', '*' and '/'. + +### Shorthand + +Note that '...members are...' is equivalent to '...members have state equal to...', +and 'some neighbours...' is equivalent to 'more than 0 neighbours...' ## License diff --git a/src/mw_parser/core.clj b/src/mw_parser/core.clj index 7ef2a66..655fa98 100644 --- a/src/mw_parser/core.clj +++ b/src/mw_parser/core.clj @@ -7,13 +7,14 @@ ;; * "if deer is more than 1 and wolves is more than 1 then deer should be deer - wolves" ;; * "if state is grassland and 4 neighbours have state equal to water then state should be village" ;; * "if state is forest and fertility is between 55 and 75 then state should be climax" -;; * "if 6 neighbours have state equal to water then state should be fishery" +;; * "if 6 neighbours have state equal to water then state should be village" +;; * "if state is in grassland or pasture or heath and 4 neighbours are water then state should be village" ;; ;; It should also but does not yet parse rules of the form: ;; * "if state is forest or state is climax and some neighbours have state is fire then 3 in 5 chance that state should be fire" ;; * "if state is pasture and more than 3 neighbours have state equal to scrub then state should be scrub" -;; * "if state is in grassland or pasture or heath and 4 neighbours are water then state should be village" +;; * ;; ;; it generates rules in the form expected by mw-engine.core @@ -79,9 +80,8 @@ "Parse a list of values from among these `tokens`. If `expect-int` is true, return an integer or something which will evaluate to an integer." [[OR token & tokens] expect-int] - (println OR) (cond (member? OR '("or" "in")) - (let [[others remainder] (parse-disjunct-value2 tokens expect-int)] + (let [[others remainder] (parse-disjunct-value tokens expect-int)] [(cons (cond expect-int (first (parse-simple-value (list token) true)) @@ -171,9 +171,15 @@ (let [[value & remainder] rest] (gen-neighbours-condition '= quantity :state value remainder)) (= have-or-are "have") - (let [[property EQUAL TO value & remainder] rest] - (cond (and (= EQUAL "equal") (= TO "to")) - (gen-neighbours-condition '= quantity property value remainder))))))) + (let [[property comp1 comp2 value & remainder] rest] + (cond (and (= comp1 "equal") (= comp2 "to")) + (gen-neighbours-condition '= quantity property value remainder) +;; (and (= comp1 "more") (= comp2 "than")) +;; (gen-neighbours-condition '> quantity property value remainder) +;; (and (= comp1 "less") (= comp2 "than")) +;; (gen-neighbours-condition '< quantity property value remainder) + ) + ))))) (defn parse-neighbours-condition "Parse conditions referring to neighbours"