Eroxl's Notes
08 - Dynamic Control Flow (CPSC 213 Practice)

Problem 1

Are procedure calls in C examples of static or dynamic control flow?

void proc(int i) { ... }

proc(1);
  • [x] (a) Static
  • [ ] (b) Dynamic

Problem 2

In mathematics, an iterated function is a function which is obtained by composing another function with itself a certain number of times. It is represented as , where is the original function, is the number of iterations, i.e., the number of times the function is applied, and is the initial value to be applied to the function. For example is equivalent to , is equivalent to , and so on. By definition, for any function .

Create a new function iterate, in C, that calls a specified function a set number of times, using the returning value of one call as an argument to the next call. The function receives three arguments, in this order:

  • A pointer to a function foo to be iterated. The function receives a double value and returns a double.
  • The number of iterations i to apply to the function.
  • The value value to be passed as argument to the first iteration of the call.

Here are some examples of how this function may be used:

iterate(sqrt, 1, 16); // returns sqrt(16), i.e., 4
iterate(sqrt, 2, 16); // returns sqrt(sqrt(16)), i.e., 2
iterate(sqrt, 0, 16); // returns 16
iterate(log, 4, 1234.56); // returns log(log(log(log(1234.56)))), i.e., -0.394054...
double iterate(double (*foo)(double), unsigned int i, double value) {
	if (i == 0) return value;
	
	double newValue = foo(value);
	
	return iterate(foo, i-1, newValue);
}

Problem 3

What sort of control flow would most likely be used to implement the following switch statement (i.e., when it is compiled)?

switch (i) {
    case -8399: ... break;
    case -8398: ... break;
    case -8397: ... break;
    case -8396: ... break;
    case -8395: ... break;
    case -8394: ... break;
    case -8393: ... break;
    case -8391: ... break;
    case -8390: ... break;
    case -8389: ... break;
    case -8388: ... break;
    case -8387: ... break;
}
  • [ ] neither
  • [x] dynamic control flow (using a jump table)
  • [ ] static control flow (using if/then/else statements)

Problem 4

The following assembly code is most likely the implementation of which of the following:

ld 4(r5), r0
ld (r0), r1
deca r5
st r0, (r5)
gpc $2, r6
j *8(r1)
inca r5
  • [ ] A switch statement
  • [ ] A static procedure call
  • [ ] A procedure return
  • [x] A polymorphic method invocation
  • [ ] None of the above

Problem 5

Which of the following statements best describes this C code.

void a() { printf("an"); }
void b() { printf("bn"); }
void c() { printf("cn"); }

struct fptrlist {
	void (*x)();
	void (*z)();
	void (*y)();
};

struct fptrlist table = { c, a, b };

void run0() {
	table.c();
}

void run1() {
	table.x();
}
  • [ ] No errors; calling either run0 or run1 prints "c".
  • [ ] Calling run0 prints "c" but run1 has a syntax error.
  • [x] run0 has a syntax error, but calling run1 prints "c"
  • [ ] Both run0 and run1 have syntax errors
  • [ ] Neither run0 nor run1 have syntax errors, but calling neither one prints "c"

Problem 6

What does the following code print?

int add (int a, int b) {return a+b;}
int sub (int a ,int b) {return a-b;}
int div (int a, int b) {return a/b;}
int mul (int a, int b) {return a*b;}

int (*func[4])(int,int) = {add,sub,div,mul};

int main(void) {
    int a = 1;
    int b = 4;
    int c = 5;
    int d = funcfunc[1](func2,func0);
    printf("%d\n",d);
}
func2 = div(c, b)
             = div(5, 4)
             = 1
func0 = add(a, b)
             = add(1, 4)
             = 5
             
func1 = sub(b, a)
             = sub(4, 1)
             = 3
             
funcfunc[1] = func[3]
                   = mul

? = funcfunc[1] ( func2, func0)
  = mul(1, 5)
  = 5

Problem 7

Consider the following SM213 Assembly code:

ld   $h, r0
ld   (r0), r0
ld   $-649, r1
add  r0, r1
bgt  r1, C9
ld   $-636, r1
add  r0, r1
bgt  r1, L0
beq  r1, L0
br   C9

L0:     ld   $L1, r2
        j    *(r2, r1, 4)
C0:     ld   $-1863, r3
        br   L2
C1:     ld   $5790, r3
        br   L2
C2:     ld   $3985, r3
        br   L2
C3:     ld   $-8572, r3
        br   L2
C4:     ld   $-1805, r3
        br   L2
C5:     ld   $-6088, r3
        br   L2
C6:     ld   $4553, r3
        br   L2
C7:     ld   $2876, r3
        br   L2
C8:     ld   $2202, r3
        br   L2
C9:     ld   $5580, r3
        br   L2
L2:     ld   $z, r2
        st   r3, (r2)
        halt
L1:
        .long C4
        .long C1
        .long C0
        .long C8
        .long C9
        .long C0
        .long C9
        .long C0
        .long C2
        .long C2
        .long C4
        .long C7
        .long C3
        .long C2

For each of the following initial values of the global variable h, determine what value will be stored in the global variable z once the program terminates.

h z
649 3985
-637 5580
635 5580
641 -1863

Problem 8

Translate the following C code into SM213 assembly.

int i;

switch (i) {
    case 97: // C1
        i \= 33;
        break;
    case 98: // C2
        i \= 41;
        break;
    case 99: // C3
        i \= 74;
        break;
    case 100: // C4
        i \= 24;
        break;
    default:
        i \= 54;
        break;
}

Assume that the variable i and following jump table exists in memory. You will need to define labels C1 to C4 in your implementation.

jmptbl:
    .long C1
    .long C2
    .long C3
    .long C4
ld $i, r0
ld (r0), r0

ld $-100, r2

add r0, r2

bgt r2, DEFAULT

ld $-97, r2
add r0, r2

bgt r2, SWITCH
beq r2, SWITCH
br DEFAULT

SWITCH:
    ld $jmptbl, r3
    j *(r3, r2, 4)

C1:
    ld $33, r5
    br COMMON_SWITCH
C2:
    ld $41, r5
    br COMMON_SWITCH
C3:
    ld $74, r5
    br COMMON_SWITCH
C4:
    ld $24, r5
    br COMMON_SWITCH
DEFAULT:
    ld $54, r5
    br COMMON_SWITCH
COMMON_SWITCH:
    ld $i, r0
    st r5, (r0)
    br END
END:
    halt