::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2020-02-12WhiteboardCS445.txt :: %union { TokenData *tokenData; TreeNode *tree; ExpType type; // for passing type spec up the tree } %type scopedVarDecl simpleExp stmtList stmt sumExp %token '+' '-' '*' %type sumop sumExp : sumExp sumop mulExp { $$ = newStmtNode(OpK, $2, $1, $3); } $$ $1 $2 $3 sumop : '+' { $$ = $1; } | '-' { $$ = $1; } ; | NUMCONST { $1->nvalue; } ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2020-02-22WhiteboardCS445.txt :: 1. type everything that is typable in the tree 2. check for semantic errors 3. be able to print the tree with extra type information main: yyparse() st <- symboltable() st <- semanticCheck(st) // annotate the tree and check semantics ------------------ symbolTable maps symbols to (something) A symbolTable is a stack of scopes! global scope local scope local scope local scope local scope The basic symbolTable Operations: (VERY IMPORTANT) insert(sym, ptr) lookup(sym) -> ptr enter() // helps if you name the scopes for debugger purposes leave() char * --> void *vptr "dogs" (TreeNode *)vptr char a; int dogs(int x, y) { int a; { bool a; a = false; } a = 666; } int cats() { a = 'z'; } ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-01-13WhiteboardCS445.txt :: Intro to CS445 importance of compilers how communication and control computers languages translate our thoughts and actions example of large programs intricate highly reliable goals of the course understand compiling understand some theory hands on construction of a compiler We compile C- why not a real language? Way too hard, objects, agregate types etc why not target a real assembly language? But many useful languages like Java and Python do it this way I have done this a whole bunch of times. I want to help you succeed. It is hard. It is a lot of code. BOOK expensive (if its new) Assignments 7 assignments non-trival assignments time management! individual work C and C++ Development/testing process use whatever machine you want to code on create files of code for compiler create makefile tar up all the files and submit them test machine will build using your makefile and run tests compare output to expected and mail it back to you at your uidaho address unix sdiff command (side by side difference) timestamp is given to each submission class has a machine that is a duplicate of the test machine no late assignments accepted only the run on the test machine counts!!! Grading percentage of points upper 10% you get an A grades are on bblearn Passing course take good notes show up submit all your homeworks ask questions office hours - 1) friday class 2) email me (send twice) 3) make an appointment personal office hour (zoom) Unix ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-01-14WhiteboardCS445.txt :: THE STRUCTURE OF A COMPILER domain specific language ---> machine understands easy to translate vs hard FORTRAN, COBOL, LISP no real compiler technology executable mathematics precise in form and meaning data + process Language Translation task: C++ -> intel processor (assembler) ratfor - Ratfor -> FORTRAN C++ - C++ -> C Other Translation tasks: context sensitive editing profilers and static analysis tools (understand compiler) translate formats (ex. hospital formats) formal framework for languages -> formal methods for translation condensing data --> machine learning (format) CS standpoint important to understand how our translaters/compilers work why did the compiler that? Why were the errors like that? translation is a key area of algorithms useful for understanding and practicing breaking down very hard problems gives us useful tools for dealing with translation if you know how to build a compiler then building a compiler is a possible answer Compiler Structure (terminology) front back source code -T-> object code source language target language T = translator or compiler it is runinng on a host machine (written in the host language) Compiler a compiler is kind of like: main() { IR = front(); output = back(IR); } if T is the compiler: front back [source code] -(T)-> [object code] (data -operation-> data) source language target language Intermediate Representation [IR] (T) has a front end and backend process: front end back end (analysis) -[IR]-> (synthesis) (operation -data- operation) retargeting the compiler (analysis) -[IR]-> (synthesisA) TM (analysis) -[IR]-> (synthesisB) postscript Also can replace the analysis section for different languages Intermediate Representation [IR] contains all the meaning (analysis) --> [IR] --> (optimizations) --> (synthesis) (analysis) --> [IR] --> (IR optimization) --> (Machine optimization) --> (synthesis) COMPILER IN MORE DETAIL: Analysis: [source code] (lexical analyser/scanner) assignment 1 (use flex) [token stream] break it down by TOKENS: example source code: int main() { int y; // dogs are great y = 34; if (y==9) return; } resulting token list: int key main id ( ) { int type y id ; y = 34 num = 34 ; if ( y == 9 ) return ; } ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-01-19WhiteboardCS445.txt :: The parts of a compiler in detail including processes in () and data in [] and assignments A1-A8 FRONT END: analysis end (C-) (scanner = lexical analysis) flex A1 [tokens] (parser) syntax checking? is it legal? bison A2 [abstract syntax tree (AST)] (semantic analysis) what does it mean? Is it non-sense? types right? A3 & A4 [AST + symbol table] A5 - error messaging BACK END: synthesis (IR) A6 - memory management A7 - procedure management and var code generation A8 - rest of code generation (intermediate code generation) [intermediate representation (IR)] (intermediate code optimization) [optimized intermediate representation (IR)] BACK END2: synthesis (TM) (target machine generation) [target machine code in editable form] (target machine optimization) [optimized target machine code] use flex to break input into tokens int main() { char c:'x' while for int @; // scanner error while = 666; // syntax error break; // semantic error 'x' + true; // semantic error } ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-01-20WhiteboardCS445.txt :: two different tokens: > >= two different tokens that are the same: -57 and 3-4 the scanner doesn't care. It will just return a minus. tokens are recognized by regular expressions. REGULAR LANGUAGES (RE) (expressions when dealing with characters) 0. alphabet 1. empty string is a RE 2. char in alphabet is a RE 3. If E is an RE then in order of precedence a. (E) b. E* c. E E d. E | E xy|z* (xy) | (z*) zero or more a's a* one or more a's aa* (a|c)*b*(a|c)* abbc abbbac abbb bbb aa (a|c)*bb*(a|c)* (while|for)'(' alphabet is a, b, c a string of the alphabet with at most one b (a|c)*|(a|c)*b(a|c)* "" (a|c)*(epsilon|b)(a|c)* EXTENSIONS TO REGULAR EXPRESSION . matches any character + matches one or more ? 0 or 1 (it is optional) case [] character set we can mention sets of chars [aeiou] matches one char only [a-z] [0-9] [a-z0-9] [^] [^a-z] -?([1-9][0-9]*|0) [A-Za-z][a-z]* greedy z = x - -3; z = x--3; Bison - takes a grammar - write the parser -> create yyparse() Flex - takes RE for tokens - write the scanner -> create a program that has yylex() ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-01-21WhiteboardCS445.txt :: RULES OF FLEX 1. characters are only matched once (and at least one char is matched) 2. longest is first 3. if same length the first pattern wins 4. if no pattern matches print it!!! Look for tokens in c-Grammar.pdf: TOKEN TAGGING BY TYPE 1 keywords (each keyword is a token class) 2 identifiers class is ID 3 literals (constants) 234 "dogs" 4 operators +, >= 5 delimiters { } ( ) , ; : Compiled by: flex num.l; g++ lex.yy.c Tested by: a.out < ztest.txt Test file and flex file: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: ztest.txt :: tasks: 4 four 2 two 1 one 3 three k9s are great. I wish I had 211 of them. 007 likes k9s as well. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: num.l :: %{ // any C/C++ code I feel like #include int num; %} %option noyywrap %% [0-9]+ { printf("%d", num++); } %% // normally the main is in the bison part. int main() { num=1; yylex(); return 0; } ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-01-22WhiteboardCS445.txt :: Discussed how to get g++ 7.3 if you wish to manually build as opposed to using the test submission scheme the basic layout of the the Calc example the importance and purpose of the scanType.h file and most important: IT MUST BE INCLUDED FIRST ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-01-25WhiteboardCS445.txt :: Bison and Flex together in the Calc example Bison on calc.y --> calc.tab.h calc.tab.c token classes c code Bison code (the parser) calls yylex (the scanner) yylex returns two things the token class as an integer AND in yylval it returns a pointer to token data block (defined in scanType.h) Bison code is compiled before the flex to define the tokens and the type of yylval (these are in (file).tab.h) Flex code is then compiled using (file).tab.h + scanType.h to create the scanner. All tokens are definable by the greedy application of regular expressions ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-01-26WhiteboardCS445.txt :: The order and products of compiling Bison (parser) something.y + scanType.h -> something.tab.h + something.tab.c Flex (scanner) something.l + scanType.h + something.tab.h -> lex.yy.c g++ something.tab.c yy.lex.c playing around the with calc files left them like: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: calc.y :: %{ // // // // // // // // // // // // // // // // // // // // // // // // CS445 - Calculator Example Program written in the style of the C- // compiler for the class. // // Robert Heckendorn // Jan 21, 2021 #include "scanType.h" // TokenData Type #include double vars[26]; extern int yylex(); extern FILE *yyin; extern int line; // ERR line number from the scanner!! extern int numErrors; // ERR err count #define YYERROR_VERBOSE void yyerror(const char *msg) { printf("ERROR(%d): %s\n", line, msg); numErrors++; } %} // this is included in the tab.h file // so scanType.h must be included before the tab.h file!!!! %union { TokenData *tokenData; double value; } %token ID NUMBER QUIT MAX %type expression sumexp mulexp unary factor %% statementlist : statementlist statement | statement ; statement : '\n' | expression '\n' { printf("THE ANSWER IS %lg\n", $1); } | QUIT '\n' { exit(0); } ; expression : ID '=' expression { vars[$1->idIndex] = $3; $$ = $3;} | sumexp { $$ = $1; } sumexp : sumexp '+' mulexp { $$ = $1 + $3; } | sumexp '-' mulexp { $$ = $1 - $3; } | sumexp MAX mulexp { if ($1 > $3) $$ = $1; else $$ = $3; } | mulexp { $$ = $1; } ; mulexp : mulexp '*' unary { $$ = $1 * $3; } | mulexp '/' unary { $$ = $1 / $3; } // no check div zero | unary { $$ = $1; } ; unary : '-' unary { $$ = - $2; } | factor { $$ = $1; } factor : ID { $$ = vars[$1->idIndex]; } | '(' expression ')' { $$ = $2; } | NUMBER { $$ = $1->numValue; } ; %% extern int yydebug; int main(int argc, char *argv[]) { if (argc > 1) { if ((yyin = fopen(argv[1], "r"))) { // file open successful } else { // failed to open file printf("ERROR: failed to open \'%s\'\n", argv[1]); exit(1); } } // init variables a through z for (int i=0; i<26; i++) vars[i] = 0.0; // do the parsing numErrors = 0; yyparse(); printf("Number of errors: %d\n", numErrors); // ERR return 0; } ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: calc.l :: %{ // this *order* of these includes is mandatory #include "scanType.h" // TokenData Type #include "calc.tab.h" // token definitions from the bison int line; int numErrors; // ERR err count // setValue creates a block of information about a token. // It allocates the block and fills it in and // passes the block back in yylval static int setValue(int linenum, int tokenClass, char *svalue) { // create the pass-back data space yylval.tokenData = new TokenData; // fill it up yylval.tokenData->linenum = linenum; yylval.tokenData->tokenstr = strdup(svalue); // duplicating string!! if (tokenClass == NUMBER) { yylval.tokenData->numValue = atof(svalue); } else if (tokenClass == ID) { yylval.tokenData->idIndex = svalue[0]-'a'; } // return the tokenclass return tokenClass; } %} %option noyywrap %% "stop"|"quit"|"exit" { return setValue(line, QUIT, yytext); } "pi" { return setValue(line, NUMBER, (char *)"3.141592653589793238"); } "e" { return setValue(line, NUMBER, (char *)"2.7182818459045"); } [0-9]+|[0-9]*\.[0-9]+ { return setValue(line, NUMBER, yytext); } [0-9]+\.[0-9]* { return setValue(line, NUMBER, yytext); } [a-z] { return setValue(line, ID, yytext); } ":>:" { return setValue(line, MAX, yytext); } [\=\+\-\*\/\(\)] { return setValue(line, yytext[0], yytext ); } [ \t] ; \/\/.* ; \n { line++; return setValue(line, yytext[0], yytext ); } . { printf("ERROR(%d): char \'%c\' is not in the language\n", line, yytext[0]); numErrors++; } %% // no main program here!!! ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-01-27WhiteboardCS445.txt :: ["][^"]*["] "" "d" "dog" "dogs and cats" (")(dogs say )(\")(hi)(\")( a lot)(") (") (") (dogs say )(\") (hi)(\") ( a lot) (")(dogs like the character')(\")(')(") "\"see you tomorrow\" says the student" "\"see you tomorrow\"" "\"\"" ---------------------------------------------------------------- The objective of assignment 2 is to build an abstract syntax tree (AST) as the parser parses the input stream of tokens you build. The parser will have access in the action part of the production to the token blocks you created. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-01-28WhiteboardCS445.txt :: for stuff printf("%c", str[i]); -------------------------------------------------------------------------------- How Grammars Work alphabet - tokens terminals - symbols from the alphabet nonterminals - symbols replaced by a list of symbols (left hand side LHS)(RHS) production - replacement rule: nonterminal -> (nonterminals and terminals) start symbol - initial symbol (most likely a nonterminal) BNF (Backus-Naur Form) Parsing make a parse tree derive the tree (parsing) Examples of Languages a language that is a string of one or more Xs --> X | X X yes XX yes XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX yes --> X | X this is the same language!!! Conclusion: grammars for a language are not unique! --> X | X | X this is the same language!!! If there exists a sentence with more than one way to create it from the grammar then the grammar is AMBIGUOUS!!! --> X | X X not the same language and unambiguous. Language with a list of X's and Y's X Y XY YX YYXYXYXXYY --> X | Y | X | Y A GOOD IDEA: hierarchy --> | --> X | Y Language: A list of x's or y's followed by a semicolon! --> ; --> | --> X | Y A GOOD IDEA: general at the top to specific at the bottom (always point to myself or a later production) Language: x's or y's SEPARATED by commas --> | , --> X | Y Language: list of lists of x's or y's each TERMINATED by ; --> ; | ; --> | --> X | Y ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-02-01WhiteboardCS445.txt :: fred() ID '(' arglist ')' epsilon -> nothing writing epsilon in Bison: args : argList | /*epsilon*/ ; In BNF: ::= ID ( ) ::= | *epsilon* ::= | , In BNF: ::= ID ( ) | ID ( ) ::= | , nested parens: (ant) (ant, bat) ((ant, (bat, cat)), (dog, elk, fox)) TREE GRAMMAR: ::= ( ) <-- always a cost to go "up" in a grammar ::= | , ::= | ::= ant | bat | cat | dog | elk | fox TOP DOWN: tree: ((ant, (bat, cat)), (dog, elk, fox)) list: (ant, (bat, cat)), (dog, elk, fox) list: list , thing list: (ant, (bat, cat)) thing: (ant, (bat, cat)) tree: (ant, (bat, cat)) list: ant, (bat, cat) ... BOTTOM UP: ((ant, (bat, cat)), (dog, elk, fox)) list , tree ( ) list list list , thing thing thing thing thing thing animal animal animal animal animal animal ant bat cat dog elk fox EXPRESSIONS precedence: what operations are done first (most tightly bound) associativity: right to left OR left to right 3-4-5 ::= + | <-- right to left associative My expression grammar: ::= + | <-- left to right associative ::= * | ::= x | y | z + + PRECEDENCE is order in the grammar from bottom to top ASSOCIATIVITY is which side of the operator does the lhs reappear (x)+(y*z) ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-02-02WhiteboardCS445.txt :: x + y + z associativity (x + y) + z associativity Yes left to right x + (y + z) associativity No right to left x + y * z precedence? (x + y) * z precedence No x + (y * z) precedence Yes ALL THE THINGS THAT CAN GO WRONG IN GRAMMARS DANGLING ELSE if ( exp ) {if ( exp ) stmt} else stmt // else is with the first if NOT OK if ( exp ) {if ( exp ) stmt else stmt} // else is with the second if OK ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-02-09WhiteboardCS445.txt :: segfaults with pointers { TreeNode *treePtr; char *str; printTree(treePtr *tptr) { if (tptr == NULL ) do something reasonable if (tptr == NULL ) print "I should never get here here are relevant values:" *ptr ptr->name printf("%s", str); 1. pointer is set to NULL 2. pointer is out of range 3. pointer is on the wrong boundary 4. you didn't give a value to a ptr. treePtr *tptr; // find the important node in tree tptr = NULL; for (lkjljllkjljlj) { tptr = important node } if (tptr == NULL) say bad things else printf("Important node name is %s\n", tptr->name); // doomed!!! --------------------------- $$ = $1; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-02-10WhiteboardCS445.txt :: LL(1) parsers TOP DOWN PARSER M(N, T) T=terminal N=nonterminal sec 4.2.1 S --> ( S ) S | epsilon in the language: () ()() (())() ((())()) ... NOT in the language: (((( )))) (() ())()( ... Example grammar: S' --> S $ accept the statment S --> ( S ) S | epsilon ()()$ M(N, T) ( ) $ S S --> ( S ) S S --> epsilon S --> epsilon stack input S $ ()$ (S)S$ ()$ S-->(S)S S)S$ )$ match )S$ )$ S--> epsilon S$ $ match $ $ S--> epsilon $ $ match/accept ( ) $ S S --> ( S ) S error S --> epsilon LL(1) if top of stack is nonterminal then if M(N, input) is a production then do that production LHS -> RHS else error elese if top of stack == input then pop the stack else error -------------------------------------------------------------------------------- LR(0) a BOTTOM UP PARSER (left to right, right most derivation) the two operations we use: reduce shift ifstmt --> IF test THEN stmt ELSE stmt IF test THEN stmt ELSE stmt Great notation: dot-thingy IF test . THEN stmt ELSE stmt IF test THEN . stmt ELSE stmt IF test THEN LR(0) Algorithm: if state contains A --> B.XC where X is a terminal then if top(input)==X then shift X push state containing A --> BX.C ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-02-11WhiteboardCS445.txt :: // parser.y:71.75-76: error: $2 of 'varDelList' has no declared type Unlike the calculator program example where doubles were passed around, here you are building a tree. So the types of left hand sides (LHS) of productions are often treeNode * because in parsing you get build subtrees. So in the production right below you have $$, $1, $2, and $3 defined by the production: varDeclList : varDeclList ',' varDelInit $$ $1 $2 $3 The types of $1 and $3 which are attached to nonterminals are probably treeNode * because other parts of the grammar you build trees there in building those nonterminals. $2 in this case is probably tokenData * because it is the token ',' right from the scanner you built. At the top varDelInit and varDelList better be declared to be of type treeNode *. See the odd way that is done in example in the calc program. But is true of almost all your terms and nonterms. You got the error specifically because you didn't type varDelList. Here is some relevant code from my parser: %type unaryExp unaryRelExp varDeclId varDeclInit varDeclList %token ',' IF ... and %union { TokenData *tokenData; TreeNode *tree; ExpType type; // for passing type spec up the tree } // varDelList : varDelList ',' varDelInit {$$ = newDeclNode(FunkK,$1,$2,$4,$6);} In the actions you tried to use $4 and $6 which aren't defined in this production so you get the next error. HINT: this is a case where you are making a sibling list and not creating a new declaration node. So newDeclNode is not the thing to be calling here anyway. And you certainly aren't defining a function // parser.y:71.78-79: error: integer out of range: '$4' // varDelList : varDelList ',' varDelInit {$$ = newDeclNode(FunkK,$1,$2,$4,$6);} Same as above // parser.y:71.81-82: error: integer out of range: '$6' // varDelList : varDelList ',' varDelInit {$$ = newDeclNode(FunkK,$1,$2,$4,$6);} // ^^ // parser.y:72.46-47: error: $1 of 'varDelList' has no declared type // | varDelInit {$$ = $1;} same type declaration issue for varDelList // parser.y:75.32-33: error: $$ of 'varDelInit' has no declared type // varDelInit : varDeclId {$$ = $1;} Same but type issue but for varDeclId. // parser.y:75.37-38: error: $1 of 'varDelInit' has no declared type // varDelInit : varDeclId {$$ = $1;} // ^^ // parser.y:83.28-29: error: $$ of 'typeSpec' has no declared type // typeSpec : INT {$$ = $1;} A note here. You ned to figure out how you want to pass the type up the parse tree. The type of INT is clearly TokenData *. Since $$ = $1 the type of typeSpec should also be TokenData *. You will need to get the typeSpec to work out in other parts of the grammar. // parser.y:84.36-37: error: $$ of 'typeSpec' has no declared type // | BOOL {$$ = $1;} Same. // parser.y:85.36-37: error: $$ of 'typeSpec' has no declared type // | CHAR {$$ = $1;} Same. // parser.y:104.50-51: error: $$ of 'parmId' has no declared type // parmId : ID {$$ = $1;} Same. // parser.y:60.21-43: warning: type clash on default action: != <> [-Wother] // varDecl : typeSpec varDelList ';' There is no action so default will be $$ = $1 and the types don't work for that here. // parser.y:63.17-44: warning: type clash on default action: != <> [-Wother] // funDecl : typeSpec '(' parms ')' stmt Same. // parser.y:64.29-49: warning: type clash on default action: != [-Wother] // | ID '(' parms ')' stmt Same. -------------------------------------------------------------------------------- Parser Algorithms defined the dot-thingy S --> A B . X C LR(0) *SHIFT if state is S --> A B . X C and X is a terminal then if input == X then pop X off of input push (shift) X push a new state S --> A B X . C else ERROR *REDUCE if state is S --> A B C . pop A B C (RHS) off and their states state is now top of stack ( B --> C . S D ) push S push B --> C S . D 1) reduce and shift cannot occur in the same state! 2) only one of the two are actionable 3) reduce only affects the stack ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-02-17WhiteboardCS445.txt :: yyparse(); // parse here printTree(); // now do all your printing here ----------------------------------------------------------------------------- LR(0) Algorithm (has no real look ahead) // shift (shifts from input and so can only shift a terminal) if state contains an item: A ::= B.XC where X is a terminal then if top(input) is X then shift X -> stack push state containing A ::= BX.C and set state to this state else ERROR end if // reduce (reduces the stack. No input is consumed.) // X below may be a list of items if state contains a complete item A ::= X. then pop the list of symbols X and their states state is now the new top(stack) // we set the state twice in a reduce // state must have a state B:=C.AD push A on the stack // the case of pushing a nonterminal happens here push the state B:=CA.D // this state is the "go to" in the LR parse table set state to state containing B:=CA.D // this is the second time we set the state end if if x>3 then if test . then goto state then-state if test . and goto state and-state SLR(1) // shift if state contains an item: A ::= B.XC where X is a terminal then if top(input) is X then shift X push state containing A ::= BX.C and set state to this state else fall through to reduce part below // this is different from LR(0)!!! end if // reduce if state contains a complete items A ::= X., B::=Y., C::=Z. then // this next decision is different from LR(0)!!! chose A if input \isin Follow(A), B if input \isin Follow(B), etc pop the list of symbols X and their states set state to top(stack) // state must have a state B:=C.AD push A on the stack push the state B:=CA.D set state to state containing B:=CA.D end if if T then S (if T then S else S) ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-02-18WhiteboardCS445.txt :: %type typeSpec char x; main() { int x, y, z; ... x++; } int x; hooray!!! I'm done ------------------------------ S' -> S S -> (S)S | Epsilon all the dot-thingys for the grammar S' -> .S S' -> S. reduce S -> .(S)S shift S -> (.S)S S -> (S.)S S -> (S).S S -> (S)S. reduce S -> . reduce (()) (S )S (S)S () () ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-02-23WhiteboardCS445.txt :: numErrors = numWarnings = 0; // scanning and parsing pass yyparse(); // make sure the numErrors and numWarnings is set right // yyerror should increment the number of errors // at some point syntaxTree = $1 in your grammar // the semantic analysis pass if (numErrors==0) { SymbolTable *symbolTable; // allocate a ptr for symbol table symbolTable = new SymbolTable(); // get the SymbolTable from Feb 2021 if (doPrintAST) printTree(syntaxTree, false); // -p flag semanticAnalysis(syntaxTree, symbolTable); // do semantic analysis // annotated tree is in use and returned here if (doPrintAnnotatedAST) printTree(syntaxTree, true); // -P flag // code generation if (numErrors==0) { generate some code here } } print numErrors and numWarnings ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: s.c- :: int a; bool dogs(int x, y) { char a; { bool a; a = true; } a = 'z'; return false; } int cats() { a = dogs(a, 'z'); a = 666; return a; } ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: ss.c- :: int a; int dogs; bool dogs(int x, y) { return false; } int cats() { a = dogs(a, 'z'); a = 666; z++; return a; } ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-02-25WhiteboardCS445.txt :: There are two flags: bool isUsed; bool isInit; // bool isConst; initialize: in initializer, in parameter list, in global, on lhs exp main() { int a:23*934; int b:2*a; a = b; // in assign node on right and (not isInit) then error // in assign node on left then mark as init (note this does not apply to index of an id) // has not been initialized a[b] = 3; // has not been initialized } // use applyToAll to check isUsed flag ----------------------------------- int x[10]; int y:30; int x[10]:30; // is not int x[10] = 30; <== not the semantics (also not legal C-) x = 30; <== more like this semantics which fails. (legal syntax, fail semantics) x[10] = 30; // same type and isArray flag so OK both syntax and semantics if X is an int array. ---- char x[10]:"dogs"; // is OK char x[10], y[20], z; ... x = y; // this is OK also x = "dogs"; // this is OK also x > y; // OK x > z; // Not OK since (child[0]->isArray != child[1]->isArray) ------------ EXPRESSION TYPES *check argument types intInt argument: (child[0]->type == Integer) && (child[1]->type == Integer) -> then OK oneInt: chsign BoolBool: and arrayInt: index array * set self type self->type = Integer // or whatever the type is self->type = child[0]->type // is set lhs ------------------------- Functions and compound statements int a; int dogs() { int a; int a; // bad int dogs(int a, a) { // defined a twice.. bad int dogs(int a) { int a; // MUST BE BAD!!! // defined a twice.. bad { // cats scope int a; a = 34; return a; } } int dogs() int a; // bad int dogs() { int a; } // good int dogs(int a) { { int a; // good }} proc dogs(int a) int a; int b; { int a; } end ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-03-04WhiteboardCS445.txt :: output(int); main() { output(666); output(true); output('z'); } output(int x); func output ---> func outputc ---> func outputb | | | parm x parm x parm x Iolibary output(int *dummy*); outputc(char x); outputb(bool x); outnl(); int input(); char inputc(); bool inputb(); // preloading the symbol table isUsedCheckOK = false; semantics(iolibtree, symboltable); // load the io lib "prototyes" into symboltable isUsedCheckOK = true; semantics(pgmtree, symboltable) -------------------------------------------- ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-03-09WhiteboardCS445.txt :: traverse(node) // SOP: prefix, infix, postfix traversal of binary trees ... case for : symtab->enter() processstuff... traverse(current->child[0]); processstuff... traverse(current->child[1]); processstuff... traverse(current->child[2]); processstuff... sybtab->apply...(checkused) symtab->leave() break; case while : processstuff... traverse(current->child[0]); processstuff... traverse(current->child[1]); processstuff... break; } // end of case // now try sibling... void checkused(std::string name, void *treenode) { cout << name << endl; } if (!((TreeNode *)treenode)->isUsed) issue an error symbolTable->applyToAll(checkUsed); strs -> pointers (strs, pointers) ("main", pointer to declaration of main()) checkused("main", pointer to declaration of main()) ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-03-12WhiteboardCS445.txt :: make an enterOK flag // enterOK = true dog(int i) // func says enterOK = false { int i; // bad if true then // if is not compound so enterOK = true { int i; // ok } } // enterOK = true dog(int i) // func says enterOK = false if true then // if is not compound so enterOK = true { int i; // ok } --------------------------------- dog() { z + z; // two undeclared errors } dog() { int z; z + z; // one uninitialized error } --------------------------------- for x = 1 to 10 do // opens up a new scope ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-03-22WhiteboardCS445.txt :: principles of ERROR RECOVERY 1. determine the point of error as soon as possible. 2. parse as much of the code as possible. 3. only true are reported. distracted by colateral errors. 4. avoid infinite loops. 5. be informative. most underappreciated part of *ANY* software is error reporting 6. enough errors to point out multiple problems if they exist without cascading -------------------------- Too hard. General strategy parse stack (state from a state machine is here) input token stream objective to keep parsing. things that might help: custom error responses for empty squares (state+input) in the parser table modifying the grammar to be more robust in error recovery: synchronizing tokens like ; in C++ in C-: int fred(int x, y; char c) blah... What about LR parsers? What can we do as an error recovery process? error recovery algorithm: 0. report an error 1. pop states from stack until a reduce is found 2. top of stack gives me a reduce? if yes then reduce a pretend nothing happened 3. if i can reduce or shift on a given input choose shift 4. if not then remove the next token from input and try all this again. In BISON: stmt : stmt exp ';' | stmt error ';' // this is something WE PUT IN !!! | exp ';' | error ';' { yyerrok; } ; stmt x + y input: z ; stmt error input: z ; stmt error input: ; stmt error ; input: stmt !! 1. discard off the parse stack until it finds a place where an error token is allowed. 2. shift the error on the stack 3. discard input until it makes sense 4. now I turn off error reporting for 3 tokens. 3 good tokens accepted. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-04-01WhiteboardCS445.txt :: BATTLE PLAN for memory allocation global variables: foffset, goffset By type of node in tree: mark each of these nodes with: mem type, location, size. VarK: ParmK: based on varkind being: mem type (varkind): global, localstatic, local, parameter mark: varkind, location(offset), and size (adjust offset for array) Func: foffset = -2 // room for return ticket (old frame pointer, return address) function size = foffset after parms (this points to first space for temps) loc will later get the address of the executable for the function Compound: remember foffset (use local variable!!) traverse decl compound size = foffset after decls (this points to first space for temps) traverse body restore foffset from remembered foffset For: remember foffset (use local variable!!) traverse decl for size = foffset after decl (this points to first space for temps) traverse body restore foffset from remembered foffset Constant: strings are a global char arrays. allocate space for them. set varkind, offset ID: copy varkind, offset, size ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-04-12WhiteboardCS445.txt :: function node: allocate space for return ticket (+2) allocated for parameters (+1 each) func set foffset = -2 child0 - parmeters (this is where the var nodes are) *here* record end of func's memory child1 - body of function compound child0 - var decl *here2* record end of func's memory child1 - body of compound statement dog(int a, b, c) *here* { int z; char a; *here2* body } ---------------------------------------------------------- The "dance" of the registers lineno 3 4 Mem 40 A 41 A A 42 B A 43 B A A 44 A*B A A the big picture: lineno 3 4 Mem 40 do child 0 41 LHS -> MEM 42 do child 1 -> R3 43 MEM -> R4 44 do OP R4, R3 lineno 3 4 Mem[-5] Mem[-6] ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-04-13WhiteboardCS445.txt :: int x[10] *x x[-1]=10 9000 size of the array x[0] 8999 <--- array pointer x[1] x[2] x[3] 8996 ... x[9] ------------------ Assignment 7 Tests 1. your compiler is used to compile test files. 2. Then tm will be used to run the test compiled test files. 3. And the output of tm will be compared as the test. <-- grading this! ------------------ 9999 old fp main frame <-- R1 9998 rtn addr 9997 R1 of main dog frame <-- 9996 rtn addr 9995 777 x 9994 y 9993 z Compile this code and look at the tm code: int dog(int x) { int y; int z; return z; } main() { dog(777); } Here are the relevant parts for the function call: * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION dog * TOFF set: -3 39: ST 3,-1(1) Store return address * COMPOUND * TOFF set: -5 * Compound Body * RETURN 40: LD 3,-4(1) Load variable z 41: LDA 2,0(3) Copy result to return register 42: LD 3,-1(1) Load return address 43: LD 1,0(1) Adjust fp 44: JMP 7,0(3) Return * TOFF set: -3 * END COMPOUND * Add standard closing in case there is no return statement 45: LDC 2,0(6) Set return value to 0 46: LD 3,-1(1) Load return address 47: LD 1,0(1) Adjust fp 48: JMP 7,0(3) Return * END FUNCTION dog * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION main * TOFF set: -2 49: ST 3,-1(1) Store return address * COMPOUND * TOFF set: -2 * Compound Body * EXPRESSION * CALL dog 50: ST 1,-2(1) Store fp in ghost frame for dog * TOFF dec: -3 * TOFF dec: -4 * Param 1 51: LDC 3,777(6) Load integer constant 52: ST 3,-4(1) Push parameter * TOFF dec: -5 * Param end dog 53: LDA 1,-2(1) Ghost frame becomes new active frame 54: LDA 3,1(7) Return address in ac 55: JMP 7,-17(7) CALL dog 56: LDA 3,0(2) Save the result in ac * Call end dog * TOFF set: -2 * TOFF set: -2 * END COMPOUND * Add standard closing in case there is no return statement 57: LDC 2,0(6) Set return value to 0 58: LD 3,-1(1) Load return address 59: LD 1,0(1) Adjust fp 60: JMP 7,0(3) Return * END FUNCTION main ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-04-15WhiteboardCS445.txt :: The code gen routine: loc = emitskip(1) for jump past all your compiled code emit the i/o library * emit the code for the c- emit backpatch at loc with jump around the code do init and closing ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-04-19WhiteboardCS445.txt :: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: z.c- :: int dog(int x) { int y:666; int z; output(y); z = x; return z; } main() { dog(777); } ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: z.tm :: * C- compiler version C-S21 * Built: Apr 18, 2021 (toffset telemetry) * Author: Robert B. Heckendorn * File compiled: z.c- * Line: -1 * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION input 1: ST 3,-1(1) Store return address 2: IN 2,2,2 Grab int input 3: LD 3,-1(1) Load return address 4: LD 1,0(1) Adjust fp 5: JMP 7,0(3) Return * END FUNCTION input * Line: -1 * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION output 6: ST 3,-1(1) Store return address 7: LD 3,-2(1) Load parameter 8: OUT 3,3,3 Output integer 9: LD 3,-1(1) Load return address 10: LD 1,0(1) Adjust fp 11: JMP 7,0(3) Return * END FUNCTION output * Line: -1 * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION inputb 12: ST 3,-1(1) Store return address 13: INB 2,2,2 Grab bool input 14: LD 3,-1(1) Load return address 15: LD 1,0(1) Adjust fp 16: JMP 7,0(3) Return * END FUNCTION inputb * Line: -1 * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION outputb 17: ST 3,-1(1) Store return address 18: LD 3,-2(1) Load parameter 19: OUTB 3,3,3 Output bool 20: LD 3,-1(1) Load return address 21: LD 1,0(1) Adjust fp 22: JMP 7,0(3) Return * END FUNCTION outputb * Line: -1 * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION inputc 23: ST 3,-1(1) Store return address 24: INC 2,2,2 Grab char input 25: LD 3,-1(1) Load return address 26: LD 1,0(1) Adjust fp 27: JMP 7,0(3) Return * END FUNCTION inputc * Line: -1 * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION outputc 28: ST 3,-1(1) Store return address 29: LD 3,-2(1) Load parameter 30: OUTC 3,3,3 Output char 31: LD 3,-1(1) Load return address 32: LD 1,0(1) Adjust fp 33: JMP 7,0(3) Return * END FUNCTION outputc * Line: -1 * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION outnl 34: ST 3,-1(1) Store return address 35: OUTNL 3,3,3 Output a newline 36: LD 3,-1(1) Load return address 37: LD 1,0(1) Adjust fp 38: JMP 7,0(3) Return * END FUNCTION outnl * Line: 1 * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION dog * TOFF set: -3 39: ST 3,-1(1) Store return address * Line: 2 * COMPOUND * TOFF set: -5 * Line: 3 * Line: 3 40: LDC 3,666(6) Load integer constant 41: ST 3,-3(1) Store variable y * Line: 4 * Compound Body * EXPRESSION * Line: 6 * CALL output 42: ST 1,-5(1) Store fp in ghost frame for output * TOFF dec: -6 * TOFF dec: -7 * Param 1 * Line: 6 43: LD 3,-3(1) Load variable y 44: ST 3,-7(1) Push parameter * TOFF dec: -8 * Param end output 45: LDA 1,-5(1) Ghost frame becomes new active frame 46: LDA 3,1(7) Return address in ac 47: JMP 7,-42(7) CALL output 48: LDA 3,0(2) Save the result in ac * Call end output * TOFF set: -5 * EXPRESSION * Line: 7 * Line: 7 49: LD 3,-2(1) Load variable x 50: ST 3,-4(1) Store variable z * Line: 9 * RETURN * Line: 9 51: LD 3,-4(1) Load variable z 52: LDA 2,0(3) Copy result to return register 53: LD 3,-1(1) Load return address 54: LD 1,0(1) Adjust fp 55: JMP 7,0(3) Return * TOFF set: -3 * END COMPOUND * Add standard closing in case there is no return statement 56: LDC 2,0(6) Set return value to 0 57: LD 3,-1(1) Load return address 58: LD 1,0(1) Adjust fp 59: JMP 7,0(3) Return * END FUNCTION dog * Line: 12 * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION main * TOFF set: -2 60: ST 3,-1(1) Store return address * Line: 12 * COMPOUND * TOFF set: -2 * Compound Body * EXPRESSION * Line: 13 * CALL dog 61: ST 1,-2(1) Store fp in ghost frame for dog * TOFF dec: -3 * TOFF dec: -4 * Param 1 * Line: 13 62: LDC 3,777(6) Load integer constant 63: ST 3,-4(1) Push parameter * TOFF dec: -5 * Param end dog 64: LDA 1,-2(1) Ghost frame becomes new active frame 65: LDA 3,1(7) Return address in ac 66: JMP 7,-28(7) CALL dog 67: LDA 3,0(2) Save the result in ac * Call end dog * TOFF set: -2 * TOFF set: -2 * END COMPOUND * Add standard closing in case there is no return statement 68: LDC 2,0(6) Set return value to 0 69: LD 3,-1(1) Load return address 70: LD 1,0(1) Adjust fp 71: JMP 7,0(3) Return * END FUNCTION main 0: JMP 7,71(7) Jump to init [backpatch] * INIT 72: LDA 1,0(0) set first frame at end of globals 73: ST 1,0(1) store old fp (point to self) * INIT GLOBALS AND STATICS * END INIT GLOBALS AND STATICS 74: LDA 3,1(7) Return address in ac 75: JMP 7,-16(7) Jump to main 76: HALT 0,0,0 DONE! * END INIT ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-04-26WhiteboardCS445.txt :: goffset - global offset R0 foffset - frame offset R1 goffset = 0 declarations: VarK ParamK am I global, parameter, local, static (global) adjust goffset by size adjust foffset by size IF ARRAY and not parameter adjust (fg)offset by -1 (fg)offset answers where the next free space is FuncK foffset = -2 enter traverse child0 size = foffset traverse child1 leave Compounds enter remember = foffset traverse child0 size = foffset traverse child1 foffset = remember leave For enter remember = foffset traverse child0 // var for the index variable and will allocate space // THIS NEXT LINE IS NEW!!!!! foffset += -2 // allocate space for two temporaray variables (start, stop, step) size = foffset traverse child1 // range traverse child2 // body foffset = remember leave constK allocate if const is char array (global) (address of mem in R3 in code gen) IdK look it up fill in size and offset CallK look it up fill in size (offset determined at code gen time) ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-04-27WhiteboardCS445.txt :: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: z.c- :: int dog(int x, a[], q) { int z; int b[10]; x + q; a[4]; b[4]; z = 666; return z; } main() { int y; int w[10]; y = dog(777, w, 888); } ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: z.tm :: * C- compiler version C-S21 * Built: Apr 18, 2021 (toffset telemetry) * Author: Robert B. Heckendorn * File compiled: z.c- * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION input 1: ST 3,-1(1) Store return address 2: IN 2,2,2 Grab int input 3: LD 3,-1(1) Load return address 4: LD 1,0(1) Adjust fp 5: JMP 7,0(3) Return * END FUNCTION input * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION output 6: ST 3,-1(1) Store return address 7: LD 3,-2(1) Load parameter 8: OUT 3,3,3 Output integer 9: LD 3,-1(1) Load return address 10: LD 1,0(1) Adjust fp 11: JMP 7,0(3) Return * END FUNCTION output * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION inputb 12: ST 3,-1(1) Store return address 13: INB 2,2,2 Grab bool input 14: LD 3,-1(1) Load return address 15: LD 1,0(1) Adjust fp 16: JMP 7,0(3) Return * END FUNCTION inputb * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION outputb 17: ST 3,-1(1) Store return address 18: LD 3,-2(1) Load parameter 19: OUTB 3,3,3 Output bool 20: LD 3,-1(1) Load return address 21: LD 1,0(1) Adjust fp 22: JMP 7,0(3) Return * END FUNCTION outputb * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION inputc 23: ST 3,-1(1) Store return address 24: INC 2,2,2 Grab char input 25: LD 3,-1(1) Load return address 26: LD 1,0(1) Adjust fp 27: JMP 7,0(3) Return * END FUNCTION inputc * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION outputc 28: ST 3,-1(1) Store return address 29: LD 3,-2(1) Load parameter 30: OUTC 3,3,3 Output char 31: LD 3,-1(1) Load return address 32: LD 1,0(1) Adjust fp 33: JMP 7,0(3) Return * END FUNCTION outputc * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION outnl 34: ST 3,-1(1) Store return address 35: OUTNL 3,3,3 Output a newline 36: LD 3,-1(1) Load return address 37: LD 1,0(1) Adjust fp 38: JMP 7,0(3) Return * END FUNCTION outnl * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION dog * TOFF set: -5 39: ST 3,-1(1) Store return address * COMPOUND * TOFF set: -17 40: LDC 3,10(6) load size of array b 41: ST 3,-6(1) save size of array b * Compound Body * EXPRESSION 42: LD 3,-2(1) Load variable x 43: ST 3,-17(1) Push left side * TOFF dec: -18 44: LD 3,-4(1) Load variable q * TOFF inc: -17 45: LD 4,-17(1) Pop left into ac1 46: ADD 3,4,3 Op + * EXPRESSION 47: LD 3,-3(1) Load address of base of array a 48: ST 3,-17(1) Push left side * TOFF dec: -18 49: LDC 3,4(6) Load integer constant * TOFF inc: -17 50: LD 4,-17(1) Pop left into ac1 51: SUB 3,4,3 compute location from index 52: LD 3,0(3) Load array element * EXPRESSION 53: LDA 3,-7(1) Load address of base of array b 54: ST 3,-17(1) Push left side * TOFF dec: -18 55: LDC 3,4(6) Load integer constant * TOFF inc: -17 56: LD 4,-17(1) Pop left into ac1 57: SUB 3,4,3 compute location from index 58: LD 3,0(3) Load array element * EXPRESSION 59: LDC 3,666(6) Load integer constant 60: ST 3,-5(1) Store variable z * RETURN 61: LD 3,-5(1) Load variable z 62: LDA 2,0(3) Copy result to return register 63: LD 3,-1(1) Load return address 64: LD 1,0(1) Adjust fp 65: JMP 7,0(3) Return * TOFF set: -5 * END COMPOUND * Add standard closing in case there is no return statement 66: LDC 2,0(6) Set return value to 0 67: LD 3,-1(1) Load return address 68: LD 1,0(1) Adjust fp 69: JMP 7,0(3) Return * END FUNCTION dog * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION main * TOFF set: -2 70: ST 3,-1(1) Store return address * COMPOUND * TOFF set: -14 71: LDC 3,10(6) load size of array w 72: ST 3,-3(1) save size of array w * Compound Body * EXPRESSION * CALL dog 73: ST 1,-14(1) Store fp in ghost frame for dog * TOFF dec: -15 * TOFF dec: -16 * Param 1 74: LDC 3,777(6) Load integer constant 75: ST 3,-16(1) Push parameter * TOFF dec: -17 * Param 2 76: LDA 3,-4(1) Load address of base of array w 77: ST 3,-17(1) Push parameter * TOFF dec: -18 * Param 3 78: LDC 3,888(6) Load integer constant 79: ST 3,-18(1) Push parameter * TOFF dec: -19 * Param end dog 80: LDA 1,-14(1) Ghost frame becomes new active frame 81: LDA 3,1(7) Return address in ac 82: JMP 7,-44(7) CALL dog 83: LDA 3,0(2) Save the result in ac * Call end dog * TOFF set: -14 84: ST 3,-2(1) Store variable y * TOFF set: -2 * END COMPOUND * Add standard closing in case there is no return statement 85: LDC 2,0(6) Set return value to 0 86: LD 3,-1(1) Load return address 87: LD 1,0(1) Adjust fp 88: JMP 7,0(3) Return * END FUNCTION main 0: JMP 7,88(7) Jump to init [backpatch] * INIT 89: LDA 1,0(0) set first frame at end of globals 90: ST 1,0(1) store old fp (point to self) * INIT GLOBALS AND STATICS * END INIT GLOBALS AND STATICS 91: LDA 3,1(7) Return address in ac 92: JMP 7,-23(7) Jump to main 93: HALT 0,0,0 DONE! * END INIT ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: zz :: 9999 9999 <- R0 <- R1 (old fp) <- R1 9998 rtn address to halt instruction 9997 [y] ---------------------------------------------------------- 9996 9999 <- ghost frame (old fp) 9995 (rtn address will go) 9994 param 9993 [z] ---------------------------------------------------------- 9992 9991 9990 9989 9988 9987 9986 9985 9984 9983 9982 9981 9980 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 2021-05-04WhiteboardCS445.txt :: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: z.c- :: dog() { int w:555; static int frank:777*888+444; // visible local scope; It's lifetime pgm output(frank); frank = 666; } // NOTES: // static is allocated in the global space (goffset is used) // /int frank-1:777 // name mangling and points to the same node as int frank:777!!! int g:111*888+333; // visible anywhere (after declaration); lifetime is pgm main() { int v:222; // visible locally; lifetime is enclosing scope dog(); dog(); } // INIT GLOBALS AND STATICS // steps for static init: // 1) make entry as before in local scope for frank with allocation as static (goffset) // 2) make entry in global scope (see insertGlobal()) for frank-# pointing to same node that step 1 pointed to. frank-# is a mangled name. // ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: z.tm :: * C- compiler version C-S21 * Built: Apr 18, 2021 (toffset telemetry) * Author: Robert B. Heckendorn * File compiled: z.c- * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION input 1: ST 3,-1(1) Store return address 2: IN 2,2,2 Grab int input 3: LD 3,-1(1) Load return address 4: LD 1,0(1) Adjust fp 5: JMP 7,0(3) Return * END FUNCTION input * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION output 6: ST 3,-1(1) Store return address 7: LD 3,-2(1) Load parameter 8: OUT 3,3,3 Output integer 9: LD 3,-1(1) Load return address 10: LD 1,0(1) Adjust fp 11: JMP 7,0(3) Return * END FUNCTION output * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION inputb 12: ST 3,-1(1) Store return address 13: INB 2,2,2 Grab bool input 14: LD 3,-1(1) Load return address 15: LD 1,0(1) Adjust fp 16: JMP 7,0(3) Return * END FUNCTION inputb * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION outputb 17: ST 3,-1(1) Store return address 18: LD 3,-2(1) Load parameter 19: OUTB 3,3,3 Output bool 20: LD 3,-1(1) Load return address 21: LD 1,0(1) Adjust fp 22: JMP 7,0(3) Return * END FUNCTION outputb * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION inputc 23: ST 3,-1(1) Store return address 24: INC 2,2,2 Grab char input 25: LD 3,-1(1) Load return address 26: LD 1,0(1) Adjust fp 27: JMP 7,0(3) Return * END FUNCTION inputc * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION outputc 28: ST 3,-1(1) Store return address 29: LD 3,-2(1) Load parameter 30: OUTC 3,3,3 Output char 31: LD 3,-1(1) Load return address 32: LD 1,0(1) Adjust fp 33: JMP 7,0(3) Return * END FUNCTION outputc * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION outnl 34: ST 3,-1(1) Store return address 35: OUTNL 3,3,3 Output a newline 36: LD 3,-1(1) Load return address 37: LD 1,0(1) Adjust fp 38: JMP 7,0(3) Return * END FUNCTION outnl * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION dog * TOFF set: -2 39: ST 3,-1(1) Store return address * COMPOUND * TOFF set: -3 40: LDC 3,555(6) Load integer constant 41: ST 3,-2(1) Store variable w * Compound Body * EXPRESSION * CALL output 42: ST 1,-3(1) Store fp in ghost frame for output * TOFF dec: -4 * TOFF dec: -5 * Param 1 43: LD 3,0(0) Load variable frank 44: ST 3,-5(1) Push parameter * TOFF dec: -6 * Param end output 45: LDA 1,-3(1) Ghost frame becomes new active frame 46: LDA 3,1(7) Return address in ac 47: JMP 7,-42(7) CALL output 48: LDA 3,0(2) Save the result in ac * Call end output * TOFF set: -3 * EXPRESSION 49: LDC 3,666(6) Load integer constant 50: ST 3,0(0) Store variable frank * TOFF set: -2 * END COMPOUND * Add standard closing in case there is no return statement 51: LDC 2,0(6) Set return value to 0 52: LD 3,-1(1) Load return address 53: LD 1,0(1) Adjust fp 54: JMP 7,0(3) Return * END FUNCTION dog * * ** ** ** ** ** ** ** ** ** ** ** ** * FUNCTION main * TOFF set: -2 55: ST 3,-1(1) Store return address * COMPOUND * TOFF set: -3 56: LDC 3,222(6) Load integer constant 57: ST 3,-2(1) Store variable v * Compound Body * EXPRESSION * CALL dog 58: ST 1,-3(1) Store fp in ghost frame for dog * TOFF dec: -4 * TOFF dec: -5 * Param end dog 59: LDA 1,-3(1) Ghost frame becomes new active frame 60: LDA 3,1(7) Return address in ac 61: JMP 7,-23(7) CALL dog 62: LDA 3,0(2) Save the result in ac * Call end dog * TOFF set: -3 * EXPRESSION * CALL dog 63: ST 1,-3(1) Store fp in ghost frame for dog * TOFF dec: -4 * TOFF dec: -5 * Param end dog 64: LDA 1,-3(1) Ghost frame becomes new active frame 65: LDA 3,1(7) Return address in ac 66: JMP 7,-28(7) CALL dog 67: LDA 3,0(2) Save the result in ac * Call end dog * TOFF set: -3 * TOFF set: -2 * END COMPOUND * Add standard closing in case there is no return statement 68: LDC 2,0(6) Set return value to 0 69: LD 3,-1(1) Load return address 70: LD 1,0(1) Adjust fp 71: JMP 7,0(3) Return * END FUNCTION main 0: JMP 7,71(7) Jump to init [backpatch] * INIT 72: LDA 1,-2(0) set first frame at end of globals 73: ST 1,0(1) store old fp (point to self) * INIT GLOBALS AND STATICS 74: LDC 3,777(6) Load integer constant 75: ST 3,-2(1) Push left side * TOFF dec: -3 76: LDC 3,888(6) Load integer constant * TOFF inc: -2 77: LD 4,-2(1) Pop left into ac1 78: MUL 3,4,3 Op * 79: ST 3,-2(1) Push left side * TOFF dec: -3 80: LDC 3,444(6) Load integer constant * TOFF inc: -2 81: LD 4,-2(1) Pop left into ac1 82: ADD 3,4,3 Op + 83: ST 3,0(0) Store variable frank 84: LDC 3,111(6) Load integer constant 85: ST 3,-2(1) Push left side * TOFF dec: -3 86: LDC 3,888(6) Load integer constant * TOFF inc: -2 87: LD 4,-2(1) Pop left into ac1 88: MUL 3,4,3 Op * 89: ST 3,-2(1) Push left side * TOFF dec: -3 90: LDC 3,333(6) Load integer constant * TOFF inc: -2 91: LD 4,-2(1) Pop left into ac1 92: ADD 3,4,3 Op + 93: ST 3,-1(0) Store variable g * END INIT GLOBALS AND STATICS 94: LDA 3,1(7) Return address in ac 95: JMP 7,-41(7) Jump to main 96: HALT 0,0,0 DONE! * END INIT