kommando -> move positionslistaIcke-terminaler: kommando positionslista position
positionslista -> positionslista ; position | position
position -> num , num
Parse-trädet för move 1, 17
Parse-trädet för move 9, 19; 11, 19
Den generella regeln för eliminering av vänsterrekursion säger att grammatiken
A -> A x | ykan skrivas om till A -> y R |
I det här fallet betyder det att produktionen
positionslista -> positionslista ; position | positionskrivs om till
positionslista -> position Rdär empty markerar en tom tokensträng.
R -> ; position R | empty
Därefter ser hela grammatiken alltså ut så här:
kommando -> move positionslistaJag antar att tokentyperna MOVE, HELTAL, KOMMA och SEMIKOLON finns definierade som heltalskonstanter. Spårutskrifterna, som skriver ut namnen på icke-terminaler, behöver inte heller vara med.
positionslista -> position R
R -> ; position R | empty
position -> num , num
int lookahead; void error() { printf("Ledsen error.\n"); exit(EXIT_FAILURE); } void match(int expected) { if (lookahead != expected) error(); else lookahead = scan(); } extern void kommando(), positionslista(), R(), position(); void kommando() { printf("[kommando]\n"); match(MOVE); positionslista(); } void positionslista() { printf("[positionslista]\n"); position(); R(); } void R() { printf("[R]\n"); if (lookahead == SEMIKOLON) { match(SEMIKOLON); position(); R(); } else { /* Match empty */ } } void position() { printf("[position]\n"); match(HELTAL); match(KOMMA); match(HELTAL); } void parse() { printf("[parse]\n"); lookahead = scan(); kommando(); printf("[Ok.]\n"); }
move [0-9]+ , [0-9]+ ( ; [0-9]+ , [0-9]+ )*
Om man tar hänsyn till var blanktecken får och ska förekomma:
move[ ]+[0-9]+[ ]*,[ ]*[0-9]+([ ]*;[ ]*[0-9]+[ ]*,[ ]*[0-9])*
b) Postfixkod för en stackmaskin:
c) Treadresskod:lvalue i push 1 = lvalue j push 0 = label 0: rvalue i rvalue j > gofalse 1 rvalue i push 10 < gofalse 2 lvalue i rvalue i push 1 + = goto 3 label 2: lvalue j push 10 rvalue i - rvalue j - = label 3: goto 0 label 1:
i = 1; j = 0; label 0: if (i ≤ j) goto 1; if (i ≥ 10) goto 2; i = i + 1; goto 3; label 2: t1 = 10 - i; t2 = t1 - j; j = t2; label 3: goto 0 label 1:
Syntaktisk analys, som mynnar ut i ett syntaxträd, är ju en av faserna i kompileringen. Terminering, dvs att programmet avslutas och inte hänger sig i en oändlig loop, är något som händer vi exekveringen.
Switch-sats -> switch ( Expression ) { Branch-list }Ett annat alternativ, som kräver en default-gren och minst en vanlig gren:
Branch-list -> Optional-branches Optional-default-branch
Optional-branches -> Branches | empty
Optional-default-branch -> Default-branch | empty
Branches -> Branches Branch | Branch
Branch -> case Expression : Statement break ;
Default-branch -> default : Statement break ;
Switch-sats -> switch ( Expression ) { Branches Default-branch }
Branches -> Branches Branch | Branch
Branch -> case Expression : Statement break ;
Default-branch -> default : Statement break ;
void execute_switch(TreeNode* tree) { if (tree->type != SWITCH) error("Internt fel: Det där var ju ingen switch-sats!"); int switch_value = execute(tree->args[0]); TreeNode* branches = tree->args[1]; while (branches != NULL) { TreeNode* this_branch; if (branches->type == SEMICOLON) { this_branch = branches->args[0]; branches = branches->args[1]; } else if (branches->type == CASE) { this_branch = branches; branches = NULL; } else if (branches->type == DEFAULT) { this_branch = branches; branches = NULL; } else error("Internt fel: Omöjligt syntaxträd"); if (this_branch->type == CASE) { if (switch_value == execute(this_branch->args[0])) { execute(this_branch->args[1]); return; } } else if (this_branch->type == DEFAULT) { execute(this_branch->args[0]); return; } } /* while */ } /* execute_switch */