ملاحظة: الإصدار الحالي من لغة الأسس متوافق مع هذه المعايير بشكل غير كامل. هذه المعايير فيها بعض التفاصيل التي ما زالت نظرية ولم تطبق بعد.
إفتح الكل أغلق الكلkeywords
تعريف لصنف يُستخدم لحمل مجموعة من الكلمات التعريفية.
keywords : type list[string]
filter
تعريف لصنف يُستخدم لحمل قيمة المرشّحات في متن القواعد. يمكن للقيمة أما أن تكون عدداً صحيحاً، أو مصفوفة من الأعداد الصحيحة.
filter : type integer || list[integer]
valid_subject
تعريف لصنف المؤشرات المسموح بها كحد من حدود التركيب أو الأمر أو الجملة.
valid_subject : type prule[Subject || Subject.Parameter || Command || Expression || Main.Statement || Set]
Keyword
القاعدة الإعرابية للكلمة التعريفية. تستخدم هذه الكلمات التعريفية في تعريف الأوامر.
Keyword : prule as (@unique kwd:string)=>{ lexer.Identifier(kwd) }
KeywordGroup
القاعدة الإعرابية لمجموعة من الكلمات التعريفية. تستخدم هذه القاعدة لتمكين الأمر الواحد من التبديل بين أكثر من كلمة تعريفية واحدة. على سبيل المثال يمكن للأمر أن يستخدم ترجمات مختلفة لنفس الكلمة التعريفية.
KeywordGroup : prule as (kwds:keywords)=>{ alternate (kwds:k)->( Keyword(k) ) }
Constants
قاعدة إعرابية لعملية تبادل بين مجموعة من الثوابت. تستخدم هذه القاعدة من قبل القواعد التي تسمح بأكثر من ثابت واحد في موضع معين. على سبيل المثال العمليات الرياضية تسمح بأكثر من مؤثر واحد بين الحدّين.
Constants : prule as (kwds:keywords)=>{ alternate (kwds:k)->( lexer.Constant(k) ) }
int: "int". identifier: letter {letter}.
BinDigit : char '0'..'1'; OctDigit : char '0'..'7'; DecDigit : char '0'..'9'; HexDigit : char '0'..'9', 'a'..'f', 'A'..'F'; Letter : char 'a'..'z', 'A'..'Z', '_', 0h0620..0h065F, 0h066E..0h06DC; AnyCharNoEs : char !('\\'); AnyCharNoEsOrSingleQuote : char !("\\'"); AnyCharNoEsOrDoubleQuote : char !("\\\""); Spacing : char " \n\r\t";ملاحظة
Spacing : char " \n\r\t"; ignore { Spacing * (1,endless) }; @minimum ignore { "/*" + any*(0,endless) + "*/" }; @minimum ignore { "//" + any*(0,endless) + "\n" }
المحارف اللامرئية
\n | سطر جديد (linefeed) |
\r | رجوع إلى بداية السطر (carriage return) |
\t | علامة التبويب (tab) |
\b | مسح للخلف (backspace) |
\0 | نهاية سلسلة محارف (string terminator) |
\ج | سطر جديد (linefeed) |
\ر | رجوع إلى بداية السطر (carriage return) |
\ت | علامة التبويب (tab) |
المحارف الاستثنائية
\' | علامة اقتباس مفردة (single quote) |
\" | علامة اقتباس مزدوجة (double quote) |
\\ | شارحة مائلة (backslash) |
\! | الرمز !. يستخدم في الرموز الحرفية (literals) الشخصية حيث يستخدم الرمز ! لتحديد نهاية الرمز |
محارف التعبيرات النمطية
\[ |
\] |
\( |
\) |
\* |
\+ |
\. |
\? |
\| |
\^ |
\$ |
إدخال شفرة المحرف يدوياً
\cDD | لإدخال شفرة بحجم بايت، أي 8 بتّات |
\uDDDD | لإدخال شفرة بحجم بايتين، أي16 بتّاً |
\wDDDDDDDD | لإدخال شفرة بحجم 4 بايتات، أي 32 بتّاً |
escapeSequences : keywords = ( // invisible characters: "\\n", "\\r", "\\t", "\\b", "\\f", "\\0", // special characters: "\\\'", "\\\"", "\\\\", "\\!", // regular expressions characters: "\\[", "\\]", "\\(", "\\)", "\\*", "\\+", "\\.", "\\?", "\\|", "\\^", "\\$"); AnyCharNoEs : char !('\\'); AnyCharNoEsOrSingleQuote : char !("\\'"); AnyCharNoEsOrDoubleQuote : char !("\\\""); @inner EsCharWithSingleQuote : trule as { AnyCharNoEsOrDoubleQuote || EsCodeSequence || alternate (escapeSequences:es)->( es ) }; @inner EsCharWithDoubleQuote : trule as { AnyCharNoEsOrSingleQuote || EsCodeSequence || alternate (escapeSequences:es)->( es ) }; @inner EsCharWithQuotes : trule as { AnyCharNoEs || EsCodeSequence || alternate (escapeSequences:es)->( es ) }; @inner EsCodeSequence : trule as { '\\' + ('c' + HexDigit*(2,2) || 'u' + HexDigit*(4,4) || 'w' + HexDigit*(8,8) || 'n' || 't' || 'r' || '"' || '\'' || '\\' || 'ج' || 'ت' || 'ر') };
identifier : letter { letter | decDigit }. letter : 'a'..'z' | 'A'..'Z' | '_' | 0h0620..0h065F | 0h066E..0h06DC. decDigit : '0'..'9'.
Identifier : trule as { Letter + (Letter || DecDigit)*(0,endless) }; Letter : char 'a'..'z', 'A'..'Z', '_', 0h0620..0h065F, 0h066E..0h06DC; DecDigit : char '0'..'9';
Constant : token as (@unique cnst:string)=>{ cnst };
مؤثرات التعيين | = += -= *= /= %= &= |= $= <<= >>= |
مؤثرات المقارنة | == != < > <= >= |
مؤثرات الجمع والطرح | + - |
مؤثرات القسمة والضرب | * / % |
مؤثرات التعاملات البتّية | | $ & << >> |
مؤثرات التعاملات المنطقية | || $$ && or nor xor xnor and nand |
مؤثرات التعاملات الأحادية المسبقة | ++ -- + - ! !! not |
مؤثرات التعاملات الأحادية المؤخرة | ++ -- |
مؤثرات الربط العليا | . -> .> <. |
مؤثرات الربط الثانية | => .. ..> <.. |
مؤثرات الربط الثالثة | : :> <: |
مؤثرات الربط السفلى | :: ::> <:: in |
مؤثر الشرط | ? |
ثوابت التنقيط (punctuators) | ( ) { } [ ] @ ~ \ ; |
ملاحظة
الثوابت الظاهرة في أكثر من مجموعة من المجموعات السابقة تُعامل من قبل المرمّز كثابت واحد. على سبيل المثال، يوجد في المرمّز تعريف واحد للرمز ++ وليس تعريفين رغم ظهوره مرتين أعلاه.
الأعداد الثنائية | 0b |
الأعداد الثمانية | 0o |
الأعداد الستة عشرية | 0h |
[prefix] digit {digit} ["u"] ["i" num].
BinDigit : char '0'..'1'; OctDigit : char '0'..'7'; DecDigit : char '0'..'9'; HexDigit : char '0'..'9', 'a'..'f', 'A'..'F'; IntLiteral : trule as { (DecIntLiteral || BinIntLiteral || OctIntLiteral || HexIntLiteral) + ("u" || "U")*(0,1) + (("i" || "I") + DecIntLiteral)*(0,1) }; @inner DecIntLiteral : trule as { DecDigit*(1,endless) }; @inner BinIntLiteral : trule as { ("0b" || "0B") + BinDigit*(1,endless) }; @inner OctIntLiteral : trule as { ("0o" || "0O") + OctDigit*(1,endless) }; @inner HexIntLiteral : trule as { ("0h" || "0H") + HexDigit*(1,endless) };
num "." num ["e" ["+"|"-"] num] ["f" num]
DecDigit : char '0'..'9'; FloatLiteral : trule as { DecDigit*(1,endless) + FloatPostfix || DecDigit*(1,endless) + FloatExponent + FloatPostfix*(0,1) || DecDigit*(1,endless) + "." + DecDigit*(1,endless) + FloatExponent*(0,1) + FloatPostfix*(1,1) }; @inner FloatExponent : token as { ("e" || "E") + ("+" || "-")*(0,1) + DecDigit*(1,endless) }; @inner FloatPostfix : token as { ("f" || "F") + DecDigit*(0,endless) };
u | UTF-8 LE |
u8 | UTF-8 LE |
u16 | UTF-16 LE |
u32 | UTF-32 LE |
a | ASCII |
"'" esCharWithDoubleQuote "'" [charCodePostfix].
charCodes : list[string] = ("u", "u8", "u16", "u32", "a"); escapeSequences : keywords = ( // invisible characters: "\\n", "\\r", "\\t", "\\b", "\\f", "\\0", // special characters: "\\\'", "\\\"", "\\\\", "\\!", // regular expressions characters: "\\[", "\\]", "\\(", "\\)", "\\*", "\\+", "\\.", "\\?", "\\|", "\\^", "\\$"); AnyCharNoEsOrSingleQuote : char !("\\'"); CharLiteral : trule as { "'" + EsCharWithDoubleQuote + "'" + CharCodePostfix*(0,1) }; @inner CharCodePostfix : trule as { alternate (charCodes:cc)->( cc ) }; @inner EsCharWithDoubleQuote : trule as { AnyCharNoEsOrSingleQuote || EsCodeSequence || alternate (escapeSequences:es)->( es ) }; @inner EsCodeSequence : trule as { '\\' + ('c' + HexDigit*(2,2) || 'u' + HexDigit*(4,4) || 'w' + HexDigit*(8,8) || 'n' || 't' || 'r' || '"' || '\'' || '\\' || 'ج' || 'ت' || 'ر') };
u | UTF-8 LE |
u8 | UTF-8 LE |
u16 | UTF-16 LE |
u32 | UTF-32 LE |
a | ASCII |
"\"" {esCharWithSingleQuote} "\"" [charCodePostfix].
charCodes : list[string] = ("u", "u8", "u16", "u32", "a"); escapeSequences : keywords = ( // invisible characters: "\\n", "\\r", "\\t", "\\b", "\\f", "\\0", // special characters: "\\\'", "\\\"", "\\\\", "\\!", // regular expressions characters: "\\[", "\\]", "\\(", "\\)", "\\*", "\\+", "\\.", "\\?", "\\|", "\\^", "\\$"); AnyCharNoEsOrDoubleQuote : char !("\\\""); StringLiteral : trule as { StringLiteralPart + (Spacing*(0,endless) + StringLiteralPart)*(0,endless) + CharCodePostfix*(0,1) }; @inner StringLiteralPart : trule as { "\"" + EsCharWithSingleQuote*(0,endless) + "\"" }; @inner CharCodePostfix : trule as { alternate (charCodes:cc)->( cc ) }; @inner EsCharWithSingleQuote : trule as { AnyCharNoEsOrDoubleQuote || EsCodeSequence || alternate (escapeSequences:es)->( es ) }; @inner EsCodeSequence : token as { '\\' + ('c' + HexDigit*(2,2) || 'u' + HexDigit*(4,4) || 'w' + HexDigit*(8,8) || 'n' || 't' || 'r' || '"' || '\'' || '\\' || 'ج' || 'ت' || 'ر') };
"!" prefix "<" {esChar} ">" [postfix] "!".
escapeSequences : keywords = ( // invisible characters: "\\n", "\\r", "\\t", "\\b", "\\f", "\\0", // special characters: "\\\'", "\\\"", "\\\\", "\\!", // regular expressions characters: "\\[", "\\]", "\\(", "\\)", "\\*", "\\+", "\\.", "\\?", "\\|", "\\^", "\\$"); AnyCharNoEs : char !('\\'); CustomLiteral : trule as (@unique prefix:keywords,postfix:keywords)=>{ "!" + alternate (prefix:p)->( p ) + "<" + EsCharWithQuotes*(0,endless) + (">!" + Spacing*(0,endless) + "!<" + EsCharWithQuotes*(0,endless))*(0,endless) + ">" + (alternate (postfix:p)->( p ))*(0,1) + "!" }; @inner EsCharWithQuotes : trule as { AnyCharNoEs || EsCodeSequence || alternate (escapeSequences:es)->( es ) }; @inner EsCodeSequence : trule as { '\\' + ('c' + HexDigit*(2,2) || 'u' + HexDigit*(4,4) || 'w' + HexDigit*(8,8) || 'n' || 't' || 'r' || '"' || '\'' || '\\' || 'ج' || 'ت' || 'ر') };
Program : StatementList. StatementList : Statement { ";" Statement }. Statement : (Phrase | Phrase | ...). Phrase : { Subject }.
Program : prule as { root.Main }; Main : module { start StatementList; StatementList : prule as { Statement*(0, 1) + (lexer.Constant(";") + Statement*(0, 1))*(0, endless) }; Statement : @limit[user.parent==self,child.terms==self] prule prefix self.id, DefaultModifier as (phrases:list[prule[Phrase]]=(CmdPhrase, SoloCmdPhrase, ExpPhrase)=>{ alternate (phrases:phrase)->( phrase ) }; Phrase : prule as (subjects:list[map[prd:valid_subject, min:integer, max:integer, pty:integer]])=>{ concat (subjects:s)->( @priority(s.pty,0) s.prd*(s.min,s.max) ) }; // Default phrases. CmdPhrase : prule ref Phrase(subjects=((prd=LeadingCmdGroup,min=1,max=1), (prd=TrailingCmdGroup,min=0,max=endless))); SoloCmdPhrase : prule ref Phrase(sections=((prd=SoloCmdGroup,min=1,max=1))); ExpPhrase : prule ref Phrase(subjects=((prd=root.Expression,min=1,max=1), (prd=TrailingCmdGroup,min=0,max=endless))); }
[unaryOp] operand. operand [unaryOp]. operand1 {binaryOp operand2}.
:: | |
::> | |
<:: | |
in | تستخدم لتحديد جزء من كل كما هو الحال في أمر foreach. |
: |
:> |
<: |
= | تحديد قيمة جديدة |
+= | إضافة قيمة للقيمة الحالية |
-= | طرح قيمة من القيمة الحالية |
*= | ضرب القيمة الحالية بقيمة أخرى |
/= | تقسيم القيمة الحالية على قيمة أخرى |
÷= | تقسيم القيمة الحالية على قيمة أخرى |
%= | تقسيم القيمة الحالية على قيمة أخرى والاحتفاظ بالباقي بدل نتيجة القسمة |
&= | تطبيق عملية 'و' المنطقية على القيمة الحالية |
|= | تطبيق عملية 'أو' المنطقية على القيمة الحالية |
$= | تطبيق عملية xor المنطقية على القيمة الحالية |
<<= | تزحيف جميع البتّات يساراً مراتباَ بتعداد القيمة المعطاة |
=>> | تزحيف جميع البتّات يميناً مراتباً بتعداد القيمة المعطاة |
أو | عملية 'أو' |
or | عملية 'أو' |
|| | صيغة رمزية ل or |
nor | عملية 'أو' معكوسة |
xor | عملية xor |
$$ | صيغة رمزية ل xor |
xnor | عملية xor معكوسة |
و | عملية 'و' |
and | عملية 'و' |
&& | صيغة رمزية ل and |
nand | عملية 'و' معكوسة |
== | فحص مساواة |
!= | فحص عدم المساواة |
< | فحص أصغر |
> | فحص أكبر |
<= | فحص أصغر أو يساوي |
>= | فحص أكبر أو يساوي |
=> |
.. |
..> |
<.. |
+ |
- |
* | |
/ | |
% | تحصيل باقي القسمة |
| | عملية 'أو' |
$ | عملية xor |
& | عملية 'و' |
<< | تزحيف البتّات يميناً مراتباً بتعداد القيمة المعطاة |
>> | تزحيف البتّات يساراً مراتباً بتعداد القيمة المعطاة |
++ | زيادة بواحد |
-- | إنقاص بواحد |
+ | إشارة الرقم الموجب |
- | إشارة الرقم السالب |
! | علامة النفي البتّية (عكس قيمة البتّات) |
!! | علامة النفي المنطقية |
++ | زيادة بواحد |
-- | إنقاص بواحد |
operand "(" [expression] ")" operand "[" [expression] ")"
. | يُستخدم للربط بين حاوية وعنصر ينتمي لها، كما هو الحال عند الإشارة إلى أحد عناصر كائن ما في البرمجة كائنية المنحى. |
-> | يستخدم كأسلوب آخر للربط بين حاوية وعنصر ينتمي لها. |
.> | |
<. |
1) myvar.mysubvar(params) 2) myvar(params).mysubvarفي المثال الأول أعلاه الجزء '(params)' يُطبق على ناتج 'myvar.mysubvar' بينما في المثال الثاني الجزء '.mysubvar' يُطبق على ناتج 'myvar(params)'.
if a (b,c,d)-e if a\ (b,c,d)-e // prevents (b,c,d)-e from being part of the condition. if a(b,c,d)\ -e // makes (a,b,c) part of the condition and leaves -e out.
a = b + c * d; a = (b + c) * d;في المثال الأول تجمع b مع ناتج ضرب c و d بينما في المثال الثاني تُضرب d بناتج جمع c و b.
TokenData : module { // Predefined Operator Lists assignmentOpList : keywords = ("=", "+=", "-=", "*=", "/=", "÷=", "%=", "&=", "|=", "$=", "<<=", ">>="); comparisonOpList : keywords = ("==", "!=", "<", ">", "<=", ">="); addOpList : keywords = ("+", "-"); mulOpList : keywords = ("*", "/", "%"); bitwiseOpList : keywords = ("|", "$", "&", "<<", ">>"); logOpList : keywords = ("||", "$$", "&&", "أو", "or", "nor", "xor", "xnor", "و", "and", "nand"); prefixOpList : keywords = ("++", "--", "+", "-", "!", "!!", "not"); postfixOpList : keywords = ("++", "--"); linkOpList : keywords = ("->", ".", ".>", "<."); lowLinkOpList : keywords = ("=>", "..", "..>", "<.."); lowerLinkOpList : keywords = (":", ":>", "<:"); lowestLinkOpList : keywords = ("::", "::>", "<::", "in") }; // Expression : // operand {binaryOp operand}. // [unaryOp] operand. // operand [unaryOp]. // operand {FunctionalOp}. Expression : module { prefix self.id, DefaultModifier; start Exp; Exp : prule as { LowestLinkExp + (@priority(in,0) lexer.Constant("\\")*(0,1)) }; LowestLinkExp : prule prefix self.id as (enable:integer=endless)=>{ ConditionalExp + (@priority(in,0) (LowestLinkOp + ConditionalExp)*(0,enable)) }; ConditionalExp : prule prefix self.id as (enable:integer[0<=n<=1]=1)=>{ ListExp + (@priority(in,0) (lexer.Constant("?") + ListExp)*(0,enable)) }; ListExp : prule prefix self.id as (enable:integer=endless)=>{ (@priority(in,0) lexer.Constant(",")*(0,enable)) + LowerLinkExp + (@priority(in,0) (lexer.Constant(",") + LowerLinkExp*(0,1))*(0,enable)) }; LowerLinkExp : prule prefix self.id as (enable:integer=endless)=>{ AssignmentExp + (@priority(in,0) (LowerLinkOp + AssignmentExp)*(0,enable)) }; AssignmentExp : prule prefix self.id as (enable:integer=endless)=>{ LogExp + (@priority(in,0) (AssignmentOp + LogExp)*(0,enable)) }; LogExp : prule prefix self.id as (enable:integer=endless)=>{ ComparisonExp + (@priority(in,0) (LogOp + ComparisonExp)*(0,enable)) }; ComparisonExp : prule prefix self.id as (enable:integer=endless)=>{ LowLinkExp + (@priority(in,0) (ComparisonOp + LowLinkExp)*(0,enable)) }; LowLinkExp : prule prefix self.id as (enable:integer=endless)=>{ AddExp + (@priority(in,0) (LowLinkOp + AddExp)*(0,enable)) }; AddExp : prule prefix self.id as (enable:integer=endless)=>{ MulExp + (@priority(in,0) (AddOp + MulExp)*(0,enable)) }; MulExp : prule prefix self.id as (enable:integer=endless)=>{ BitwiseExp + (@priority(in,0) (MulOp + BitwiseExp)*(0,enable)) }; BitwiseExp : prule prefix self.id as (enable:integer=endless)=>{ UnaryExp + (@priority(in,0) (BitwiseOp + UnaryExp)*(0,enable)) }; UnaryExp : prule prefix self.id as ( enable1:integer[0<=n<=1]=1, enable2:integer[0<=n<=1]=1 )=>{ (@priority(in,0) PrefixOp*(0,enable1)) + FunctionalExp + (@priority(in,0) PostfixOp*(0,enable2)) }; FunctionalExp : prule prefix self.id as ( operand:valid_subject=root.Subject, fltr:filter=null, dup:integer=endless, pty:integer=in )=>{ operand + (@priority(pty,0) (@filter(fltr) ParamPassExp || TildeExp || LinkExp(operand))*(0,dup)) }; // ParamPassExp : "(" [Expression] ")" | "[" [Expression] "]". ParamPassExp : prule as ( expr:prule[Expression||Statement]=root.Expression, fltr:filter=null )=>{ @filter(fltr) lexer.Constant("(") + expr*(0,1) + lexer.Constant(")") || lexer.Constant("[") + expr*(0,1) + lexer.Constant("]") }; // TildeExp : "~" Subject. TildeExp : prule as (operand:valid_subject=root.TildeSubject)=>{ lexer.Constant("~") + operand }; // LinkExp : LinkOp operand. LinkExp : prule as (operand:valid_subject=root.Subject)=>{ LinkOp + operand }; // Operators : AssignmentOp : prule as { root.Constants(root.TokenData.assignmentOpList) }; ComparisonOp : prule as { root.Constants(root.TokenData.comparisonOpList) }; AddOp : prule as { root.Constants(root.TokenData.addOpList) }; MulOp : prule as { root.Constants(root.TokenData.mulOpList) }; BitwiseOp : prule as { root.Constants(root.TokenData.bitwiseOpList) }; LogOp : prule as { root.Constants(root.TokenData.logOpList) }; PrefixOp : prule as { root.Constants(root.TokenData.prefixOpList) }; PostfixOp : prule as { root.Constants(root.TokenData.postfixOpList) }; LinkOp : prule as { root.Constants(root.TokenData.linkOpList) }; LowLinkOp : prule as { root.Constants(root.TokenData.lowLinkOpList) }; LowerLinkOp : prule as { root.Constants(root.TokenData.lowerLinkOpList) }; LowestLinkOp : prule as { root.Constants(root.TokenData.lowestLinkOpList) } };
// An expression that blocks sets. NoSetExpression : module inherits Expression { FunctionalExp.operand = root.NoSetSubject; LinkExp.operand = root.NoSetSubject; }; // An expression that doesn't allow brackets. NoBracketExpression : module inherits Expression { FunctionalExp.{operand=root.NoBracketSubject; fltr=(0,1,1); dup=endless; pty=in}; LinkExp.operand = root.NoBracketSubject; }; // An expression that allows only identifiers with link operators. FullIdExpression : module inherits Expression { start FunctionalExp; FunctionalExp.{operand=IdSubject; fltr=2; dup=endless; pty=in}; LinkExp.operand = root.IdSubject; };
statement: a = b + c * d translates into: store(a, add(b, multiply(c, d))) statement: a > b ? c, d translates into: decide(greaterThan(a, b), list(c, d)) statement: a:int, b:float, c:char translates into: list(link(a,int), link(b,float), link(c,char)) statement: a = myclass.myfunction(5, 2) translates into: store(a, bracketOp(dot(myclass, myfunction), list(5, 2)))
Cmd : keyword {Subject}. MultiCmd : {keyword {Subject}}.القالب Cmd يبدأ بكلمة تعريفية يليها عدد غير محدد من الحدود. يمكن التحكم عن طريق معطيات القالب بخيارات التكرار لكل حد من هذه الحدود. القالب MultiCmd عبارة عن سلسلة مقاطع كل منها مشابه للقالب Cmd ويمكن التحكم بخيارات التكرار لكل مقطع من هذه المقاطع، بالإضافة لإمكانية التحكم لكل حد في كل من هذه المقاطع. في حقيقة الأمر، القالب Cmd عبارة عن نسخة مبسطة من القالب MultiCmd، أي أن بالإمكان الاستعاضة عن Cmd ب MultiCmd.
ملاحظة: تجنب الغموض الإعرابي من مسؤولية كاتب مكتبة البناء. الغموض قد ينتج من استخدام نفس الكلمة التعريفية في أكثر من أمر وقد ينتج أيضاً بسبب الحدود الاختيارية. على سبيل المثال، قد ينتج الغموض من حدّي تراكيب متتاليين أولهما اختياري.
// Root Command Command : @limit[child.terms==(Cmd||MultiCmd)] prule prefix self.id, DefaultModifier; // Cmd : keyword {Subject}. Cmd : @limit[user.parent==root.Command] prule as (kwd:keywords, args:list[map[prd:valid_subject, min:integer, max:integer, pty:integer]])=>{ root.KeywordGroup(kwd) + concat (args:a)->( @priority(a.pty,0) a.prd*(a.min,a.max) ) }; // MultiCmd : {keyword {Subject}}. MultiCmd : @limit[user.parent==root.Command] prule as (sections:list[map[kwd:keywords, min:integer, max:integer, pty:integer, args:list[map[prd:valid_subject, min:integer, max:integer, pty:integer]] ]])=>{ concat (sections:s)->( @priority(s.pty,0) (root.KeywordGroup(s.kwd) + concat (s.args:a)->( @priority(a.pty,0) a.arg*(a.min, a.max) ))*(s.min, s.max) ) };التعريف Command هو جذر كل الأوامر وكل أمر يجب أن يُشتق منه بشكل مباشر أو غير مباشر. فيما يلي قائمة المعطيات الداخلة في تعريف القالبين:
1
Cmd: keyword {Subject}. gotoCmd: "goto" Expression. goto mystart;
2
MultiCmd: {keyword {Subject}}. ifCmd: "if" Expression Statement "else" Statement. if i==5 DoSomething() else DoSomethingElse();المثال أعلاه يُعرب إلى:
ifCmd Expression: i==5 Statement: DoSomething() Statement: DoSomethingElse()
Subject : (Parameter | Command | Expression | Statement | Set) | "(" (Parameter | Command | Expression | Statement | Set) ")" | "[" (Parameter | Command | Expression | Statement | Set) "]". Parameter : Identifier | Literal. Literal : IntLiteral | FloatLiteral | CharLiteral | StringLiteral | CustomLiteral.
Subject : module { prefix self.id, DefaultModifier; start Subject1; Subject1 : prule as ( sbj1:list[prule[ Parameter||root.Command||root.Expression||root.Main.Statement||root.Set ]] = (Parameter, SubjectCommandGroup, root.Set), sbj2:list[prule[ Parameter||root.Command||root.Expression||root.Main.Statement||root.Set ]] = (root.Expression), sbj3:list[prule[ Parameter||root.Command||root.Expression||root.Main.Statement||root.Set ]] = (root.Expression), fltr:filter, frc2:integer = 0, frc3:integer = 0 )=>{ @filter(fltr) alternate (sbj1:s)->( s ) || lexer.Constant("(") + (alternate (sbj2:s)->( s ))*(frc2,1) + lexer.Constant(")") || lexer.Constant("[") + (alternate (sbj3:s)->( s ))*(frc3,1) + lexer.Constant("]") }; Subject2 : @limit[user.owner==Subject] prule as ( sbj:prule[Parameter||root.Command||root.Expression||root.Main.Statement||root.Set], fltr:filter, frc:integer )=>{ @filter(fltr) sbj || lexer.Constant("(") + sbj*(frc,1) + lexer.Constant(")") || lexer.Constant("[") + sbj*(frc,1) + lexer.Constant("]") }; // Commands SubjectCommand : prule inherits root.Command prefix self.id; SubjectCommandGroup : prule_group[SubjectCommand]; // Parameter Parameter : prule prefix self.id as (fltr:filter=null, cnsts:keywords=null)=>{ @filter(fltr) lexer.Identifier || Literal || root.Constants(cnsts) }; // Literal Literal : prule as (fltr:filter=null)=>{ @filter(fltr) lexer.IntLiteral || lexer.FloatLiteral || lexer.CharLiteral || lexer.StringLiteral || lexer.CustomLiteral } }الفرق بين Subject1 و Subject2 هو أن الأول يسمح بأكثر من صنف واحد بينما يقتصر الأخير على صنف واحد يُسمح به في هذا الحد. التعريف SubjectCommandGroup حاوية لمجموعة الأوامر المسموح ظهورها كحد. فيما يلي قائمة المعطيات:
// The default Tilde subject. TildeSubject : module inherits Subject { Subject1.{sbj1=(SubjectCommandGroup); sbj2=(root.Expression); frc2=0; sbj3=(root.Expression); frc3=0}; SubjectCommandGroup = (); }; // A subject that doesn't allow sets. NoSetSubject : module inherits Subject { Subject1.{sbj1=(Parameter, SubjectCommandGroup); sbj2=(root.Expression); frc2=0; sbj3=(root.Expression); frc3=0} }; // A subject that doesn't allow brackets. NoBracketSubject : module inherits Subject { Subject1.{sbj1=(Parameter, SubjectCommandGroup, root.Set); sbj2=(); frc2=0; sbj3=(); frc3=0} }; // A subject that allows only identifiers. IdSubject : module inherits Subject { start Parameter; Parameter.{fltr=0; cnsts=null} }; // A subject that allows full identifiers (with . or -> operators). FullIdSubject : module inherits Subject { start Subject2; Subject2.{obj=root.FullIdExpression; fltr=0; frc=0} }; ModifierSubject : module inherits Subject { Subject1.{sbj1=(SubjectCommandGroup); sbj2=(root.Expression); frc2=0; sbj3=(root.Expression); frc3=0}; SubjectCommandGroup = (UseModifierCmd); // @use modifier. UseModifierCmd : prule ref root.Cmd(kwd=("use"), args=((UseModifierSubject))); UseModifierSubject : module inherits root.FullIdSubject { Subject2.{fltr=2, frc=1} } };
Set : "{" StatementList "}".
Set : @limit[child.terms==self,user.parent==self] prule prefix DefaultModifier as ( stmt:prule[StatementList]=root.Main )=>{ lexer.Constant("{") + stmt + lexer.Constant("}") };
Modifier : "@" Subject | "@<" Subject.هناك صيغتان لكتابة المبدّل. الصيفة الأولى تعني أن الأسبقية في مزاوجة المعلومات الوصفية مع قاعدة إعرابية تكون للقاعدة الإعرابية الداخلية بينما تعطي الصيغة الثانية الأسبقية للقاعدة الخارجية. على سبيل المثال، لو كانت القاعدة Subject تشير إلى القاعدة Parameter وكلتا القاعدتين تقبلان مبدّلاً معيناً فإن استخدام الصيغة الأولى يُعطي المبدّل للقاعدة Parameter بينما تعطي الصيغة الثانية المبدّل للقاعدة Subject.
Modifiers : module { Expression: module inherits root.Expression { start FunctionalExp; FunctionalExp.vars.{ operand = root.Modifiers.Subject; dup = 1; filter2 = 2; }; }; Subject : module inherits root.Subject { SubjectCommandGroup = (); }; CmdGroup : prule_group[LeadingCommand]; Phrase: prule as { module.CmdGroup || module.Expression }; LeadingModifier: prule inherits module.Phrase; TrailingModifier: prule inherits module.Phrase; }; dimension { entryTokenText: "@"; diverge : atRuleEntry; start: root.Modifiers.LeadingModifier; onExit : function (dt:ParsingData) { if dt.data.data.id == root.ModifierSubject.UseModifierCmd // Grammar overriding modifier. override dt.data.data.data else if dt.route == 0 // Command based modifiers (specifies their own targets). addPrefix data=dt.data, type=dt.data.id, targets=prule(dt.data.id).targets else // Expression based modifiers (uses a default target). addPrefix data=dt.data, type=dt.data.id, targets=DefaultModifier } }; dimension { entryTokenText: "@<"; diverge : atRuleEntry; start: root.Modifiers.TrailingModifier; onExit : function (dt:ParsingData) { if dt.route == 0 // Command based modifiers (specifies their own targets). addPostfix data=dt.data, type=dt.data.id, targets=prule(dt.data.id).targets else // Expression based modifiers (uses a default target). addPostfix data=dt.data, type=dt.data.id, targets=DefaultModifier } };
اشـمل: "اشمل" تـركيب.
Import : "import" Expression.
ImportCmd : prule inherits SoloCommand ref root.Cmd(kwd=("import", "اشمل"), args=((prd=root.Expression, min=1, max=1, pty=in)));
عـرف: ("عرف" | "عرّف") تـركيب.
Def : "def" Expression.
DefCmd : prule inherits SoloCommand ref root.Cmd(kwd=("def", "عرف", "عرّف"), args=((prd=root.Expression, min=1, max=1, pty=in)));
UseCmd : "use" FullIdSubject [IdSubject]. UseModifierCmd : "use" "[" FullIdSubject "]".
UseCmd : prule inherits SoloCommand ref root.Cmd(kwd=("use"), args=((prd=root.FullIdSubject, min=1, max=1, pty=in), (prd=root.IdSubject, min=0, max=1, pty=in))) handle onProductionEnd : function (dt:ParsingData) { if dt.data(1) == null override dt.data(0) else defGrammar dt.data(1), dt.data(0) }; UseModifierCmd : prule ref root.Cmd(kwd=("use"), args=((UseModifierSubject))); UseModifierSubject : module inherits root.FullIdSubject { Subject2.{fltr=2, frc=1} }
@use[myGrammar] myGrammarCmd "...";استخدام الأمر use لتفعيل مجموعة قواعد ضمن المجال الحالي:
use myGrammar; myGrammarCmd "...";استخدام الأمر use لإنشاء اختصار لمجموعة القواعد يمكن استخدامه لاحقاً في مبدّل use:
use myGrammar g; @use[g] myGrammarCmd "...";
الشفرة (code) | الشدة (severity) | الوصف |
---|---|---|
CL1001 | 1 | يطلق هذا الإشعار عند مصادفة المرمّز لمحارف لا تنتمي لأي قاعدة ترميزية. |
CL1002 | 1 | صوان المحارف المدخلة ممتلئ. الرمز أطول من سعة الصوان وقد يتم تقسيم الرمز إلى عدة رموز. |
CL2001 | 2 | صوان المحارف المدخلة ممتلئ. الرمز أطول من سعة الصوان ما يؤدي إلى إقتطاع بعض المحارف من الرمز. |
CP1001 | 1 | خطأ إعرابي. سيتم تجاوز الجملة الخاطئة إلى التي تليها. |
CP1002 | 1 | المعرب أنهى عملية الإعراب قبل إكمال القاعدة الإعرابية الجذرية. |
CP1003 | 1 | المعرب استلم رمزاً بعد أن أنهى عملية الإعراب بإكمال القاعدة الإعرابية الجذرية. |
CP2004 | 2 | الغموض الإعرابي يتسبب في تشعب المعرب إلى وضعيات متعددة. |
CP1005 | 1 | مبدّل غير متوقع. واجه المعرب مبدّلاً يم تتقبله أي قاعدة إعرابية. |
CD1001 | 1 | التعريف يفتقر إلى التركيب الصحيح. لم يجد المعرب تركيب الربط بـ":" المطلوب للتعريف. |
CD1002 | 1 | التعريف يفتقر إلى اسم. |
CD1003 | 1 | أمر تعريف غير صالح. |
CD1004 | 1 | محاولة دمج تعريفين غير متوافقين. |
CG1001 | 1 | خطأ مجهول. |
CG1003 | 1 | فشل الاستيراد. فشل تحميل الملف المعني. |
//////////////////////////////////////////////////////////////////////////// // Type Definitions // A list of keywords. keywords : type list[string]; // A value for the filter modifier. filter : type integer || list[integer]; // A list of productions that can be used as subjects. valid_subject : type prule[Subject || Subject.Parameter || Command || Expression || Main.Statement || Set]; //////////////////////////////////////////////////////////////////////////// // Token Data Definitions TokenData : module { // The set of postfixes used to specify character coding (ascii, unicode, etc.). charCodes : list[string] = ("u", "u8", "u16", "u32", "a"); // Escape Sequences escapeSequences : keywords = ( // invisible characters: "\\n", "\\r", "\\t", "\\b", "\\f", "\\0", // special characters: "\\\'", "\\\"", "\\\\", "\\!", // regular expressions characters: "\\[", "\\]", "\\(", "\\)", "\\*", "\\+", "\\.", "\\?", "\\|", "\\^", "\\$"); // Predefined Operator Lists assignmentOpList : keywords = ("=", "+=", "-=", "*=", "/=", "÷=", "%=", "&=", "|=", "$=", "<<=", ">>="); comparisonOpList : keywords = ("==", "!=", "<", ">", "<=", ">="); addOpList : keywords = ("+", "-"); mulOpList : keywords = ("*", "/", "%"); bitwiseOpList : keywords = ("|", "$", "&", "<<", ">>"); logOpList : keywords = ("||", "$$", "&&", "أو", "or", "nor", "xor", "xnor", "و", "and", "nand"); prefixOpList : keywords = ("++", "--", "+", "-", "!", "!!", "not"); postfixOpList : keywords = ("++", "--"); linkOpList : keywords = ("->", ".", ".>", "<."); lowLinkOpList : keywords = ("=>", "..", "..>", "<.."); lowerLinkOpList : keywords = (":", ":>", "<:"); lowestLinkOpList : keywords = ("::", "::>", "<::", "in") }; //////////////////////////////////////////////////////////////////////////// // Lexer Definitions lexer LexerDefs; LexerDefs : module { //////////////////////////////////////////////////////////////////////// // Character Group Definitions BinDigit : char '0'..'1'; OctDigit : char '0'..'7'; DecDigit : char '0'..'9'; HexDigit : char '0'..'9', 'a'..'f', 'A'..'F'; Letter : char 'a'..'z', 'A'..'Z', '_', 0h0620..0h065F, 0h066E..0h06DC; AnyCharNoEs : char !('\\'); AnyCharNoEsOrSingleQuote : char !("\\'"); AnyCharNoEsOrDoubleQuote : char !("\\\""); Spacing : char " \n\r\t"; //////////////////////////////////////////////////////////////////////// // Token Definitions // Identifiers // letter {letter|decDigit}. Identifier : trule as { Letter + (Letter || DecDigit)*(0,endless) }; // Integer Literals // [prefix] digit {digit} ["u"] ["i" num]. IntLiteral : trule as { (DecIntLiteral || BinIntLiteral || OctIntLiteral || HexIntLiteral) + ("u" || "U")*(0,1) + (("i" || "I") + DecIntLiteral)*(0,1) }; @inner DecIntLiteral : trule as { DecDigit*(1,endless) }; @inner BinIntLiteral : trule as { ("0b" || "0B") + BinDigit*(1,endless) }; @inner OctIntLiteral : trule as { ("0o" || "0O") + OctDigit*(1,endless) }; @inner HexIntLiteral : trule as { ("0h" || "0H") + HexDigit*(1,endless) }; // Float Literals // num "." num ["e" ["+"|"-"] num] ["f" num]. FloatLiteral : trule as { DecDigit*(1,endless) + FloatPostfix || DecDigit*(1,endless) + FloatExponent + FloatPostfix*(0,1) || DecDigit*(1,endless) + "." + DecDigit*(1,endless) + FloatExponent*(0,1) + FloatPostfix*(1,1) }; @inner FloatExponent : trule as { ("e" || "E") + ("+" || "-")*(0,1) + DecDigit*(1,endless) }; @inner FloatPostfix : trule as { ("f" || "F") + DecDigit*(0,endless) }; // Character And String Literals // charLiteral: "'" esCharWithDoubleQuote "'" [charCodePostfix]. // stringLiteral: "\"" {esCharWithSingleQuote} "\"" [charCodePostfix]. CharLiteral : trule as { "'" + EsCharWithDoubleQuote + "'" + CharCodePostfix*(0,1) }; StringLiteral : trule as { StringLiteralPart + (Spacing*(0,endless) + StringLiteralPart)*(0,endless) + CharCodePostfix*(0,1) }; @inner StringLiteralPart : trule as { "\"" + EsCharWithSingleQuote*(0,endless) + "\"" }; @inner CharCodePostfix : trule as { alternate (root.TokenData.charCodes:cc)->( cc ) }; // Custom Literals // "!" prefix "<" {esCharWithQuotes} ">" [postfix] "!". CustomLiteral : trule as (@unique prefix:keywords,postfix:keywords)=>{ "!" + alternate (prefix:p)->( p ) + "<" + EsCharWithQuotes*(0,endless) + (">!" + Spacing*(0,endless) + "!<" + EsCharWithQuotes*(0,endless))*(0,endless) + ">" + (alternate (postfix:p)->( p ))*(0,1) + "!" }; // String Characters @inner EsCharWithSingleQuote : trule as { AnyCharNoEsOrDoubleQuote || EsCodeSequence || alternate (root.TokenData.escapeSequences:es)->( es ) }; @inner EsCharWithDoubleQuote : trule as { AnyCharNoEsOrSingleQuote || EsCodeSequence || alternate (root.TokenData.escapeSequences:es)->( es ) }; @inner EsCharWithQuotes : trule as { AnyCharNoEs || EsCodeSequence || alternate (root.TokenData.escapeSequences:es)->( es ) }; @inner EsCodeSequence : trule as { '\\' + ('c' + HexDigit*(2,2) || 'u' + HexDigit*(4,4) || 'w' + HexDigit*(8,8) || 'n' || 't' || 'r' || '"' || '\'' || '\\' || 'ج' || 'ت' || 'ر') }; // Constants Constant : trule as (@unique cnst:string)=>{ cnst }; //////////////////////////////////////////////////////////////////////// // Ignore spacing (' ', '\n', '\r', '\t') when they don't belong to any token ignore { Spacing*(1,endless) }; @minimum ignore { "/*" + any*(0,endless) + "*/" }; @minimum ignore { "//" + any*(0,endless) + "\n" } }; //////////////////////////////////////////////////////////////////////////// // Parser Productions // NOTE: // The syntax written in comments is just an approximation of the actual syntax. // This commented syntax is written just to give the reader a simplified outline // of the actual syntax of the element. start Program; //////****** Main ******////// // Program : StatementList. Program : prule as { root.Main }; // Keywords and Constants KeywordGroup : prule as (kwds:keywords)=>{ alternate (kwds:k)->( Keyword(k) ) }; Keyword : prule as (@unique kwd:string)=>{ lexer.Identifier(kwd) }; Constants : prule as (kwds:keywords)=>{ alternate (kwds:k)->( lexer.Constant(k) ) }; Main : module { start StatementList; // StatementList : Statement { ";" Statement }. StatementList : prule as { Statement*(0, 1) + (lexer.Constant(";") + Statement*(0, 1))*(0, endless) }; // Statement : (Phrase | Phrase | ...). Statement : @limit[user.parent==self,child.terms==self] prule prefix self.id, DefaultModifier as (phrases:list[prule[Phrase]]=(CmdPhrase, SoloCmdPhrase, ExpPhrase)=>{ alternate (phrases:phrase)->( phrase ) }; // Phrase : { Subject }. Phrase : prule as ( subjects:list[map[prd:valid_subject, min:integer, max:integer, pty:integer]] )=>{ concat (subjects:s)->( @priority(s.pty,0) s.prd*(s.min,s.max) ) }; // Default phrases. CmdPhrase : prule ref Phrase(subjects=((prd=LeadingCmdGroup,min=1,max=1), (prd=TrailingCmdGroup,min=0,max=endless))); SoloCmdPhrase : prule ref Phrase(subjects=((prd=SoloCmdGroup,min=1,max=1))); ExpPhrase : prule ref Phrase(subjects=((prd=root.Expression,min=1,max=1), (prd=TrailingCmdGroup,min=0,max=endless))); // Default Command Types LeadingCommand : prule inherits root.Command prefix self.id; TrailingCommand : prule inherits root.Command prefix self.id; SoloCommand : prule inherits root.Command prefix self.id; // Default Command Groups LeadingCmdGroup : prule_group[LeadingCommand]; TrailingCmdGroup : prule_group[TrailingCommand]; SoloCmdGroup : prule_group[SoloCommand] = (ImportCmd, DefCmd, UseCmd); // 'import' command. ImportCmd : prule inherits SoloCommand ref root.Cmd(kwd=("import", "اشمل"), args=((prd=root.Expression, min=1, max=1, pty=in))); // 'def' command. DefCmd : prule inherits SoloCommand ref root.Cmd(kwd=("def", "عرف", "عرّف"), args=((prd=root.Expression, min=1, max=1, pty=in))); // 'use' command. UseCmd : prule inherits SoloCommand ref root.Cmd(kwd=("use"), args=((prd=root.FullIdSubject, min=1, max=1, pty=in), (prd=root.IdSubject, min=0, max=1, pty=in))) handle onProductionEnd : function (dt:ParsingData) { if dt.data(1) == null override dt.data(0) else defGrammar dt.data(1), dt.data(0) }; }; //////****** Commands ******////// // Root Command Command : @limit[child.terms==(Cmd||MultiCmd)] prule prefix self.id, DefaultModifier; // Cmd : keyword {Subject}. Cmd : @limit[user.parent==root.Command] prule as (kwd:keywords, args:list[map[prd:valid_subject, min:integer, max:integer, pty:integer]])=>{ root.KeywordGroup(kwd) + concat (args:a)->( @priority(a.pty,0) a.prd*(a.min,a.max) ) }; // MultiCmd : {keyword {Subject}}. MultiCmd : @limit[user.parent==root.Command] prule as (sections:list[map[kwd:keywords, min:integer, max:integer, pty:integer, args:list[map[prd:valid_subject, min:integer, max:integer, pty:integer]] ]])=>{ concat (sections:s)->( @priority(s.pty,0) (root.KeywordGroup(s.kwd) + concat (s.args:a)->( @priority(a.pty,0) a.arg*(a.min, a.max) ))*(s.min, s.max) ) }; //////****** Expressions ******////// // Expression : // operand {binaryOp operand}. // [unaryOp] operand. // operand [unaryOp]. // operand {FunctionalOp}. Expression : module { prefix self.id, DefaultModifier; start Exp; Exp : prule as { LowestLinkExp + (@priority(in,0) lexer.Constant("\\")*(0,1)) }; LowestLinkExp : prule prefix self.id as (enable:integer=endless)=>{ ConditionalExp + (@priority(in,0) (LowestLinkOp + ConditionalExp)*(0,enable)) }; ConditionalExp : prule prefix self.id as (enable:integer[0<=n<=1]=1)=>{ ListExp + (@priority(in,0) (lexer.Constant("?") + ListExp)*(0,enable)) }; ListExp : prule prefix self.id as (enable:integer=endless)=>{ (@priority(in,0) lexer.Constant(",")*(0,enable)) + LowerLinkExp + (@priority(in,0) (lexer.Constant(",") + LowerLinkExp*(0,1))*(0,enable)) }; LowerLinkExp : prule prefix self.id as (enable:integer=endless)=>{ AssignmentExp + (@priority(in,0) (LowerLinkOp + AssignmentExp)*(0,enable)) }; AssignmentExp : prule prefix self.id as (enable:integer=endless)=>{ LogExp + (@priority(in,0) (AssignmentOp + LogExp)*(0,enable)) }; LogExp : prule prefix self.id as (enable:integer=endless)=>{ ComparisonExp + (@priority(in,0) (LogOp + ComparisonExp)*(0,enable)) }; ComparisonExp : prule prefix self.id as (enable:integer=endless)=>{ LowLinkExp + (@priority(in,0) (ComparisonOp + LowLinkExp)*(0,enable)) }; LowLinkExp : prule prefix self.id as (enable:integer=endless)=>{ AddExp + (@priority(in,0) (LowLinkOp + AddExp)*(0,enable)) }; AddExp : prule prefix self.id as (enable:integer=endless)=>{ MulExp + (@priority(in,0) (AddOp + MulExp)*(0,enable)) }; MulExp : prule prefix self.id as (enable:integer=endless)=>{ BitwiseExp + (@priority(in,0) (MulOp + BitwiseExp)*(0,enable)) }; BitwiseExp : prule prefix self.id as (enable:integer=endless)=>{ UnaryExp + (@priority(in,0) (BitwiseOp + UnaryExp)*(0,enable)) }; UnaryExp : prule prefix self.id as (enable1:integer[0<=n<=1]=1, enable2:integer[0<=n<=1]=1)=>{ (@priority(in,0) PrefixOp*(0,enable1)) + FunctionalExp + (@priority(in,0) PostfixOp*(0,enable2)) }; FunctionalExp : prule prefix self.id as ( operand:valid_subject=root.Subject, fltr:filter=null, dup:integer=endless, pty:integer=in )=>{ operand + (@priority(pty,0) (@filter(fltr) ParamPassExp || TildeExp || LinkExp(operand))*(0,dup)) }; // ParamPassExp : "(" [Expression] ")" | "[" [Expression] "]". ParamPassExp : prule as (expr:prule[Expression||Statement]=root.Expression, fltr:filter=null)=>{ @filter(fltr) lexer.Constant("(") + expr*(0,1) + lexer.Constant(")") || lexer.Constant("[") + expr*(0,1) + lexer.Constant("]") }; // TildeExp : "~" Subject. TildeExp : prule as (operand:valid_subject=root.TildeSubject)=>{ lexer.Constant("~") + operand }; // LinkExp : LinkOp operand. LinkExp : prule as (operand:valid_subject=root.Subject)=>{ LinkOp + operand }; // Operators : AssignmentOp : prule as { root.Constants(root.TokenData.assignmentOpList) }; ComparisonOp : prule as { root.Constants(root.TokenData.comparisonOpList) }; AddOp : prule as { root.Constants(root.TokenData.addOpList) }; MulOp : prule as { root.Constants(root.TokenData.mulOpList) }; BitwiseOp : prule as { root.Constants(root.TokenData.bitwiseOpList) }; LogOp : prule as { root.Constants(root.TokenData.logOpList) }; PrefixOp : prule as { root.Constants(root.TokenData.prefixOpList) }; PostfixOp : prule as { root.Constants(root.TokenData.postfixOpList) }; LinkOp : prule as { root.Constants(root.TokenData.linkOpList) }; LowLinkOp : prule as { root.Constants(root.TokenData.lowLinkOpList) }; LowerLinkOp : prule as { root.Constants(root.TokenData.lowerLinkOpList) }; LowestLinkOp : prule as { root.Constants(root.TokenData.lowestLinkOpList) } }; // An expression that blocks sets. NoSetExpression : module inherits Expression { FunctionalExp.operand = root.NoSetSubject; LinkExp.operand = root.NoSetSubject; }; // An expression that doesn't allow brackets. NoBracketExpression : module inherits Expression { FunctionalExp.{operand=root.NoBracketSubject; fltr=(0,1,1); dup=endless; pty=in}; LinkExp.operand = root.NoBracketSubject; }; // An expression that allows only identifiers with link operators. FullIdExpression : module inherits Expression { start FunctionalExp; FunctionalExp.{operand=IdSubject; fltr=2; dup=endless; pty=in}; LinkExp.operand = root.IdSubject; }; //////****** Subjects ******////// // Subject : (Parameter | Command | Expression | Statement | Set) | // "(" (Parameter | Command | Expression | Statement | Set) ")" | // "[" (Parameter | Command | Expression | Statement | Set) "]". Subject : module { prefix self.id, DefaultModifier; start Subject1; Subject1 : prule as ( sbj1:list[prule[ Parameter||root.Command||root.Expression||root.Main.Statement||root.Set ]] = (Parameter, SubjectCommandGroup, root.Set), sbj2:list[prule[ Parameter||root.Command||root.Expression||root.Main.Statement||root.Set ]] = (root.Expression), sbj3:list[prule[ Parameter||root.Command||root.Expression||root.Main.Statement||root.Set ]] = (root.Expression), fltr:filter=null, frc2:integer = 0, frc3:integer = 0 )=>{ @filter(fltr) alternate (sbj1:s)->( s ) || lexer.Constant("(") + (alternate (sbj2:s)->( s ))*(frc2,1) + lexer.Constant(")") || lexer.Constant("[") + (alternate (sbj3:s)->( s ))*(frc3,1) + lexer.Constant("]") }; Subject2 : @limit[user.owner==Subject] prule as ( sbj:prule[Parameter||root.Command||root.Expression||root.Main.Statement||root.Set], fltr:filter, frc:integer )=>{ @filter(fltr) sbj || lexer.Constant("(") + sbj*(frc,1) + lexer.Constant(")") || lexer.Constant("[") + sbj*(frc,1) + lexer.Constant("]") }; // Commands SubjectCommand : prule inherits root.Command prefix self.id; SubjectCommandGroup : prule_group[SubjectCommand]; // Parameter: Identifier | Literal. Parameter : prule prefix self.id as (fltr:filter=null, cnsts:keywords=null)=>{ @filter(fltr) lexer.Identifier || Literal || root.Constants(cnsts) }; // Literal: IntLiteral | FloatLiteral | CharLiteral | StringLiteral | CustomLiteral. Literal : prule as (fltr:filter=null)=>{ @filter(fltr) lexer.IntLiteral || lexer.FloatLiteral || lexer.CharLiteral || lexer.StringLiteral || lexer.CustomLiteral } }; // The default Tilde subject. TildeSubject : module inherits Subject { Subject1.{sbj1=(SubjectCommandGroup); sbj2=(root.Expression); frc2=0; sbj3=(root.Expression); frc3=0}; SubjectCommandGroup = (); }; // A subject that doesn't allow sets. NoSetSubject : module inherits Subject { Subject1.{sbj1=(Parameter, SubjectCommandGroup); sbj2=(root.Expression); frc2=0; sbj3=(root.Expression); frc3=0} }; // A subject that doesn't allow brackets. NoBracketSubject : module inherits Subject { Subject1.{sbj1=(Parameter, SubjectCommandGroup, root.Set); sbj2=(); frc2=0; sbj3=(); frc3=0} }; // A subject that allows only identifiers. IdSubject : module inherits Subject { start Parameter; Parameter.{fltr=0; cnsts=null} }; // A subject that allows full identifiers (with . or -> operators). FullIdSubject : module inherits Subject { start Subject2; Subject2.{obj=root.FullIdExpression; fltr=0; frc=0} }; ModifierSubject : module inherits Subject { Subject1.{sbj1=(SubjectCommandGroup); sbj2=(root.Expression); frc2=0; sbj3=(root.Expression); frc3=0}; SubjectCommandGroup = (UseModifierCmd); // @use modifier. UseModifierCmd : prule ref root.Cmd(kwd=("use"), args=((UseModifierSubject))); UseModifierSubject : module inherits root.FullIdSubject { Subject2.{fltr=2, frc=1} } }; //////****** Sets ******////// // Set : "{" StatementList "}". Set : @limit[child.terms==self,user.parent==self] prule prefix DefaultModifier as ( stmt:prule[StatementList]=root.Main )=>{ lexer.Constant("{") + stmt + lexer.Constant("}") }; //////****** Modifiers ******////// Modifiers : module { Expression: module inherits root.Expression { start FunctionalExp; FunctionalExp.vars.{ operand = root.Modifiers.Subject; dup = 1; filter2 = 2; }; }; Subject : module inherits root.Subject { SubjectCommandGroup = (); }; CmdGroup : prule_group[LeadingCommand]; Phrase: prule as { module.CmdGroup || module.Expression }; LeadingModifier: prule inherits module.Phrase; TrailingModifier: prule inherits module.Phrase; }; dimension { entryTokenText: "@"; diverge : atRuleEntry; start: root.Modifiers.LeadingModifier; onExit : function (dt:ParsingData) { if dt.data.data.id == root.ModifierSubject.UseModifierCmd // Grammar overriding modifier. override dt.data.data.data else if dt.route == 0 // Command based modifiers (specifies their own targets). addPrefix data=dt.data, type=dt.data.id, targets=prule(dt.data.id).targets else // Expression based modifiers (uses a default target). addPrefix data=dt.data, type=dt.data.id, targets=DefaultModifier } }; dimension { entryTokenText: "@<"; diverge : atRuleEntry; start: root.Modifiers.TrailingModifier; onExit : function (dt:ParsingData) { if dt.route == 0 // Command based modifiers (specifies their own targets). addPostfix data=dt.data, type=dt.data.id, targets=prule(dt.data.id).targets else // Expression based modifiers (uses a default target). addPostfix data=dt.data, type=dt.data.id, targets=DefaultModifier } };
الكلمات التمييزية: تكتب الكلمات التمييزية باللون الأزرق.
الشفرات المصدرية: تكتب الشفرات المصدرية داخل مستطيل بخلفية غامقة اللون.
الأمثلة: تكتب الأمثلة داخل مستطيل مشابه للشفرات المصدرية ولكنه بخلفية بيضاء.
مقدمة: يحتوي على شرح مبسّط وسريع للعنصر المعني.
التعريف القواعدي: يحتوي على شرح القاعدة الإعرابية (parsing rule) أو القاعدة الترميزية (tokenizing rule) للعنصر المعني بشكل مفصّل. تفسّر هذه القاعدة كيفية تحليل العنصر وتمثيله رقميّاً.
التركيب النحوي (syntax): يحتوي على شرح مبسّط لتركيب هذا العنصر وكيفية استخدامه من قبل المبرمج. الغرض من هذا القسم تبسيط فهم القاعدة ولكنه لا يكفي لفهم كيفية تحليل العنصر وتمثيله رقميّاً.
الشروط: يحتوي الشروط اللازم توفرها كي يُقبل العنصر المعني من قبل المترجم.
النتيجة: يحتوي على نتيجة العملية، إن كان للعملية نتيجة. يُعلّم المتغير بعلامة ' للإشارة إلى قيمته بعد العملية. على سبيل المثال:
var' = var + 1
العملية: يحتوي على التفاصيل المعنية بطريقة التنفيذ وخطواتها، أي أسلوب عمل المترجم أثناء ترجمة أو تنفيذ العنصر المعني.
الردود: يحتوي على كافة الردود الممكنة من قبل المترجم أو المعرِب لكل حالة من الحالات.
لا يحتوي كل فصل على كل هذه الأقسام بالضرورة، بل قد يحتوي على بعضها فقط حسب الحاجة.العناصر غير الطرفية (non-terminals) | تُكتب بكلمات مفصولة بشارحة سفلية، مع تكبير (capitalize) الحرف الأول من كلّ كلمة. |
العناصر الطرفية (terminals) | تُكتب بكلمات مفصولة بشارحة سفلية وباستخدام الأحرف الصغيرة. |
سلسلة محارف فارغة | تكتب "". |
الفراغات | الفراغات غير مؤثرة. |
| | يُمثّل التبادل (عملية أو). |
التسلسل | التسلسل يمثَّل بوضع العناصر المتسلسلة بعد بعضها دون فاصل. |
( ) | يُستخدم لتجميع العناصر. |
[ ] | يُستخدم لتمثيل العناصر أو المجموعات الإختيارية. |
{ } | يُمثّل التكرار مع إمكانية الغياب. |
: | يُستخدم لفصل اسم العنصر عن تركيبه النحوي. |
. | يوضع في نهاية التعريف. |
a b c | d (a b c) | d
العناصر | تُكتب بكلمات مفصولة بشارحة سفلية، مع تكبير (capitalize) الحرف الأول من كلّ كلمة. يُستخدم هذا التدوين لتمثيل العناصر النهائية وغير النهائية بالإضافة إلى مجموعات المحارف. |
الثوابت | تُحصر الثوابت بين علامتي اقتباس ويشمل هذا العناصر النهائية الثابتة بالإضافة إلى مجموعات المحارف. |
سلسلة محارف فارغة | تكتب "". |
المتغيّرات | المتغيرات تمثل بكلمات مفصولة بشارحة سفلية وباستخدام الأحرف الصغيرة. |
الفراغات | الفراغات غير مؤثرة. |
|| | يُمثّل التبادل (عملية أو). أي أن المُعرب يقبل أيّاً من العناصر المفصولة بهذا الرمز. |
+ | تمثّل التسلسل. أي أن العناصر المفصولة بهذا الرمز يجب أن تأتي متسلسلة في الشفرة المصدرية. |
* | تمثّل التكرار. يُتبع بقائمة من عنصرين مفصولين بفارزة يمثّل الأول منهما الحد الأدنى للتكرار بينما يمثّل الآخر الحد الأعلى. لتمثيل تكرار مفتوح (دون حد أعلى) تُستخدم الكلمة 'endless'. يمكن للحذ الأعلى أن يكون صفراً ما يعني تعطيل العنصر المعني. يمكن استخدام قيمة ضمنية للحدين الأعلى والأدنى ويمكن أيضاً تمثيلهما بمتغيرات. |
( ) | يُستخدم لتجميع العناصر، أو لتعريف متغيرات القوالب. |
: | يُستخدم لفصل اسم العنصر عن قاعدته النحوية. |
; | يُستخدم لفصل التعريفات عن بعضها. |
@ | يُستخدم لتمييز المبدلات القواعدية. |
/* */ | يُستخدم لكتابة التعليقات والملاحظات المتعددة الأسطر. |
// | يستخدم لكتابة الملاحظات المفردة السطر. |
للتسلسل أسبقية على التبادل. على سبيل المثال، التركيبان التاليان متساويان:
a + b + c || d (a + b + c) || d
Identifier ":" DefinitionCommandالأمر التعريفي (definition command) يختلف بتركيبه حسب نوع التعريف، ولكنّه يبدأ دائماً بكلمة تمييزية تحدد نوع هذا التعريف. اسم التعريف لا يُمكن تكراره ضمن مجال واحد. فيما يلي قائمة بالأوامر التعريفية الممكنة:
type
يعرّف صنف بيانات جديد. على سبيل المثال، التعريف التالي يعرّف صنف بيانات يتكون من مصفوفة من سلاسل المحارف:
keywords : type list[string];يمكن للصنف أن يكون اختياراً بين مجموعة من الأصناف. على سبيل المثال:
keyword : type string || list[string];المثال أعلاه يعرّف الصنف ليكون أما سلسلة محارف أو مصفوفة من سلاسل المحارف. راجع قسم القواعد ذات المعطيات أدناه لمزيد من المعلومات عن الأصناف الجائزة.
integer, string, list, map
هذه الأوامر التعريفية تقوم بتعريف بيانات من نوع رقم صحيح (integer) أو سلسلة محارف (string) أو مصفوفة (list) أو قاموس (map).
تحديد صنف عناصر المصفوفة يتم بين قوسين مربّعين. ويُمكن أيضاً التخيير بين أكثر من صنف باستخدام ||. فيما يلي مثالان توضيحيان:
list[string] list[string || integer]ويتم تحديد عناصر القاموس بشكل مشابه، أي بكتابة قائمة عناصر القاموس مفصولة بفارزة ومحصورة بقوسين مربّعين. كل عنصر من عناصر القاموس يتكون من اسم وصنف مفصولين بنقطتان متعامدتان (:). كما هو الحال مع المصفوفة، يُمكن هنا التخيير بين أكثر من صنف. فيما يلي مثالان توضيحيان:
map[kwd:string, count:integer] map[kwd:string||list[string], count:integer]راجع قسم القواعد ذات المعطيات أدناه لمزيد من المعلومات حول الأصناف الجائزة للمصفوفة والقاموس.
char
يعرّف هذا الأمر مجموعة محارف ويُتبع الأمر char بتعريف لمجموعة المحارف المشمولة بهذا التعريف وبكون بأحد الصيغ التالية:
1. "<characters of the group>" 2. <from code> .. <to code> 3. 'f' .. 't' 4. <code>, <code>, ... 5. <character group>, <character group>, ... 6. !(<character group>)وفيما يلي شرح لهذه الصيغ:
trule
يُستخدم لتعريف قاعدة ترميزية (tokenizing rule) وهو ما يُستخدم من قبل المعرِب. يُمكن للرمز أن يرث رمزا آخراً ما يجعله يحمل نفس المعرّف للمورّث، أي عندما يُطابق المرمز المدخلات مع قاعدة الرمز الوارث فإنه يُعطي الناتج قيمة المورث التعريفية بدل قيمة الوارث. لتعريف رمز يُستخدم التدوين التالي:
Id ":" "trule" ["inherits" ParentId] "as" ["(" ParamList ")" "=>"] "{" RuleBody "}".لتعريف قاعدة تستخدم متن قاعدة أخرى (أي تستخدم المتن من قالب) يُستخدم التدوين التالي:
Id ":" "trule" ["inherits" ParentId] "ref" RuleReference ["(" ParamList ")"].قائمة المعطيات اختيارية وسيأتي شرحها لاحقاً.
Identifier : trule as { ( Letter )*(1,endless) };يُمكن أيضاً استخدام تعريف رمزي فارغ كمظلة لمجموعة تعريفات أخرى ترث منها نفس القيمة التعريفية، كما يلي:
Id ":" ["inherits" ParentId] "trule" ";".الإشارة داخل متن القاعدة إلى قاعدة ترميزية أخرى يعني استدعاءها أثناء عملية الترميز بصورة مشابهة لاستدعاء الدالّات لبعضها. ويُمكن تعليم القاعدة الترميزية بمبدل @inner لإعلام المرمّز أن هذا الرمز لا يأتي منفرداً وإنماً فقط ليُستدعى من متن تعريف آخر. يمكن استخدام الأمر trule كصنف لمعطى يجعل هذا المعطى مؤشراً على قاعدة ترميزية ويُتبع بإسم أو مجموعة أسماء لقواعد ترميزية تحصر المعطى بين أحد هذه الأسماء أو قاعدة مشقة من أحدها. المثال التالي يُعرف مصفوفة من المؤشرات على تعريفات ترميزية مشتقة من Constant:
consts : list[trule[Constant]];
prule
يُستخدم لتعريف قاعدة إعرابية (parsing rule). يُمكن للقاعدة الإعرابية أن ترث قاعدة أخرى ما يُعطيها كل صفاتها باستثناء ما تقوم القاعدة الوارثة بتعريفه بنفسها، أي أن التعريفات في القاعدة الوارثة تطغى على مثيلاتها في القاعدة المورّثة كما هو الحال مع الاشتقاق في البرمجة كائنية المنحى. تعريف القاعدة الإعرابية يكون بالصيغة التالية:
Id ":" "prule" ["inherits" ParentId] ["prefix" Ids] "as" ["(" ParamList ")" "=>"] "{" RuleBody "}".لتعريف قاعدة تستخدم متن قاعدة أخرى (أي تستخدم المتن من قالب) يستخدم التدوين التالي:
Id ":" "prule" ["inherits" ParentId] ["prefix" Ids] "ref" RuleReference ["(" ParamList ")"].قائمة المعطيات اختيارية وسيأتي شرحها لاحقاً. استخدام متن قاعدة أخرى يُعامل معاملة تضمين المتن في القاعدة، أي أنه يطغى على المتن الموروث. يُمكن أيضاً تعريف قاعدة إعرابية فارغة، أو قاعدة دون متن طالما لا تُستخدم القاعدة مباشرة في التحليل بل فقط لتوريث بعض الصفات لمجموعة من القواعد الأخرى. المثال التالي يعرّف قاعدة إعرابية لعملية جمع:
Multiply : prule as { Operand + lexer.Constant("*") + Operand };كما هو الحال مع trule، يُمكن استخدام prule كصنف لمؤشرات على قاعدات إعرابية. المثال التالي يُعرف مصفوفة من المؤشرات على قاعدات مشتقة من Exp.
exps : list[prule[Exp]];الكلمة التعريفية prefix تُستخدم مع التحليل متعدد الأبعاد لتحديد البيانات الإعرابية الموازية التي يمكن دمجها مع البيانات الإعرابية الناتجة من هذه القاعدة. راجع القسم "القواعد الموازية" أدناه لمزيد من التفاصيل.
prule_group
يعرّف مجموعة من القواعد الإعرابية يطبق المعرب عملية تبادل عليها عندما يُشار إلى هذه المجموعة.
Id ":" "prule_group" [ "[" ParentId "]" ].يمكن تحديد القواعد الإعرابية الجائز إضافتها إلى المجموعة عن طريق تحديد اسم قاعدة مورِّثة، فيُحصر الاختيار في القواعد الوارثة لتلك القاعدة. على سبيل المثال:
CmdGroup : prule_group[Command]; Statement : prule as { Expression || CmdGroup };في المثال أعلاه CmdGroup تمثل مجموعة من الأوامر ويُسمح للقاعدة Command أو أي وريث لها بالإنضمام لهذه المجموعة. القاعدة Statement تشير إلى المجموعة فيقوم المعرب بالبحث بين عناصر هذه المجموعة عن قاعدة متوافقة مع الرمز المعطى.
module
يُستخدم لتعريف حزمة من التعريفات. يُمكن للحزم أن ترث بعضها فتحتوي الحزمة الوارثة على كل تعريفات الحزمة المورّثة. تعريفات الحزمة الوارثة تطغى على التعريفات الموروثة كما هو الحال مع الاشتقاق في البرمجة كائنية المنحى. تعريف الحزمة يكون بالصيغة التالية:
Id ":" "module" ["inherits" ParentId] "{" ModuleBody "}" ";".يُمكن لحزمة أن تعرف أحد القواعد الإعرابية كنقطة بداية وبذلك يكون جائزاً استخدام الحزمة كقاعدة إعرابية فيتم الإشارة إليها مباشرة من متن قواعد أخرى بدل الإشارة إلى قاعدة بداخلها ويتم ذلك باستخدام الأمر start الذي يستقبل بعده إسم القاعدة المعنية. المثال التالي يُعرف حزمة تحتوي ويحدد أحد قواعدها كنقطة بداية.
Exp : module { start Add; Add : prule as { Multiply + (lexer.Constant("*") + Multiply)*(0,1) }; Multiply : prule as { root.Operand + (lexer.Constant("+") + root.Operand)*(0,1) }; }الإشارة إلى قاعدة أو متغير ضمن حزمة أخرى يتم بتسبيق الإسم بنقطة تسبقها اسم الحزمة. الإسم root يُشير إلى المجال الرئيسي خارج أي حزمة.
null
الأمر null يُستخدم عند التوريث لإلغاء تعريف موروث عن طريق إعادة تعريفه بnull.
ParamList : Name ":" Type ["=" Value] {"," Name ":" Type ["=" Value]}إن غابت قيمة المعطى من التعريف فإن الناتج يكون قالباً لا يُستخدم مباشرة وإنما بعد إنشاء قاعدة موصولة به أو مشتقة منه. المثال التالي يوضح كيفية إنشاء قالب وقاعدة موصولة به:
Cmd : prule as (kwd:string,body:prule[Expression])=>{ lexer.Constant(kwd) + body }; Print : prule ref Cmd(kwd="print", body=MyExpression);المثال التالي يوضح تحديد قيمة للمعطيات في تعريف القاعدة:
LogicalExp : prule as (ops:list[string]=("&&", "||"))=>{ Operand + (Constants(ops) + Operand)*(0,endless) }فيما يلي قائمة بأصناف المعطيات الجائزة في القواعد. تُستخدم هذه الأصناف في القواعد الترميزية والإعرابية بالإضافة لتعريفات الأصناف (الأمر type).
سلسلة محارف | string |
عدد صحيح | integer |
مصفوفة | list |
قاموس | map |
مؤشر على مجموعة محارف | char |
مؤشر على قاعدة ترميزية | trule |
مؤشر على قاعدة إعرابية | prule |
concat
يقوم هذا الأمر بتكرار عنصر معين وتطبيق عملية التسلسل عليه (+) مع ربط كل عنصر من عناصر المصفوفة بأحد هذه التكرارات. الأمر يأخذ الصيغة التالية:
"concat" "(" ListArg ":" LoopArg ")" "=>" "(" Grammar ")".يقوم الأمر بتحويل ListArg إلى سلسلة عناصر مع استبدال كل عنصر منها بناتج تطبيق ذلك العنصر على القالب Grammar. المثال التالي يوضّح هذه العملية:
Words : list("hello", "world"); HelloWorld : prule as { concat (Words:w)=>( w + "!" ) }; HelloWorldHardcoded : prule as { "hello" + "!" + "world" + "!" };في هذا المثال HelloWorld مطابقة في نتيجتها ل HelloWorldHardcoded. فيقوم الأمر concat بتطبيق المقطع (w + "!") على كل عنصر من عناصر المصفوفة Words.
alternate
هذا الأمر مطابق بأسلوبه للأمر concat لكنه يطبق عملية تبادل بين عناصر المصفوفة بدل عملية التسلسل. كما في المثال التالي:
Words : list("hello", "world"); HelloWorld : prule as { alternate (Words:w)=>( w + "!" ) }; HelloWorldHardcoded : prule as { ("hello" + "!") || ("world" + "!") };
a : prule as { lexer.Identifier }; b : prule as { lexer.Identifier("hello") }في المثال أعلاه القاعدة الإعرابية a تقبل أي رمز من نوع Identifier بينما القاعدة b لا تقبل إلى رمزاً من نوع Identifier قيمته hello.
P : module { a : prule as { "cmd" + Expression } }; C : module inherits P { a : prule as { "cmd" + Expression + Expression } }في هذا المثال تحتوي الحزمة C على تعريف جديد ل a يُلغي التعريف الموروث من P.
P : module { a : prule as (kwd:string="cmd")=>{ kwd + Expression } }; C : module inherits P { a.kwd = "mycmd"; }يُمكن جمع عمليات تعديل متعددة باستخدام الأقواس الحاصرة كما في المثال التالي:
C : module inherits P { a.{kwd = "mycmd"; param = MyExpression} }
ignore
يستخدم الأمر ignore لتعريف الرموز المهملة، أي لتعريف قاعدة ترميزية لرموز يتم إهمالها ولا تُرسل إلى المعرِب كما في تعريف الفراغات التي لا تدخل ضمن الإعراب وتأخذ الصيغة التالية:
"ignore" "{" TokenBody "}".
start
الأمر start يُعرّف نقطة البداية في الإعراب بتحديد اسم القاعدة الإعرابية التي يبدأ منها المعرِب. عند ظهور هذا الأمر داخل حزمة فإنه يحدد نقطة البداية لتلك الحزمة، أي عندما يُشار داخل متن قاعدة إعرابية إلى حزمة فإن المعرب ينتقل إلى القاعدة الإعرابية المُشار إليها بالإمر start داخل الحزمة.
lexer
هذا الأمر يشير إلى الحزمة التي تحتوي على القواعد الترميزية. تُتبع الكلمة lexer باسم الحزمة التي تحتوي على القواعد الترميزية. يتعامل المرمّز فقط مع القواعد التي داخل الحزمة المعنية ويهمل القواعد التي خارجها. يجب وجود هذا الأمر في المجال الرئيسي لتحديد الحزمة الترميزية الرئيسية أما داخل الحزم فإن وجوده أختياري ويؤدي إلى استخدام حزمة ترميزية مختلفة حال دخول المُعرب الحزمة المحتوية على هذا الأمر، والعودة إلى الحزمة الترميزية السابقة حال الخروج من تلك الحزمة والعودة للمجال السابق.
self
الكلمة التعريفية self تستخدم للإشارة إلى القاعدة المحتوية على هذه الكلمة. على سبيل المثال، التعريفان التاليان متساويان:
Multiply : prule as { Operand + (lexer.Constant("*") + self)*(0,1) }; Multiply : prule as { Operand + (lexer.Constant("*") + Multiply)*(0,1) }
@filter
هذا المبدل يُستخدم كمرشّح لعناصر قائمة داخلة في عملية التبادل أو التسلسل. يأخذ هذا المبدل أحد هاتين الصيغتين:
"@filter" "(" number ")" <concatenation or alternation> "@filter" "(" list ")" <concatenation or alternation>في الصيغة الأولى يُبقي هذا المرشح على عنصر واحد من قائمة العناصر الداخلة في عملية التبادل أو التسلسل وهو العنصر ذو الموقع المقابل للرقم المُعطى. أما في الصيغة الثانية فإن المبدل يستلم قائمة من الأرقام كمعطيات بدل رقم واحد، كل عنصر من هذه القائمة يشير إلى أحد عناصر عملية التبادل أو التسلسل. على سبيل المثال:
@filter(2) Exp1 || Exp2 || Exp3 || Exp4القاعدة في المثال أعلاه مساوية لكتابة Exp2 بمفردها.
@filter(2,1,4) Exp1 || Exp2 || Exp3 || Exp4 Exp2 || Exp1 || Exp4وفي هذا المثال القاعدتان متطابقتان.
@priority
يُستخدم هذا المبدل لتحديد الأسبقية في أماكن التفرّع الإعرابي ويأخذ الصيغة التالية:
"@priority" "(" [priority ","] tokensToLive ")" Grammar.يحدد هذا المبدّل قيمتين، الأولى (priority) تمثّل الفرع ذو الأسبقية الأعلى أما الثانية فتحدد عمر الفروع غير ذات الأسبقية ويحدد العمر بعدد الرموز التي يستقبلها المُعرب. عندما تمر على المعرب العدد المحدد من الرموز فإنه يقوم بإلغاء الفروع التي مازالت قائمة. إذا كانت قيمة العمر 0 فإن المعرب لا يقوم بالتفرّع بل يأخد من البداية الفرع ذو الأسبقية الأعلى ويهمل غيره.
a + (@priority(in,0) b*(0,1)); // الأسبقية للفرع b وتهمل الحالة الأخرى a + (@priority(out,0) b*(0,1)); // الأسبقية لترك الفرع b @priority(2,3) a || b || c || d; // الأسبقية للفرع c مع إعطاء الفروع الأخرى فرصة مدتها 3 رموز قبل إلغائهم @priority(5,0) prule MyCmd = x; // أسبقية بقيمة 5 تعطى لهذه القاعدة ويؤدي ذلك لإلغاء أي قاعدة بأسبقية تقل عن 5
@limit
يُستخدم للإشارة إلى القيود المطبقة على القواعد. يُعطى هذا المبدل مجموعة من الشروط التي تطبقها القاعدة على القواعد المتعاملة معها. على سبيل المثال:
CmdTemplate : @limit[user.parent==Command] prule as (kwd:keywords)=>{ KeywordGroup(kwd) + Expression }; Command : @limit[child.terms==(CmdTemplate||CmdTemplate2)] prule;في المثال أعلاه يشترط على أي مستخدم للقالب CmdTemplate أن يكون وريثاً للقاعدة Command. ويُشترط على ورثة Command أن يستخدموا أحد القالبين CmdTemplate و CmdTemplate2.
@unique
يُستخدم في تعريف معطيات القوالب القواعدية للإشارة إلى فرادة ذلك المعطى. يُمنع تكرار القيمة نفسها لذات المتغير في طبعات مختلفة من ذلك القالب. مثال:
Command : prule as (@unique kwd:string)=>{ kwd + Expression + ";" }في المثال أعاله يُمنع إنشاء طبعتين من القالب Command بنفس القيمة لkwd.
@inner
يُستخدم مع تعريفات القواعد الترميزية للإشارة إلى قواعد داخلية لا تُستخدم من قبل المرمّز منفردة وإنما فقط عندما يُشار إليها من متن قاعدة أخرى.
@minimum
تستخدم مع الرموز لتحدد أن على المرمز الاكتفاء بأقصر رمز يطابق القاعدة بدل محاولة الحصول على أطول رمز.
dimension { start : <startingRule>; diverge : <divergePoint>; onExit : <exitHandler> }يحتوي التعريف على ثلاث قيم:
جميع الحقوق محفوظة لـ سرمد خالد عبداللّه 2018م \ 1440هـ.
نُشر هذا الملف برخصة الأسُس العامة (Alusus Public License)، الإصدار 1.0، والمضمّنة مع هذا الملف
والمتوفرة أيضاً على الرابط http://alusus.net/alusus_license_1_0. يرجى قراءة الرخصة للتعرف على شروط الاستخدام والنسخ.