// BCAE0.bcpl - BCPL Compiler -- CAE Main Program.
// Copyright Xerox Corporation 1980
//  Swinehart, 5-10-77: docase exp

// last modified by Butterfield, January 25, 1979  2:09 PM
// - Nextsymb, add END - 1/25/79

//	ConstructTree	Construct the AE-tree.
//	Nextsymb	Read the LEX file for the next lexeme
//	CAEskip		Skip over command after an error
//	LinePtr		Get the last line pointer read by Nextsymb
//	CAEreport	Error report for CAE.

get "bcaex"
external InitToRead

static   //  Scalars used in CAE.
 [  TRUENODE = nil	//  Tree node to hold (TRUE, true).
    FALSENODE = nil	//  ditto false
    NILNODE = nil	//  ditto nil
    ERRORNAME = nil	//  Dummy name used to recover from errors.
    ERRORNODE = nil	//  Dummy node for undefined names
    ZERONODE = nil	//  A useful node consisting of (NUMBER,0)
    NULLQUALNODE = nil	//  For qualname errors

    TempV = nil	//  Temp vector for EXT, etc. in Readblockbody

  ]

let ConstructTree() be   //  Translate the source code
 [  if SWDebug do WriteS("CAE*n")

    let v = vec Vmax; V = v   //  Nextsymb reads names and numbers and strings here.

    let v = vec TempT; TempV = v

    Tree = Newvec(0)	//  The initial tree location

    TRUENODE  = List2(TRUE, true)	//  Various useful nodes
    FALSENODE = List2(FALSE, false)
    NILNODE   = List2(NIL, 0)
    ZERONODE = List2(NUMBER,0)
    ERRORNAME = 0	
    ERRORNODE = List2(ERRORNAME + LABEL, 0)
    NULLQUALNODE = List3(0, WordSizeOb, 0)

    ResetStream(LexStream, $l)	//  Reopen the LEX file for reading
    InitToRead(LexStream)

    Curline = 0

    Nextsymb()
    rv Tree = Readblockbody()   //  DO THE WORK.
    unless Symb eq END do CAEreport(0)

    CloseTemp(LexStream, $l)	//  Close the LEX file
  ]

and CAEreport(n) be
 [  Ostream = ErrorStream
    WW($*n)
    let w = WriteLines(Curline, -1, 2)
    if not w do unless SWHelp % SWDebug return
    let m = selecton n into
     [	default: 0
	case 0: "END OF SOURCE TEXT NOT REACHED*n*t(POSSIBLY DUE TO PREVIOUS ERROR)"
	case 1:	"ILLEGAL EXPRESSION IN DECLARATION"
	case 2:	"ILLEGAL EXPRESSION"
	case 3:	"TOO MANY NAMES IN DECLARATION"
	case 4:	"DECLARATION IMPROPERLY TERMINATED"
	case 5:	"TABLE NOT FOLLOWED BY  [  "
	case 6:	"END OF SOURCE TEXT REACHED -- CLOSING  ]  EXPECTED"
	case 7:	"CLOSING  ]  EXPECTED"
	case 8:	"NAME EXPECTED"
	case 9:	"MISSING COMMA"
	case 10: "ILLEGAL STATEMENT"
	case 11: "ILLEGAL EXPRESSION IN SWITCH"
	case 12: "SWITCH NOT FOLLOWED BY  [  "
	case 13: "ILLEGAL ARGUMENT LIST"
	case 14: "ILLEGAL CONDITIONAL EXPRESSION"
	case 15: "ILLEGAL PROCEDURE DECLARATION"
	case 16: "PROCEDURE BODY EXPECTED"
	case 17: "ILLEGAL DECLARATION"
	case 18: "ILLEGAL LABEL"
	case 19: "ILLEGAL STATEMENT"
	case 20: "CONDITIONAL CLAUSE IMPROPERLY TERMINATED"
	case 21: "ILLEGAL FOR CLAUSE"
	case 22: "FOR CLAUSE IMPROPERLY TERMINATED"
	case 23: "CASE LABEL IMPROPERLY TERMINATED"
	case 24: "NEXT CASE EXPECTED IN SELECTON EXPRESSION"
	case 25: "DO, THEN, IFSO, IFNOT, INTO  OUT OF CONTEXT"
	case 26: "AND  OUT OF CONTEXT"
	case 27: "TABLE TOO BIG"
	case 28: "OPENING [ EXPECTED"
     ]
    BCPLreport(n, m)
    if SWHelp do Help("CAE REPORT")
    if n le 0 goto Abort
    Ostream = OutputStream
  ]

and Nextsymb() be	//  Read the next lexeme from the LEX file
 [ let n = nil
L:	if SWCaeTrace do [ WriteS("*t*******s") ]
	Readch(LexStream, lv Symb)	//  The lexeme symbol
	switchon Symb into
	 [  case NAME:
		Readaddr(LexStream, lv V!0)
		if SWCaeTrace do
		[ WriteS("NAME "); WriteO(V!0) ]
		endcase
	    case LINE:
		Readaddr(LexStream, lv Curline)
		if SWCaeTrace do
		[ WriteS("LINE "); WriteO(Curline); if SWList do WW($*n) ]
		if SWList do
		[ if not SWCaeTrace do [ WriteO(Curline); WW($*s) ]
		  WriteLine(Curline) ]
		goto L
	    case END:
		Readaddr(LexStream, lv V!0)
		if SWCaeTrace do
		[ WriteS("END "); WriteO(V!0) ]
		endcase
	    case NUMBER:
	    case CHARCONST:
		Readword(LexStream, lv V!0)
		if SWCaeTrace do
		[ WriteN(Symb); WW($*s); WriteO(V!0) ]
		endcase
	    case NAMEBRA:
	    case NAMEKET:
	    case STRINGCONST:
		Readword(LexStream, lv V!0)
		for i = 1 to Length(V)/Bytesperword do Readword(LexStream, lv V!i)
		test    Symb eq NAMEBRA  
		then    Symb  = SECTBRA 
		or if   Symb eq NAMEKET  
		then    Symb  = SECTKET
		if SWCaeTrace do
		[ WriteN(Symb); WW($*s); WriteS(V) ]
		endcase
	    case SECTBRA:
	    case SECTKET:
		V!0 = 0
		if SWCaeTrace do
		[ WriteN(Symb) ]
		endcase
	    default:
		if SWCaeTrace do
		[ WriteN(Symb) ]
		endcase
	   ]
    if SWCaeTrace do WW($*n)
 ]

and CAEskip(n) = valof
 [  CAEreport(n)
    switchon Symb into
    [	case SEMICOLON: case SECTKET: case END:
	    resultis true	// We are at the end of a command

	case SECTBRA:
	case LET: case AND: case STATIC: case EXT: case MANIFEST:
	case IF: case UNLESS: case WHILE: case UNTIL:
	case TEST: case FOR:
	case GOTO: case SWITCHON: case CASE: case DEFAULT:
	case BREAK: case LOOP: case ENDCASE:
	case RETURN: case RESULTIS: case FINISH: case ABORT:
	case DOCASE:
	    resultis false	// We are at the beginning of a command

	default:	Nextsymb()

    ] repeat
  ]

and LinePtr() = Curline	//  Retrieve the last line pointer seen by Nextsymb