import Object "object"
import Type "type"
import Universe "universe"
+import AST "ast"
// So I can submit and have a running parser for now...
comp *Globals.Compilation;
verbose, indent int;
S *Scanner.Scanner;
+
+ // Token
tok int; // one token look-ahead
- beg, end int; // token position
- ident string; // last ident seen
+ pos int; // token source position
+ val string; // token value (for IDENT, NUMBER, STRING only)
+
+ // Semantic analysis
top_scope *Globals.Scope;
exports *Globals.List;
}
func (P *Parser) Next() {
- P.tok, P.beg, P.end = P.S.Scan();
- if P.tok == Scanner.IDENT {
- P.ident = P.S.src[P.beg : P.end];
- }
+ P.tok, P.pos, P.val = P.S.Scan();
if P.verbose > 1 {
P.PrintIndent();
- print "[", P.beg, "] ", Scanner.TokenName(P.tok), "\n";
+ print "[", P.pos, "] ", Scanner.TokenName(P.tok), "\n";
}
}
func (P *Parser) Expect(tok int) {
if P.tok != tok {
- P.Error(P.beg, "expected '" + Scanner.TokenName(tok) + "', found '" + Scanner.TokenName(P.tok) + "'");
+ P.Error(P.pos, "expected '" + Scanner.TokenName(tok) + "', found '" + Scanner.TokenName(P.tok) + "'");
}
P.Next(); // make progress in any case
}
ident := "";
if P.tok == Scanner.IDENT {
- ident = P.ident;
+ ident = P.val;
if P.verbose > 0 {
P.PrintIndent();
print "Ident = \"", ident, "\"\n";
func (P *Parser) ParseIdentDecl(kind int) *Globals.Object {
P.Trace("IdentDecl");
- pos := P.beg;
+ pos := P.pos;
obj := Globals.NewObject(pos, kind, P.ParseIdent());
P.Declare(obj);
P.Trace("QualifiedIdent");
if EnableSemanticTests {
- pos := P.beg;
+ pos := P.pos;
ident := P.ParseIdent();
obj := P.Lookup(ident);
if obj == nil {
typ := P.TryType();
if typ == nil {
- P.Error(P.beg, "type expected");
+ P.Error(P.pos, "type expected");
typ = Universe.bad_t;
}
func (P *Parser) ParseStatement() {
P.Trace("Statement");
if !P.TryStatement() {
- P.Error(P.beg, "statement expected");
+ P.Error(P.pos, "statement expected");
P.Next(); // make progress
}
P.Ecart();
case Scanner.NEW:
P.ParseNew();
default:
- P.Error(P.beg, "operand expected");
+ P.Error(P.pos, "operand expected");
P.Next(); // make progress
}
P.Ecart();
}
-func (P *Parser) ParseUnaryExpr() {
+func (P *Parser) ParseUnaryExpr() *AST.Expr {
P.Trace("UnaryExpr");
switch P.tok {
case Scanner.ADD: fallthrough;
P.Next();
P.ParseUnaryExpr();
P.Ecart();
- return;
+ return nil; // TODO fix this
}
P.ParsePrimaryExpr();
P.Ecart();
+ return nil; // TODO fix this
}
}
-func (P *Parser) ParseBinaryExpr(prec1 int) {
+func (P *Parser) ParseBinaryExpr(prec1 int) *AST.Expr {
P.Trace("BinaryExpr");
- P.ParseUnaryExpr();
+
+ x := P.ParseUnaryExpr();
for prec := Precedence(P.tok); prec >= prec1; prec-- {
for Precedence(P.tok) == prec {
+ e := new(AST.Expr);
+ e.typ = Universe.undef_t; // TODO fix this
+ e.op = P.tok; // TODO should we use tokens or separate operator constants?
+ e.x = x;
P.Next();
- P.ParseBinaryExpr(prec + 1);
+ e.y = P.ParseBinaryExpr(prec + 1);
+ x = e;
}
}
+
P.Ecart();
}
case Scanner.RECV:
P.ParseSimpleStat(); // send or receive
case Scanner.IDENT:
- switch P.ident {
+ switch P.val {
case "print", "panic":
P.ParseBuiltinStat();
default:
func (P *Parser) ParseTypeSpec() {
P.Trace("TypeSpec");
- pos := P.beg;
+ pos := P.pos;
ident := P.ParseIdent();
obj := P.top_scope.Lookup(ident); // only lookup in top scope!
if obj != nil {
case Scanner.EXPORT:
P.ParseExportDecl();
default:
- P.Error(P.beg, "declaration expected");
+ P.Error(P.pos, "declaration expected");
P.Next(); // make progress
}
if indent != P.indent {
}
-func is_whitespace (ch int) bool {
+func is_whitespace(ch int) bool {
return ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t';
}
-func is_letter (ch int) bool {
+func is_letter(ch int) bool {
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 128 ;
}
-func digit_val (ch int) int {
+func digit_val(ch int) int {
if '0' <= ch && ch <= '9' {
return ch - '0';
}
nerrors int; // number of errors
errpos int; // last error position
- src string;
+ src string; // scanned source
pos int; // current reading position
ch int; // one char look-ahead
chpos int; // position of ch
// Read the next Unicode char into S.ch.
// S.ch < 0 means end-of-file.
//
-func (S *Scanner) Next () {
+func (S *Scanner) Next() {
const (
Bit1 = 7;
Bitx = 6;
}
-func Init () {
+func Init() {
Keywords = new(map [string] int);
for i := KEYWORDS_BEG; i <= KEYWORDS_END; i++ {
}
-func (S *Scanner) Open (filename, src string) {
+func (S *Scanner) Open(filename, src string) {
if Keywords == nil {
Init();
}
}
-func (S *Scanner) Expect (ch int) {
+func (S *Scanner) Expect(ch int) {
if S.ch != ch {
S.Error(S.chpos, "expected " + CharString(ch) + ", found " + CharString(S.ch));
}
}
-func (S *Scanner) SkipWhitespace () {
+func (S *Scanner) SkipWhitespace() {
for is_whitespace(S.ch) {
S.Next();
}
}
-func (S *Scanner) SkipComment () {
+func (S *Scanner) SkipComment() {
// '/' already consumed
if S.ch == '/' {
// comment
}
-func (S *Scanner) ScanIdentifier () int {
- beg := S.pos - 1;
+func (S *Scanner) ScanIdentifier() (tok int, val string) {
+ pos := S.chpos;
for is_letter(S.ch) || digit_val(S.ch) < 10 {
S.Next();
}
- end := S.pos - 1;
+ val = S.src[pos : S.chpos];
- var tok int;
var present bool;
- tok, present = Keywords[S.src[beg : end]];
+ tok, present = Keywords[val];
if !present {
tok = IDENT;
}
- return tok;
+ return tok, val;
}
-func (S *Scanner) ScanMantissa (base int) {
+func (S *Scanner) ScanMantissa(base int) {
for digit_val(S.ch) < base {
S.Next();
}
}
-func (S *Scanner) ScanNumber (seen_decimal_point bool) int {
+func (S *Scanner) ScanNumber(seen_decimal_point bool) string {
+ pos := S.chpos;
+
if seen_decimal_point {
+ pos--; // '.' is one byte
S.ScanMantissa(10);
goto exponent;
}
}
// octal int
}
- return NUMBER;
+ goto exit;
}
mantissa:
}
S.ScanMantissa(10);
}
- return NUMBER;
+
+exit:
+ return S.src[pos : S.chpos];
}
}
-func (S *Scanner) ScanEscape () string {
+func (S *Scanner) ScanEscape() string {
// TODO: fix this routine
ch := S.ch;
}
-func (S *Scanner) ScanChar () int {
+func (S *Scanner) ScanChar() string {
// '\'' already consumed
+ pos := S.chpos - 1;
ch := S.ch;
S.Next();
if ch == '\\' {
}
S.Expect('\'');
- return NUMBER;
+ return S.src[pos : S.chpos];
}
-func (S *Scanner) ScanString () int {
+func (S *Scanner) ScanString() string {
// '"' already consumed
pos := S.chpos - 1;
S.ScanEscape();
}
}
-
+
S.Next();
- return STRING;
+ return S.src[pos : S.chpos];
}
-func (S *Scanner) ScanRawString () int {
+func (S *Scanner) ScanRawString() string {
// '`' already consumed
pos := S.chpos - 1;
}
S.Next();
- return STRING;
+ return S.src[pos : S.chpos];
}
-func (S *Scanner) Select2 (tok0, tok1 int) int {
+func (S *Scanner) Select2(tok0, tok1 int) int {
if S.ch == '=' {
S.Next();
return tok1;
}
-func (S *Scanner) Select3 (tok0, tok1, ch2, tok2 int) int {
+func (S *Scanner) Select3(tok0, tok1, ch2, tok2 int) int {
if S.ch == '=' {
S.Next();
return tok1;
}
-func (S *Scanner) Select4 (tok0, tok1, ch2, tok2, tok3 int) int {
+func (S *Scanner) Select4(tok0, tok1, ch2, tok2, tok3 int) int {
if S.ch == '=' {
S.Next();
return tok1;
}
-func (S *Scanner) Scan () (tok, beg, end int) {
+func (S *Scanner) Scan() (tok, pos int, val string) {
S.SkipWhitespace();
ch := S.ch;
tok = ILLEGAL;
- beg = S.chpos;
-
+ pos = S.chpos;
+
switch {
- case is_letter(ch): tok = S.ScanIdentifier();
- case digit_val(ch) < 10: tok = S.ScanNumber(false);
+ case is_letter(ch): tok, val = S.ScanIdentifier();
+ case digit_val(ch) < 10: tok, val = NUMBER, S.ScanNumber(false);
default:
S.Next(); // always make progress
switch ch {
case -1: tok = EOF;
- case '"': tok = S.ScanString();
- case '\'': tok = S.ScanChar();
- case '`': tok = S.ScanRawString();
+ case '"': tok, val = STRING, S.ScanString();
+ case '\'': tok, val = NUMBER, S.ScanChar();
+ case '`': tok, val = STRING, S.ScanRawString();
case ':': tok = S.Select2(COLON, DEFINE);
case '.':
if digit_val(S.ch) < 10 {
- tok = S.ScanNumber(true);
+ tok, val = NUMBER, S.ScanNumber(true);
} else {
tok = PERIOD;
}
if S.ch == '/' || S.ch == '*' {
S.SkipComment();
// cannot simply return because of 6g bug
- tok, beg, end = S.Scan();
- return tok, beg, end;
+ tok, pos, val = S.Scan();
+ return tok, pos, val;
}
tok = S.Select2(QUO, QUO_ASSIGN);
case '%': tok = S.Select2(REM, REM_ASSIGN);
case '&': tok = S.Select3(AND, AND_ASSIGN, '&', LAND);
case '|': tok = S.Select3(OR, OR_ASSIGN, '|', LOR);
default:
- S.Error(beg, "illegal character " + CharString(ch));
+ S.Error(pos, "illegal character " + CharString(ch));
tok = ILLEGAL;
}
}
- return tok, beg, S.chpos;
+ return tok, pos, val;
}