// File: /workspace/github_c_makefile_star2_O3/theovosse[P]llgen/llgen.c
// Function: DetermineFollowRule
static void DetermineFollowRule(TREE *follow, Node rule, Name orig, TREE followers) {
	NodeList rules;
	TREE nFollowers;
	TREE chain1EltFollowers;
	TREE chain2EltFollowers;
    TREE sequenceFirstsAndFollowers;

	for (; rule != NULL; rule = rule->next) {
		if (rule->nodeType != single || rule->element.name == orig) {
			nFollowers = NULL;
			(void) collectFirst(&nFollowers, followers, rule->next);
			switch (rule->nodeType) {
				case single: /* && rule->element.name == orig */
					if (Unite(follow, nFollowers)) {
						changes = true;
					}
					break;
				case option:
					DetermineFollowRule(follow, rule->element.sub, orig, nFollowers);
					break;
				case sequence:
                    sequenceFirstsAndFollowers = NULL;
                    (void) collectFirst(&sequenceFirstsAndFollowers, NULL, rule->element.sub);
                    Unite(&sequenceFirstsAndFollowers, nFollowers);
					DetermineFollowRule(follow, rule->element.sub, orig, sequenceFirstsAndFollowers);
                    KillTree(sequenceFirstsAndFollowers, NULL);
					break;
				case chain:
					/*	A CHAIN B, C
						FOLLOW(A) = nFollowers + FIRST(B) + (EMPTY(B)? FIRST(A) + ...: EMPTY)
						FOLLOW(B) = FIRST(A) + (EMPTY(A)? FIRST(B) + nFollowers: EMPTY) */
					chain1EltFollowers = NULL;
					chain2EltFollowers = NULL;
					(void) collectFirst(&chain2EltFollowers, nFollowers, rule->element.sub->element.sub);
					/* chain2EltFollowers = FIRST(A) + (EMPTY(A)? nFollowers: EMPTY) */
					(void) collectFirst(&chain1EltFollowers, chain2EltFollowers, rule->element.sub->next->element.sub);
					/* chain1EltFollowers = FIRST(B) + (EMPTY(B)? chain2EltFollowers: EMPTY) */
					(void) Unite(&chain1EltFollowers, nFollowers);
					/* chain1EltFollowers = nFollowers + FIRST(B) + ... */
					DetermineFollowRule(follow, rule->element.sub->element.sub, orig, chain1EltFollowers);
					KillTree(chain1EltFollowers, NULL);
					KillTree(chain2EltFollowers, NULL);
					chain1EltFollowers = NULL;
					chain2EltFollowers = NULL;
					(void) collectFirst(&chain2EltFollowers, NULL, rule->element.sub->next->element.sub);
					/* chain2EltFollowers = FIRST(B) */
					(void) Unite(&chain2EltFollowers, nFollowers);
					/* chain2EltFollowers = FIRST(B) + nFollowers */
					(void) collectFirst(&chain1EltFollowers, chain2EltFollowers, rule->element.sub->element.sub);
					/* chain1EltFollowers = FIRST(A) + (EMPTY(A)? chain2EltFollowers: EMPTY) */
					DetermineFollowRule(follow, rule->element.sub->next->element.sub, orig, chain1EltFollowers);
					KillTree(chain1EltFollowers, NULL);
					KillTree(chain2EltFollowers, NULL);
					break;
				case alternative: /* Try each one... */
					for (rules = rule->element.alternatives; rules != NULL; rules = rules->rest) {
						DetermineFollowRule(follow, rules->first, orig, nFollowers);
					}
					break;
				case breakToken:
				case errorMessage:
					// Just empty productions
					break;
				// default:
				// 	fprintf(stderr, "DetermineFollowRule: unknown nodetype %d", rule->nodeType);
				// 	return;
			}
			KillTree(nFollowers, NULL);
		}
	}
}

// Assembly:
testq %rsi, %rsi
je 0x68ee
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq %rcx, %rbx
movq %rdx, %r14
movq %rsi, %r15
movq %rdi, %r12
leaq 0xa98e(%rip), %rbp      # 0x1106c
movq %rcx, 0x20(%rsp)
cmpl $0x0, 0x4(%r15)
je 0x673a
movq $0x0, (%rsp)
movq 0x28(%r15), %rdx
movq %rsp, %rdi
movq %rbx, %rsi
callq 0x64b2
movl 0x4(%r15), %eax
cmpq $0x4, %rax
ja 0x68c8
movslq (%rbp,%rax,4), %rax
addq %rbp, %rax
jmpq *%rax
movq (%rsp), %rsi
movq %r12, %rdi
callq 0x6655
testw %ax, %ax
je 0x68c8
movb $0x1, 0x133f3(%rip)     # 0x19b28
jmp 0x68c8
cmpq %r14, 0x18(%r15)
jne 0x68d3
jmp 0x66ea
movq 0x18(%r15), %r13
testq %r13, %r13
je 0x68c8
movq (%r13), %rsi
movq (%rsp), %rcx
movq %r12, %rdi
movq %r14, %rdx
callq 0x66b4
movq 0x8(%r13), %r13
jmp 0x674a
movq $0x0, 0x18(%rsp)
movq 0x18(%r15), %rdx
leaq 0x18(%rsp), %r13
movq %r13, %rdi
xorl %esi, %esi
callq 0x64b2
movq (%rsp), %rsi
movq %r13, %rdi
callq 0x6655
movq 0x18(%r15), %rsi
movq 0x18(%rsp), %rcx
movq %r12, %rdi
movq %r14, %rdx
callq 0x66b4
movq 0x18(%rsp), %rdi
jmp 0x68ac
xorl %r13d, %r13d
movq %r13, 0x10(%rsp)
movq %r13, 0x8(%rsp)
movq (%rsp), %rsi
movq 0x18(%r15), %rax
movq 0x18(%rax), %rdx
leaq 0x8(%rsp), %rbp
movq %rbp, %rdi
callq 0x64b2
movq 0x8(%rsp), %rsi
movq 0x18(%r15), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rdx
leaq 0x10(%rsp), %rbx
movq %rbx, %rdi
callq 0x64b2
movq (%rsp), %rsi
movq %rbx, %rdi
callq 0x6655
movq 0x18(%r15), %rax
movq 0x18(%rax), %rsi
movq 0x10(%rsp), %rcx
movq %r12, %rdi
movq %r14, %rdx
callq 0x66b4
movq 0x10(%rsp), %rdi
xorl %esi, %esi
callq 0xbd36
movq 0x8(%rsp), %rdi
xorl %esi, %esi
callq 0xbd36
movq %r13, 0x10(%rsp)
movq %r13, 0x8(%rsp)
movq 0x18(%r15), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rdx
movq %rbp, %rdi
xorl %esi, %esi
callq 0x64b2
movq (%rsp), %rsi
movq %rbp, %rdi
leaq 0xa80c(%rip), %rbp      # 0x1106c
callq 0x6655
movq 0x8(%rsp), %rsi
movq 0x18(%r15), %rax
movq 0x18(%rax), %rdx
movq %rbx, %rdi
movq 0x20(%rsp), %rbx
callq 0x64b2
movq 0x18(%r15), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rsi
movq 0x10(%rsp), %rcx
movq %r12, %rdi
movq %r14, %rdx
callq 0x66b4
movq 0x10(%rsp), %rdi
xorl %esi, %esi
callq 0xbd36
movq 0x8(%rsp), %rdi
xorl %esi, %esi
callq 0xbd36
jmp 0x68c8
movq 0x18(%r15), %rsi
movq (%rsp), %rcx
movq %r12, %rdi
movq %r14, %rdx
callq 0x66b4
movq (%rsp), %rdi
xorl %esi, %esi
callq 0xbd36
movq 0x28(%r15), %r15
testq %r15, %r15
jne 0x66e3
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq