For testing of logistics in our SAP retail system, we needed a flexible rule how to put the items of N deliveries into M handling units (HU, pallets). I invented a syntax which can be used by the business people without my help, because the keywords are taken from their domain. They know what an HU is, it's their daily business. They can write, e.g. " 1. pallet ( 2. pallet ( 1. delivery 2. delivery, 1. item, 50% ) 3. pallet ( 3. delivery ) ) 4. pallet ( 2. delivery, rest ) " I had programmed the parser by hand, since the rules are very simple and parser generators seemed too complicated, too far away for me at that time (OK, it's only half a year ago... :-) ). Just for fun, I am now exploring how these rules could be written in OMeta/JS (to be prepared for my next DSL...) Probably this is not an optimized form to write down the rules, but at least it works for all the keywords (except the keyword "rest" and quantities like "50%", I don't think that they are more difficult, I just wanted to get a working example quickly and therefore restricted to a subset). I parse expressions like the above into an "AST" which could be used as a template to fill easily the database tables (VEPO and VEKP) with the data according to the specified model. Maybe even this part could be defined with OMeta, if an appropriate target syntax is generated... ometa HandlingUnitDefinition <: Parser { ordnum = digit+:ds '.' -> parseInt(ds.join('')), // The complete delivery (with all items) gets item number 0 dlv = ordnum:n ( "delivery" | "dlv" | "DLV" ) -> ["DLV", n, 0], // An SSCC (Serial Shipment Container Code = will correspond to an ID of a Handling Unit) sscc = ordnum:n ( "pallet" | "pal" | "SSCC" ) -> ["SSCC", n], // Expression for item item = ordnum:n ( "item" | "pos" | "POS" ) -> ["POS", n], // Delivery Item = Combines Delivery , Item dlvItem = dlv:d "," spaces item:p -> ["DLV",d[1],p[1]], // A Handling Unit may contain 1..n contentParts: contentPart = dlvItem | dlv | hu | sscc, // This is the complete content of a handling unit content = contentPart:x (spaces contentPart)*:xs -> [x].concat(xs), hu = sscc:s spaces "(" spaces content:c spaces ")" -> ["HU", s[1],c], expr = spaces hu:first (spaces hu)*:more -> [first].concat(more) } // See it work... :-) HandlingUnitDefinition.matchAll( " 11. pallet ( 1. dlv, 2. pos 2. pallet ( 3.dlv 4.dlv,2.item ) 3.pallet ) 3.pal ( 95. delivery) ", "expr") // should give: [[HU, 11, [[DLV, 1, 2], [HU, 2, [[DLV, 3, 0], [DLV, 4, 2]]], [SSCC, 3]]], [HU, 3, [[DLV, 95, 0]]]] [ [HU, 11, [ [DLV, 1, 2], [HU, 2, [ [DLV, 3, 0], [DLV, 4, 2] ] ], [SSCC, 3] ] ], [HU, 3, [ [DLV, 95, 0] ] ] ] // That is an exact image of the entered rule, generated by only 11 lines of code! Remarkable! // My handwritten tokenizer/parser needed some more lines... :-) // I have added some whitespace into the output to clarify the structure // Observe that the content of a pallet can be declared immediately at the place where its code is used (as HU 2 in the // example), or used first and declared in a later step (as HU 3). I use the different tokens SSCC and HU to distinguish // these cases // RĂ¼diger Plantiko, June 30, 2009.